Added basic creature document editing UI

This commit is contained in:
Stefan Zermatten
2020-03-02 15:45:55 +02:00
parent 2bd7c2908f
commit 724f9574a2
8 changed files with 197 additions and 24 deletions

View File

@@ -1,10 +1,11 @@
import SimpleSchema from 'simpl-schema';
import deathSaveSchema from "/imports/api/properties/subSchemas/DeathSavesSchema.js"
import ColorSchema from "/imports/api/properties/subSchemas/ColorSchema.js";
import deathSaveSchema from '/imports/api/properties/subSchemas/DeathSavesSchema.js'
import ColorSchema from '/imports/api/properties/subSchemas/ColorSchema.js';
import SharingSchema from '/imports/api/sharing/SharingSchema.js';
import {assertEditPermission, assertOwnership} from '/imports/api/sharing/sharingPermissions.js';
//set up the collection for creatures
Creatures = new Mongo.Collection("creatures");
Creatures = new Mongo.Collection('creatures');
let CreatureSettingsSchema = new SimpleSchema({
//slowed down by carrying too much?
@@ -28,25 +29,25 @@ let CreatureSchema = new SimpleSchema({
// Strings
name: {
type: String,
defaultValue: "",
defaultValue: '',
optional: true,
},
urlName: {
type: String,
optional: true,
autoValue: function() {
return getSlug(this.field("name").value, {maintainCase: true}) || "-";
return getSlug(this.field('name').value, {maintainCase: true}) || '-';
},
},
alignment: {
type: String,
optional: true
},
gender: {
gender: {
type: String,
optional: true
},
picture: {
picture: {
type: String,
optional: true
},
@@ -70,8 +71,8 @@ let CreatureSchema = new SimpleSchema({
},
type: {
type: String,
defaultValue: "pc",
allowedValues: ["pc", "npc", "monster"],
defaultValue: 'pc',
allowedValues: ['pc', 'npc', 'monster'],
},
variables: {
type: Object,
@@ -93,14 +94,14 @@ Creatures.attachSchema(CreatureSchema);
const insertCreature = new ValidatedMethod({
name: "Creatures.methods.insertCreature",
name: 'Creatures.methods.insertCreature',
validate: null,
run() {
if (!this.userId) {
throw new Meteor.Error("Creatures.methods.insert.denied",
"You need to be logged in to insert a creature");
throw new Meteor.Error('Creatures.methods.insert.denied',
'You need to be logged in to insert a creature');
}
// Create the creature document
@@ -114,15 +115,36 @@ const insertCreature = new ValidatedMethod({
});
const removeCreature = new ValidatedMethod({
name: 'Creature.methods.remove',
name: 'Creatures.methods.remove',
validate: null,
run({charId}) {
assertCreatureEditPermission(charId, this.userId);
let creature = Creatures.findOne(_id);
assertOwnership(creature, this.userId);
let _id = CreatureProperties.insert(creatureProperty);
let property = CreatureProperties.findOne(_id);
recomputeCreatures(property);
},
});
const updateCreature = new ValidatedMethod({
name: 'Creatures.methods.update',
validate({_id, path, value, ack}){
if (!_id) return false;
// Allowed fields
let allowedFields = ['name', 'alignment', 'gender', 'picture', 'settings'];
if (!allowedFields.includes(path[0])){
throw new Meteor.Error('Creatures.methods.update.denied',
'This field can\'t be updated using this method');
}
},
run({_id, path, value}) {
let creature = Creatures.findOne(_id);
assertEditPermission(creature, this.userId);
Creatures.update(_id, {
$set: {[path.join('.')]: value},
});
},
});
export default Creatures;
export { CreatureSchema, insertCreature, removeCreature };
export { CreatureSchema, insertCreature, removeCreature, updateCreature };

View File

@@ -0,0 +1,88 @@
<template lang="html">
<div class="creature-form">
<text-field
label="Name"
:value="model.name"
@change="(value, ack) => $emit('change', {path: ['name'], value, ack})"
:error-messages="errors.name"
:debounce-time="debounceTime"
/>
<text-field
label="Alignment"
:value="model.alignment"
@change="(value, ack) => $emit('change', {path: ['alignment'], value, ack})"
:error-messages="errors.alignment"
:debounce-time="debounceTime"
/>
<text-field
label="Gender"
:value="model.gender"
@change="(value, ack) => $emit('change', {path: ['gender'], value, ack})"
:error-messages="errors.gender"
:debounce-time="debounceTime"
/>
<text-field
label="Picture URL"
:value="model.picture"
@change="(value, ack) => $emit('change', {path: ['picture'], value, ack})"
:error-messages="errors.picture"
:debounce-time="debounceTime"
/>
<form-sections>
<form-section name="settings">
<v-switch
label="Use variant encumbrance"
:input-value="model.settings.useVariantEncumbrance"
:error-messages="errors.useVariantEncumbrance"
@change="value => $emit('change', {path: ['settings','useVariantEncumbrance'], value})"
/>
<v-switch
label="Hide spells tab"
:input-value="model.settings.hideSpellcasting"
:error-messages="errors.hideSpellcasting"
@change="value => $emit('change', {path: ['settings','hideSpellcasting'], value})"
/>
<v-switch
label="Swap ability scores and modifiers"
:input-value="model.settings.swapStatAndModifier"
:error-messages="errors.swapStatAndModifier"
@change="value => $emit('change', {path: ['settings','swapStatAndModifier'], value})"
/>
</form-section>
</form-sections>
</div>
</template>
<script>
import FormSection, {FormSections} from '/imports/ui/properties/forms/shared/FormSection.vue';
export default {
components: {
FormSection,
FormSections,
},
props: {
stored: {
type: Boolean,
},
model: {
type: Object,
default: () => ({}),
},
errors: {
type: Object,
default: () => ({}),
},
attackForm: {
type: Boolean,
},
debounceTime: Number,
},
methods: {
log: console.log,
}
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -0,0 +1,48 @@
<template lang="html">
<dialog-base>
<div slot="toolbar">
Creature Form Dialog
</div>
<div>
<creature-form :model="model" @change="change"/>
</div>
<v-spacer slot="actions"/>
<v-btn
slot="actions"
flat
@click="$store.dispatch('popDialogStack')"
>Done</v-btn>
</dialog-base>
</template>
<script>
import {updateCreature} from '/imports/api/creature/Creatures.js';
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
import CreatureForm from '/imports/ui/creature/CreatureForm.vue'
export default {
components: {
DialogBase,
CreatureForm,
},
props: {
_id: String,
startInEditTab: Boolean,
},
meteor: {
model(){
return Creatures.findOne(this._id);
},
},
methods: {
change({path, value, ack}){
updateCreature.call({_id: this._id, path, value}, (error, result) =>{
ack && ack(error && error.reason || error);
});
},
}
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -4,10 +4,14 @@
<v-btn v-if="showMenuButton" flat icon @click="toggleDrawer">
<v-icon>menu</v-icon>
</v-btn>
<v-btn v-if="showMenuButton" flat icon @click="recompute(character._id)">
<v-btn flat icon @click="recompute(character._id)">
<v-icon>refresh</v-icon>
</v-btn>
<span>{{character.name}}</span>
<v-spacer/>
<v-btn flat icon @click="showCharacterForm" data-id="character-form-button">
<v-icon>more</v-icon>
</v-btn>
<v-tabs
slot="extension"
v-model="tab"
@@ -74,6 +78,15 @@
recompute(charId){
recomputeCreature.call({charId});
},
showCharacterForm(){
this.$store.commit('pushDialogStack', {
component: 'creature-form-dialog',
elementId: 'character-form-button',
data: {
_id: this.creatureId,
},
});
},
isDarkColor,
},
meteor: {

View File

@@ -68,7 +68,7 @@
<v-btn
slot="activator"
color="primary"
small fab disabled
small fab
@click="insertCreatureProperty"
>
<v-icon>edit</v-icon>
@@ -116,7 +116,7 @@
creatureProperty.parent = {collection: "creatures", id: that.creatureId};
creatureProperty.ancestors = [ {collection: "creatures", id: that.creatureId}];
setDocToLastOrder({collection: CreatureProperties, doc: creatureProperty});
let creaturePropertyId = insertProperty.call(creatureProperty);
let creaturePropertyId = insertProperty.call({creatureProperty});
return creaturePropertyId;
}
});

View File

@@ -105,13 +105,13 @@ export default {
change({path, value, ack}){
updateProperty.call({_id: this._id, path, value}, (error, result) =>{
console.log({error, result});
ack && ack(error);
ack && ack(error && error.reason || error);
});
},
push({path, value, ack}){
pushToProperty.call({_id: this._id, path, value}, (error, result) =>{
console.log({error, result});
ack && ack(error);
ack && ack(error && error.reason || error);
});
},
pull({path, ack}){
@@ -119,7 +119,7 @@ export default {
path.pop();
pullFromProperty.call({_id: this._id, path, itemId}, (error, result) =>{
console.log({error, result});
ack && ack(error);
ack && ack(error && error.reason || error);
});
},
remove(){

View File

@@ -1,6 +1,7 @@
import AttributeDialog from '/imports/ui/properties/attributes/AttributeDialog.vue';
import AttributeDialogContainer from '/imports/ui/properties/attributes/AttributeDialogContainer.vue';
import AttributeCreationDialog from '/imports/ui/properties/attributes/AttributeCreationDialog.vue';
import CreatureFormDialog from '/imports/ui/creature/CreatureFormDialog.vue';
import CreaturePropertyCreationDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyCreationDialog.vue';
import CreaturePropertyDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue'
import CreaturePropertyFromLibraryDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue'
@@ -15,6 +16,7 @@ export default {
AttributeDialog,
AttributeDialogContainer,
AttributeCreationDialog,
CreatureFormDialog,
CreaturePropertyCreationDialog,
CreaturePropertyDialog,
CreaturePropertyFromLibraryDialog,

View File

@@ -64,13 +64,13 @@
change({path, value, ack}){
updateLibraryNode.call({_id: this._id, path, value}, (error, result) =>{
console.log({error, result});
ack && ack(error);
ack && ack(error && error.reason || error);
});
},
push({path, value, ack}){
pushToLibraryNode.call({_id: this._id, path, value}, (error, result) =>{
console.log({error, result});
ack && ack(error);
ack && ack(error && error.reason || error);
});
},
pull({path, ack}){
@@ -78,7 +78,7 @@
path.pop();
pullFromLibraryNode.call({_id: this._id, path, itemId}, (error, result) =>{
console.log({error, result});
ack && ack(error);
ack && ack(error && error.reason || error);
});
},
remove(){