Started work on library node insert forms
This commit is contained in:
@@ -5,6 +5,7 @@ import librarySchemas from '/imports/api/library/librarySchemas.js';
|
||||
import Libraries from '/imports/api/library/Libraries.js';
|
||||
import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js';
|
||||
import getModifierFields from '/imports/api/getModifierFields.js';
|
||||
import simpleSchemaMixin from '/imports/api/creature/mixins/simpleSchemaMixin.js';
|
||||
|
||||
let LibraryNodes = new Mongo.Collection('libraryNodes');
|
||||
|
||||
@@ -62,6 +63,18 @@ function assertNodeEditPermission(node, userId){
|
||||
return assertEditPermission(lib, userId);
|
||||
}
|
||||
|
||||
const insertNode = new ValidatedMethod({
|
||||
name: 'LibraryNodes.methods.insert',
|
||||
mixins: [
|
||||
simpleSchemaMixin,
|
||||
],
|
||||
schema: LibraryNodeSchema,
|
||||
run(libraryNode) {
|
||||
assertNodeEditPermission(libraryNode, this.userId);
|
||||
return LibraryNodes.insert(libraryNode);
|
||||
},
|
||||
});
|
||||
|
||||
const updateNode = new ValidatedMethod({
|
||||
name: 'LibraryNodes.methods.update',
|
||||
validate({_id, update}){
|
||||
@@ -101,4 +114,4 @@ function libraryNodesToTree(ancestorId){
|
||||
}
|
||||
|
||||
export default LibraryNodes;
|
||||
export { LibraryNodeSchema, updateNode };
|
||||
export { LibraryNodeSchema, insertNode, updateNode };
|
||||
|
||||
@@ -46,6 +46,7 @@ Meteor.publish('library', function(libraryId){
|
||||
const user = Meteor.user();
|
||||
const userId = user && user._id;
|
||||
if (!userId) return [];
|
||||
const subs = user && user.subscribedLibraries || [];
|
||||
let libraryCursor = Libraries.find({
|
||||
_id: libraryId,
|
||||
$or: [
|
||||
|
||||
30
app/imports/ui/components/forms/schemaFormMixin.js
Normal file
30
app/imports/ui/components/forms/schemaFormMixin.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Forms that take in a schema and a model of the current data, manages smart
|
||||
* inputs, and sends update events when valid data model changes must occur
|
||||
*/
|
||||
export default function schemaFormMixin(schema){
|
||||
return {
|
||||
data(){ return {
|
||||
valid: true,
|
||||
};},
|
||||
created(){
|
||||
this.validationContext = schema.newContext();
|
||||
},
|
||||
computed: {
|
||||
errors(){
|
||||
this.valid = true;
|
||||
if (!this.model){
|
||||
throw new Error("this.model must be set");
|
||||
}
|
||||
let cleanModel = this.validationContext.clean(this.model);
|
||||
this.validationContext.validate(cleanModel);
|
||||
let errors = {};
|
||||
this.validationContext.validationErrors().forEach(error => {
|
||||
if (this.valid) this.valid = false;
|
||||
errors[error.name] = Attributes.simpleSchema().messageForError(error);
|
||||
});
|
||||
return errors;
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -79,11 +79,11 @@ export default {
|
||||
this.$emit('change', val, this.acknowledgeChange);
|
||||
},
|
||||
hasChangeListener(){
|
||||
return this.$listeners && this.$listeners.change
|
||||
return this.$listeners && this.$listeners.change;
|
||||
},
|
||||
forceSafeValueUpdate(){
|
||||
// hack to force the value to update on the child component
|
||||
this.safeValue = null
|
||||
this.safeValue = null;
|
||||
this.$nextTick(() => this.safeValue = this.value);
|
||||
},
|
||||
},
|
||||
|
||||
47
app/imports/ui/components/properties/PropertySelector.vue
Normal file
47
app/imports/ui/components/properties/PropertySelector.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template lang="html">
|
||||
<div>
|
||||
<v-container fluid grid-list-lg fill-height>
|
||||
<v-layout row wrap>
|
||||
<v-flex v-for="property in properties" :key="property.name" xs4>
|
||||
<v-card hover @click="$emit('select', property.type)">
|
||||
<div class="layout row align-center justify-center" style="min-height: 70px;">
|
||||
<v-icon x-large>{{ property.icon }}</v-icon>
|
||||
</div>
|
||||
<h3 class="subtitle pb-3" style="text-align: center;">
|
||||
{{ property.name }}
|
||||
</h3>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data(){return {
|
||||
properties: [
|
||||
{name: 'Creature', icon: 'accessibility', type: 'creature'},
|
||||
{name: 'Action', icon: 'offline-bolt', type: 'action'},
|
||||
{name: 'Attribute', icon: 'star-rate', type: 'attribute'},
|
||||
{name: 'Class', icon: 'school', type: 'class'},
|
||||
{name: 'Class Level', icon: 'plus-one', type: 'classLevel'},
|
||||
{name: 'Damage Multiplier', icon: 'layers', type: 'damageMultiplier'},
|
||||
{name: 'Effect', icon: 'show-chart', type: 'effect'},
|
||||
{name: 'Experience', icon: 'add', type: 'experience'},
|
||||
{name: 'Feature', icon: 'subject', type: 'feature'},
|
||||
{name: 'Folder', icon: 'folder', type: 'folder'},
|
||||
{name: 'Note', icon: 'note', type: 'note'},
|
||||
{name: 'Proficiency', icon: 'radio-button-checked', type: 'proficiency'},
|
||||
{name: 'Skill', icon: 'check-box', type: 'skill'},
|
||||
{name: 'Spell List', icon: 'list', type: 'spellList'},
|
||||
{name: 'Spell', icon: 'whatshot', type: 'spell'},
|
||||
{name: 'Container', icon: 'work', type: 'container'},
|
||||
{name: 'Item', icon: 'category', type: 'item'},
|
||||
],
|
||||
}}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -44,6 +44,9 @@
|
||||
},
|
||||
valid: true,
|
||||
}},
|
||||
created(){
|
||||
this.validationContext = Attributes.simpleSchema().newContext();
|
||||
},
|
||||
methods: {
|
||||
change(update, ack){
|
||||
for (key in update){
|
||||
@@ -58,9 +61,6 @@
|
||||
if (ack) ack();
|
||||
},
|
||||
},
|
||||
created(){
|
||||
this.validationContext = Attributes.simpleSchema().newContext();
|
||||
},
|
||||
computed: {
|
||||
errors(){
|
||||
this.valid = true;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<v-layout column style="height: 100%;">
|
||||
<v-toolbar :color="color || 'secondary'" dark class="base-dialog-toolbar" :flat="!offsetTop">
|
||||
<v-btn icon flat @click="close">
|
||||
<v-btn icon flat @click="back">
|
||||
<v-icon>arrow_back</v-icon>
|
||||
</v-btn>
|
||||
<slot name="toolbar"></slot>
|
||||
<slot name="toolbar"/>
|
||||
<template v-if="$slots.edit">
|
||||
<v-spacer/>
|
||||
<v-btn icon flat @click="$emit('remove')" v-if="isEditing">
|
||||
@@ -20,6 +20,7 @@
|
||||
example > bread > crumb
|
||||
</v-card-text>
|
||||
</template>
|
||||
<slot name="unwrapped-content"/>
|
||||
<v-card-text id="base-dialog-body" v-scroll:#base-dialog-body="onScroll">
|
||||
<v-tabs-items :value="isEditing ? 1 : 0" touchless>
|
||||
<v-tab-item>
|
||||
@@ -43,6 +44,7 @@
|
||||
props: {
|
||||
color: String,
|
||||
breadcrumbs: Object,
|
||||
overrideBackButton: Function,
|
||||
},
|
||||
data(){ return {
|
||||
offsetTop: 0,
|
||||
@@ -52,6 +54,13 @@
|
||||
onScroll(e){
|
||||
this.offsetTop = e.target.scrollTop
|
||||
},
|
||||
back(){
|
||||
if (this.overrideBackButton){
|
||||
this.overrideBackButton();
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
},
|
||||
close(){
|
||||
store.dispatch("popDialogStack");
|
||||
},
|
||||
|
||||
@@ -4,6 +4,7 @@ import AttributeCreationDialog from '/imports/ui/creature/properties/attributes/
|
||||
import FeatureCreationDialog from '/imports/ui/creature/properties/features/FeatureCreationDialog.vue';
|
||||
import FeatureDialogContainer from '/imports/ui/creature/properties/features/FeatureDialogContainer.vue';
|
||||
import LibraryCreationDialog from '/imports/ui/library/LibraryCreationDialog.vue';
|
||||
import LibraryNodeCreationDialog from '/imports/ui/library/LibraryNodeCreationDialog.vue';
|
||||
import SkillDialogContainer from '/imports/ui/creature/properties/skills/SkillDialogContainer.vue';
|
||||
|
||||
export default {
|
||||
@@ -13,5 +14,6 @@ export default {
|
||||
FeatureCreationDialog,
|
||||
FeatureDialogContainer,
|
||||
LibraryCreationDialog,
|
||||
LibraryNodeCreationDialog,
|
||||
SkillDialogContainer,
|
||||
};
|
||||
|
||||
42
app/imports/ui/library/LibraryNodeCreationDialog.vue
Normal file
42
app/imports/ui/library/LibraryNodeCreationDialog.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template lang="html">
|
||||
<dialog-base :override-back-button="step === 2 && back">
|
||||
<v-window v-model="step" slot="unwrapped-content" style="height: 100%;">
|
||||
<v-window-item :value="1">
|
||||
<property-selector @select="setType"/>
|
||||
</v-window-item>
|
||||
<v-window-item :value="2">
|
||||
<v-card-text>
|
||||
{{ type }}
|
||||
</v-card-text>
|
||||
</v-window-item>
|
||||
</v-window>
|
||||
</dialog-base>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
|
||||
import PropertySelector from '/imports/ui/components/properties/PropertySelector.vue';
|
||||
|
||||
export default {
|
||||
data() { return {
|
||||
type: undefined,
|
||||
step: 1,
|
||||
};},
|
||||
components: {
|
||||
DialogBase,
|
||||
PropertySelector,
|
||||
},
|
||||
methods: {
|
||||
back(){
|
||||
this.step = 1;
|
||||
},
|
||||
setType(type){
|
||||
this.type = type;
|
||||
this.step = 2;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -6,17 +6,38 @@
|
||||
:library-id="$route.params.id"
|
||||
/>
|
||||
</v-card>
|
||||
<v-btn fixed fab bottom right
|
||||
color="primary"
|
||||
@click="insertLibraryNode"
|
||||
data-id="insert-library-node-fab"
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
</v-btn>
|
||||
</toolbar-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ToolbarLayout from '/imports/ui/layouts/ToolbarLayout.vue';
|
||||
import LibraryContentsContainer from '/imports/ui/library/LibraryContentsContainer.vue';
|
||||
import {insertNode} from '/imports/api/library/LibraryNodes.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ToolbarLayout,
|
||||
LibraryContentsContainer,
|
||||
},
|
||||
methods: {
|
||||
insertLibraryNode(){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'library-node-creation-dialog',
|
||||
elementId: 'insert-library-node-fab',
|
||||
callback(libraryNode){
|
||||
if (!libraryNode) return;
|
||||
let libraryNodeId = insertNode.call(libraryNode);
|
||||
return libraryNodeId;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user