Removed Polymer 0.5, started implementing Polymer 1.0
This commit is contained in:
68
rpg-docs/client/views/private/GeneralCSS/globalDetail.css
Normal file
68
rpg-docs/client/views/private/GeneralCSS/globalDetail.css
Normal file
@@ -0,0 +1,68 @@
|
||||
#detailScreenFiller {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#screenDim {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: grey;
|
||||
background-color: rgba(0,0,0,0.35);
|
||||
}
|
||||
|
||||
#fadeDummy {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.detailContent {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
html /deep/ .red-button:not([disabled]) {
|
||||
background: #d23f31;
|
||||
color: #fff;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
#globalDetail {
|
||||
background-color: white;
|
||||
width: 624px;
|
||||
height: 500px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#globalDetail core-toolbar {
|
||||
border-radius: 2px 2px 0 0;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
#globalDetail core-toolbar {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
#globalDetail {
|
||||
top: 0 !important;
|
||||
left: 0 !important;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.not-selected [hero] {
|
||||
visibility: hidden;
|
||||
}
|
||||
113
rpg-docs/client/views/private/GeneralCSS/typography.css
Normal file
113
rpg-docs/client/views/private/GeneralCSS/typography.css
Normal file
@@ -0,0 +1,113 @@
|
||||
.display2 {
|
||||
font-size: 45px;
|
||||
font-weight: 400;
|
||||
color: #000;
|
||||
color: rgba(0,0,0,0.54);
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.white-text .display2{
|
||||
color: rgba(255,255,255,0.54);
|
||||
}
|
||||
|
||||
.display1 {
|
||||
font-size: 34px;
|
||||
font-weight: 400;
|
||||
color: #000;
|
||||
color: rgba(0,0,0,0.54);
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.white-text .display1, .white-text.display1{
|
||||
color: rgba(255,255,255,0.54);
|
||||
}
|
||||
|
||||
h1, .headline {
|
||||
font-size: 24px;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
color: #000;
|
||||
color: rgba(0,0,0,0.87);
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.white-text h1, .white-text .headline, .white-text.headline{
|
||||
color: rgba(255,255,255,0.87);
|
||||
}
|
||||
|
||||
h2, .title {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
color: #000;
|
||||
color: rgba(0,0,0,0.87);
|
||||
letter-spacing: 0.005em;
|
||||
}
|
||||
|
||||
.white-text h2, .white-text .title, .white-text.title{
|
||||
color: rgba(255,255,255,0.87);
|
||||
}
|
||||
|
||||
h3, .subhead {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
color: #000;
|
||||
color: rgba(0,0,0,0.87);
|
||||
letter-spacing: 0.010em;
|
||||
}
|
||||
|
||||
.white-text h3, .white-text .subhead{
|
||||
color: rgba(255,255,255,0.87);
|
||||
}
|
||||
|
||||
.body2 {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
color: rgba(0,0,0,0.87);
|
||||
letter-spacing: 0.010em;
|
||||
}
|
||||
|
||||
.white-text .body2{
|
||||
color: rgba(255,255,255,0.87);
|
||||
}
|
||||
|
||||
p, .body1, body {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
color: #000;
|
||||
color: rgba(0,0,0,0.87);
|
||||
letter-spacing: 0.010em;
|
||||
}
|
||||
|
||||
.white-text p, .white-text .body1{
|
||||
color: rgba(255,255,255,0.87);
|
||||
}
|
||||
|
||||
.caption{
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #000;
|
||||
color: rgba(0,0,0,0.54);
|
||||
letter-spacing: 0.020em;
|
||||
}
|
||||
|
||||
.white-text .caption{
|
||||
color: rgba(255,255,255,0.54);
|
||||
}
|
||||
|
||||
html /deep/ .white-text{
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.black54 {
|
||||
color: #444;
|
||||
color: rgba(0,0,0,0.54);
|
||||
}
|
||||
|
||||
.white54 {
|
||||
color: #eee;
|
||||
color: rgba(255,255,255,0.54);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<template name="attackEdit">
|
||||
<div layout horizontal>
|
||||
<div layout vertical flex>
|
||||
<div layout horizontal>
|
||||
<!--attackBonus-->
|
||||
<paper-input class="attackBonusInput"
|
||||
label="Attack Bonus"
|
||||
floatinglabel
|
||||
value={{attackBonus}}
|
||||
flex></paper-input>
|
||||
<!--details-->
|
||||
<paper-input class="detailInput"
|
||||
label="Details"
|
||||
floatinglabel
|
||||
value={{details}}></paper-input>
|
||||
</div>
|
||||
<div layout horizontal>
|
||||
<!--damageBonus-->
|
||||
<paper-input class="damageInput"
|
||||
label="Damage"
|
||||
floatinglabel
|
||||
value={{damage}}
|
||||
flex></paper-input>
|
||||
<!--DamageType-->
|
||||
<paper-dropdown-menu class="damageTypeDropdown" label="Damage Type">
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu" selected={{damageType}}>
|
||||
{{#each damageTypes}}
|
||||
<paper-item name={{this}} class="containerMenuItem">{{this}}</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
</div>
|
||||
<!--Delete Button-->
|
||||
<paper-icon-button class="deleteAttack" role="button" tabindex="0" icon="delete" aria-label="Delete"></paper-icon-button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,50 @@
|
||||
var damageTypes = [
|
||||
"bludgeoning",
|
||||
"piercing",
|
||||
"slashing",
|
||||
"acid",
|
||||
"cold",
|
||||
"fire",
|
||||
"force",
|
||||
"lightning",
|
||||
"necrotic",
|
||||
"poison",
|
||||
"psychic",
|
||||
"radiant",
|
||||
"thunder",
|
||||
];
|
||||
|
||||
Template.attackEdit.events({
|
||||
"tap .deleteAttack": function(event, instance) {
|
||||
Attacks.softRemoveNode(this._id);
|
||||
GlobalUI.deletedToast(this._id, "Attacks", "Attack");
|
||||
},
|
||||
"change .attackBonusInput": function(event) {
|
||||
var value = event.currentTarget.value;
|
||||
Attacks.update(this._id, {$set: {attackBonus: value}});
|
||||
},
|
||||
"change .damageInput": function(event) {
|
||||
var value = event.currentTarget.value;
|
||||
Attacks.update(this._id, {$set: {damage: value}});
|
||||
},
|
||||
"change .detailInput": function(event) {
|
||||
var value = event.currentTarget.value;
|
||||
Attacks.update(this._id, {$set: {details: value}});
|
||||
},
|
||||
"core-select .damageTypeDropdown": function(event) {
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var value = detail.item.getAttribute("name");
|
||||
if (value == this.damageType) return;
|
||||
Attacks.update(this._id, {$set: {damageType: value}});
|
||||
},
|
||||
});
|
||||
|
||||
Template.attackEdit.helpers({
|
||||
damageTypes: function() {
|
||||
return damageTypes;
|
||||
},
|
||||
DAMAGE_DICE: function() {
|
||||
return DAMAGE_DICE;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
<!--needs to be given charId, parentId and parentCollection-->
|
||||
<template name="attackEditList">
|
||||
{{#if attacks.count}}
|
||||
<hr style="margin: 16px 0 16px 0;">
|
||||
<div id="attacks">
|
||||
<h2>Attacks</h2>
|
||||
{{#each attacks}}
|
||||
{{>attackEdit}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<paper-button id="addAttackButton" class="red-button" raised>Add Attack</paper-button>
|
||||
</template>
|
||||
@@ -0,0 +1,18 @@
|
||||
Template.attackEditList.helpers({
|
||||
attacks: function() {
|
||||
var cursor = Attacks.find({"parent.id": this.parentId, charId: this.charId});
|
||||
return cursor;
|
||||
}
|
||||
});
|
||||
|
||||
Template.attackEditList.events({
|
||||
"tap #addAttackButton": function() {
|
||||
Attacks.insert({
|
||||
charId: this.charId,
|
||||
parent: {
|
||||
id: this.parentId,
|
||||
collection: this.parentCollection
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
<template name="attackView">
|
||||
<div class="attackView" layout horizontal>
|
||||
<div class="headline" style="margin-right: 16px;" layout horizontal center>
|
||||
{{evaluateSigned charId attackBonus}}
|
||||
</div>
|
||||
<div layout vertical>
|
||||
<div>
|
||||
{{evaluateString charId damage}} {{damageType}}
|
||||
</div>
|
||||
{{#if details}}
|
||||
<div class="caption">
|
||||
{{details}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,11 @@
|
||||
<template name="attacksViewList">
|
||||
{{#if attacks.count}}
|
||||
<hr style="margin: 16px 0 16px 0;">
|
||||
<div class="attacks">
|
||||
<h2 class="spaceAfter">Attacks</h2>
|
||||
{{#each attacks}}
|
||||
{{> attackView}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
@@ -0,0 +1,5 @@
|
||||
Template.attacksViewList.helpers({
|
||||
attacks: function() {
|
||||
return Attacks.find({"parent.id": this.parentId, charId: this.charId});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
<template name="buffDialog">
|
||||
{{#with buff}}
|
||||
{{#baseDialog title=name class=colorClass hideEdit=true}}
|
||||
{{> buffDetails}}
|
||||
{{/baseDialog}}
|
||||
{{/with}}
|
||||
</template>
|
||||
|
||||
<template name="buffDetails">
|
||||
{{#if description}}
|
||||
<div class="pre-wrap">{{evaluateString charId description}}</div>
|
||||
{{/if}}
|
||||
|
||||
{{> effectsViewList charId=charId parentId=_id}}
|
||||
</template>
|
||||
@@ -0,0 +1,5 @@
|
||||
Template.buffDialog.helpers({
|
||||
buff: function(){
|
||||
return Buffs.findOne(this.buffId);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
<template name="characterSettings">
|
||||
{{#with character}}
|
||||
<div style="height: 100px;">
|
||||
<table style="width: 100%;">
|
||||
<tr>
|
||||
<td>Hide Spells tab</td>
|
||||
<td>
|
||||
<paper-toggle-button id="hideSpellcasting"
|
||||
checked={{settings.hideSpellcasting}}
|
||||
touch-action="pan-y">
|
||||
</paper-toggle-button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Use variant encumbrance</td>
|
||||
<td>
|
||||
<paper-toggle-button id="variantEncumbrance"
|
||||
checked={{settings.useVariantEncumbrance}}
|
||||
touch-action="pan-y">
|
||||
</paper-toggle-button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{{/with}}
|
||||
<paper-button id="doneButton" affirmative> Done </paper-button>
|
||||
</template>
|
||||
@@ -0,0 +1,26 @@
|
||||
Template.characterSettings.helpers({
|
||||
character: function() {
|
||||
return Characters.findOne(this._id, {fields: {settings: 1}});
|
||||
}
|
||||
});
|
||||
|
||||
Template.characterSettings.events({
|
||||
"change #variantEncumbrance": function(event, instance){
|
||||
var value = instance.find("#variantEncumbrance").checked;
|
||||
if (this.settings.useVariantEncumbrance !== value){
|
||||
Characters.update(
|
||||
this._id,
|
||||
{$set: {"settings.useVariantEncumbrance": value}}
|
||||
);
|
||||
}
|
||||
},
|
||||
"change #hideSpellcasting": function(event, instance){
|
||||
var value = instance.find("#hideSpellcasting").checked;
|
||||
if (this.settings.hideSpellcasting !== value){
|
||||
Characters.update(
|
||||
this._id,
|
||||
{$set: {"settings.hideSpellcasting": value}}
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
<template name="deleteCharacterConfirmation">
|
||||
<div>
|
||||
Deleting a character cannot be undone.<br>
|
||||
To continue type "{{name}}" into the box below.<br>
|
||||
<paper-input id="nameInput" label="type the characters's name here" style="width: 100%;"></paper-input><br>
|
||||
<paper-button id="deleteButton" style={{getStyle}} disabled={{cantDelete}}>Delete Character</paper-button>
|
||||
</div>
|
||||
<paper-button id="cancelButton" affirmative> Cancel </paper-button>
|
||||
</template>
|
||||
@@ -0,0 +1,28 @@
|
||||
Template.deleteCharacterConfirmation.onCreated(function() {
|
||||
this.canDelete = new ReactiveVar(false);
|
||||
});
|
||||
|
||||
Template.deleteCharacterConfirmation.helpers({
|
||||
cantDelete: function() {
|
||||
return !Template.instance().canDelete.get();
|
||||
},
|
||||
getStyle: function() {
|
||||
if (Template.instance().canDelete.get()) {
|
||||
return "background: #d23f31; color: white;";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Template.deleteCharacterConfirmation.events({
|
||||
"change #nameInput, input #nameInput": function(event, instance) {
|
||||
var canDel = instance.find("#nameInput").value === this.name;
|
||||
instance.canDelete.set(canDel);
|
||||
},
|
||||
"tap #deleteButton": function(event, instance) {
|
||||
if (instance.find("#nameInput").value === this.name) {
|
||||
GlobalUI.closeDialog();
|
||||
Router.go("/");
|
||||
Characters.remove(this._id);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
<template name="shareDialog">
|
||||
<div style="width: 360px;">
|
||||
<div layout horizontal center>
|
||||
<div>Who can view this character: </div>
|
||||
<paper-dropdown-menu class="visibilityDropdown"
|
||||
label="Visibility">
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu visibilityMenu" selected={{viewPermission}}>
|
||||
<paper-item name="whitelist">Only people I share with</paper-item>
|
||||
<paper-item name="public">Anyone with link</paper-item>
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
<div>
|
||||
{{#if readers.count}}
|
||||
<div style="font-weight: 500;">
|
||||
Can View
|
||||
</div>
|
||||
{{#each readers}}
|
||||
<div layout horizontal center>
|
||||
<div flex>{{getUserName}}</div>
|
||||
<paper-icon-button class="deleteShare" icon="delete"></paper-icon-button>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if writers.count}}
|
||||
<div style="font-weight: 500;">
|
||||
Can Edit
|
||||
</div>
|
||||
{{#each writers}}
|
||||
<div layout horizontal center>
|
||||
<div flex>{{username}}</div>
|
||||
<paper-icon-button class="deleteShare" icon="delete"></paper-icon-button>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div layout horizontal center>
|
||||
<paper-input flex id="userNameOrEmailInput" label="Username or email" floatinglabel></paper-input>
|
||||
<paper-button id="shareButton"
|
||||
class="red-button"
|
||||
style="width: 80px; height: 37px; margin-top: 16px;"
|
||||
raised
|
||||
disabled={{shareButtonDisabled}}>Share</paper-button>
|
||||
</div>
|
||||
<p style="color: red;">{{userFindError}}</p>
|
||||
<paper-radio-group id="accessLevelMenu" selected="read">
|
||||
<paper-radio-button name="read" label="View Only"></paper-radio-button>
|
||||
<paper-radio-button name="write" label="Can Edit"></paper-radio-button>
|
||||
</paper-radio-group>
|
||||
</div>
|
||||
<paper-button id="doneButton" affirmative> Done </paper-button>
|
||||
</template>
|
||||
@@ -0,0 +1,76 @@
|
||||
Template.shareDialog.onCreated(function(){
|
||||
this.userId = new ReactiveVar();
|
||||
});
|
||||
|
||||
Template.shareDialog.helpers({
|
||||
viewPermission: function() {
|
||||
var char = Characters.findOne(this._id, {fields: {settings: 1}});
|
||||
return char.settings.viewPermission || "whitelist";
|
||||
},
|
||||
readers: function(){
|
||||
var char = Characters.findOne(this._id, {fields: {readers: 1}});
|
||||
return Meteor.users.find({_id: {$in: char.readers}});
|
||||
},
|
||||
writers: function(){
|
||||
var char = Characters.findOne(this._id, {fields: {writers: 1}});
|
||||
return Meteor.users.find({_id: {$in: char.writers}});
|
||||
},
|
||||
shareButtonDisabled: function(){
|
||||
return !Template.instance().userId.get();
|
||||
},
|
||||
userFindError: function(){
|
||||
if (!Template.instance().userId.get()){
|
||||
return "User not found";
|
||||
}
|
||||
},
|
||||
getUserName: function() {
|
||||
return this.username || "user: " + this._id;
|
||||
}
|
||||
});
|
||||
|
||||
Template.shareDialog.events({
|
||||
"core-select .visibilityDropdown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var value = detail.item.getAttribute("name");
|
||||
var char = Characters.findOne(this._id, {fields: {settings: 1}});
|
||||
if (value == char.settings.viewPermission) return;
|
||||
Characters.update(this._id, {$set: {"settings.viewPermission": value}});
|
||||
},
|
||||
"input #userNameOrEmailInput":
|
||||
function(event, instance){
|
||||
var userName = instance.find("#userNameOrEmailInput").value;
|
||||
instance.userId.set(undefined);
|
||||
Meteor.call("getUserId", userName, function(err, result) {
|
||||
if (err){
|
||||
console.error(err);
|
||||
} else {
|
||||
console.log(result);
|
||||
instance.userId.set(result);
|
||||
}
|
||||
});
|
||||
},
|
||||
"tap #shareButton": function(event, instance){
|
||||
var self = this;
|
||||
var permission = instance.find("#accessLevelMenu").selected;
|
||||
if (!permission) throw "no permission set";
|
||||
var userId = instance.userId.get();
|
||||
if (!userId) return;
|
||||
if (permission === "write"){
|
||||
Characters.update(self._id, {
|
||||
$addToSet: {writers: userId},
|
||||
$pull: {readers: userId},
|
||||
});
|
||||
} else {
|
||||
Characters.update(self._id, {
|
||||
$addToSet: {readers: userId},
|
||||
$pull: {writers: userId},
|
||||
});
|
||||
}
|
||||
},
|
||||
"tap .deleteShare": function(event, instance) {
|
||||
Characters.update(instance.data._id, {
|
||||
$pull: {writers: this._id, readers: this._id}
|
||||
});
|
||||
},
|
||||
});
|
||||
28
rpg-docs/client/views/private/character/characterSheet.css
Normal file
28
rpg-docs/client/views/private/character/characterSheet.css
Normal file
@@ -0,0 +1,28 @@
|
||||
paper-tabs, core-toolbar {
|
||||
box-shadow: 0px 3px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
core-toolbar paper-tabs {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
paper-tabs[noink][nobar] paper-tab.core-selected {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
paper-tabs /deep/ #selectionBar, #onRadio {
|
||||
background-color: #d50000;
|
||||
}
|
||||
|
||||
paper-tabs ::shadow #ink {
|
||||
color: #b22 !important;
|
||||
}
|
||||
|
||||
paper-tabs.transparent-brown {
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
core-toolbar.medium-tall {
|
||||
height: 108px;
|
||||
}
|
||||
54
rpg-docs/client/views/private/character/characterSheet.html
Normal file
54
rpg-docs/client/views/private/character/characterSheet.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<template name="characterSheet">
|
||||
<!--<div tool horizontal layout flex end-justified class="bottom">Title-bottom</div>-->
|
||||
<core-toolbar class="medium-tall {{colorClass}}">
|
||||
<core-icon-button icon="menu" core-drawer-toggle></core-icon-button>
|
||||
<div flex>
|
||||
{{name}}
|
||||
</div>
|
||||
{{#if canEditCharacter _id}}
|
||||
<div>
|
||||
{{> colorDropdown}}
|
||||
</div>
|
||||
<paper-menu-button>
|
||||
<paper-icon-button icon="more-vert" noink></paper-icon-button>
|
||||
<paper-dropdown class="dropdown" halign="right">
|
||||
<core-menu class="menu" style="color: black; color: rgba(0,0,0,0.87);">
|
||||
<paper-item id="deleteCharacter">
|
||||
<core-icon icon="delete"></core-icon>Delete
|
||||
</paper-item>
|
||||
<paper-item id="shareCharacter">
|
||||
<core-icon icon="social:share"></core-icon>Share
|
||||
</paper-item>
|
||||
<paper-item id="characterSettings">
|
||||
<core-icon icon="settings"></core-icon>Settings
|
||||
</paper-item>
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-menu-button>
|
||||
{{/if}}
|
||||
<div class="bottom fit" horizontal layout>
|
||||
<paper-tabs flex horizontal center layout id="characterSheetTabs" selected={{selectedTab}} class="{{colorClass}}">
|
||||
<paper-tab name="stats">Stats</paper-tab>
|
||||
<paper-tab name="features">Features</paper-tab>
|
||||
<paper-tab name="inventory">Inventory</paper-tab>
|
||||
{{#unless hideSpellcasting}}
|
||||
<paper-tab name="spells">Spells</paper-tab>
|
||||
{{/unless}}
|
||||
<paper-tab name="persona">Persona</paper-tab>
|
||||
<paper-tab name="journal">Journal</paper-tab>
|
||||
</paper-tabs>
|
||||
</div>
|
||||
</core-toolbar>
|
||||
<div fit>
|
||||
<core-animated-pages id="tabPages" selected={{selectedTab}} transitions="slide-from-right" fit>
|
||||
<section flex name="stats">{{> stats}}</section>
|
||||
<section flex name="features">{{> features}}</section>
|
||||
<section flex name="inventory">{{> inventory}}</section>
|
||||
{{#unless hideSpellcasting}}
|
||||
<section flex name="spells">{{> spells}}</section>
|
||||
{{/unless}}
|
||||
<section flex name="persona">{{> persona}}</section>
|
||||
<section flex name="journal">{{> journal}}</section>
|
||||
</core-animated-pages>
|
||||
</div>
|
||||
</template>
|
||||
57
rpg-docs/client/views/private/character/characterSheet.js
Normal file
57
rpg-docs/client/views/private/character/characterSheet.js
Normal file
@@ -0,0 +1,57 @@
|
||||
Template.characterSheet.onCreated(function() {
|
||||
//default to the first tab
|
||||
Session.setDefault(this.data._id + ".selectedTab", "stats");
|
||||
//watch this character and make sure their encumbrance is updated
|
||||
trackEncumbranceConditions(this.data._id, this);
|
||||
});
|
||||
|
||||
var setTab = function(charId, tab){
|
||||
return Session.set(charId + ".selectedTab", tab);
|
||||
};
|
||||
|
||||
var getTab = function(charId){
|
||||
return Session.get(charId + ".selectedTab");
|
||||
};
|
||||
|
||||
Template.characterSheet.helpers({
|
||||
selectedTab: function(){
|
||||
return getTab(this._id);
|
||||
},
|
||||
hideSpellcasting: function() {
|
||||
var char = Characters.findOne(this._id);
|
||||
return char && char.settings.hideSpellcasting;
|
||||
},
|
||||
});
|
||||
|
||||
Template.characterSheet.events({
|
||||
"core-animated-pages-transition-end #tabPages": function(event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
"tap #characterSheetTabs paper-tab": function(event, instance){
|
||||
setTab(this._id, event.currentTarget.getAttribute("name"));
|
||||
},
|
||||
"color-change": function(event, instance){
|
||||
Characters.update(this._id, {$set: {color: event.color}});
|
||||
},
|
||||
"tap #deleteCharacter": function(event, instance){
|
||||
GlobalUI.showDialog({
|
||||
heading: "Delete " + this.name,
|
||||
data: this,
|
||||
template: "deleteCharacterConfirmation",
|
||||
});
|
||||
},
|
||||
"tap #shareCharacter": function(event, instance){
|
||||
GlobalUI.showDialog({
|
||||
heading: "Share " + this.name,
|
||||
data: this,
|
||||
template: "shareDialog",
|
||||
});
|
||||
},
|
||||
"tap #characterSettings": function(event, instance){
|
||||
GlobalUI.showDialog({
|
||||
heading: this.name + " Settings",
|
||||
data: this,
|
||||
template: "characterSettings",
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
html /deep/ .operationDropDown {
|
||||
width: 152px;
|
||||
}
|
||||
|
||||
html /deep/ .statDropDown {
|
||||
width: 152px;
|
||||
}
|
||||
|
||||
html /deep/ .damageMultiplierDropDown {
|
||||
width: 152px;
|
||||
}
|
||||
|
||||
html /deep/ .effectEdit paper-input {
|
||||
position: relative;
|
||||
bottom: 5px;
|
||||
}
|
||||
|
||||
html /deep/ .effectEdit {
|
||||
height: 64px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<template name="effectEdit">
|
||||
<div class="effectEdit" layout horizontal center>
|
||||
<paper-dropdown-menu class="statDropDown"
|
||||
label="Stat">
|
||||
<paper-dropdown layered
|
||||
class="dropdown">
|
||||
<core-menu class="menu statMenu" selected={{stat}}>
|
||||
{{#each statGroups}}
|
||||
<div style="font-weight: bold;
|
||||
margin-top: 16px;">{{this}}</div>
|
||||
{{#each stats}}
|
||||
<paper-item name={{stat}}>{{name}}</paper-item>
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
{{#if operations}}
|
||||
<paper-dropdown-menu class="operationDropDown"
|
||||
label="Operation">
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu operationMenu" selected={{operation}}>
|
||||
{{#each operations}}
|
||||
<paper-item name={{operation}}>{{name}}</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
{{/if}}
|
||||
{{#if effectValueTemplate}}
|
||||
{{> Template.dynamic template=effectValueTemplate}}
|
||||
{{else}}
|
||||
<div flex></div>
|
||||
{{/if}}
|
||||
<paper-icon-button class="deleteEffect"
|
||||
icon="delete">
|
||||
</paper-icon-button>
|
||||
<br>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="regularEffectValue">
|
||||
<paper-input class="effectValueInput"
|
||||
label="Value"
|
||||
floatinglabel
|
||||
value={{effectValue}}
|
||||
flex
|
||||
style="flex-basis: 100px;">
|
||||
</paper-input>
|
||||
</template>
|
||||
|
||||
<template name="multiplierEffectValue">
|
||||
<paper-dropdown-menu class="damageMultiplierDropDown"
|
||||
label="Damage Multiplier">
|
||||
<paper-dropdown layered
|
||||
class="dropdown">
|
||||
<core-menu class="menu multiplierMenu"
|
||||
selected={{value}}>
|
||||
<paper-item name="0.5">Resistance</paper-item>
|
||||
<paper-item name="2">Vulnerability</paper-item>
|
||||
<paper-item name="0">Immunity</paper-item>
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
<div flex></div>
|
||||
</template>
|
||||
@@ -0,0 +1,178 @@
|
||||
//TODO add dexterity armor
|
||||
var stats = [
|
||||
{stat: "strength", name: "Strength", group: "Ability Scores"},
|
||||
{stat: "dexterity", name: "Dexterity", group: "Ability Scores"},
|
||||
{stat: "constitution", name: "Constitution", group: "Ability Scores"},
|
||||
{stat: "intelligence", name: "Intelligence", group: "Ability Scores"},
|
||||
{stat: "wisdom", name: "Wisdom", group: "Ability Scores"},
|
||||
{stat: "charisma", name: "Charisma", group: "Ability Scores"},
|
||||
{name: "Strength Save", stat: "strengthSave", group: "Saving Throws"},
|
||||
{name: "Dexterity Save", stat: "dexteritySave", group: "Saving Throws"},
|
||||
{name: "Constitution Save", stat: "constitutionSave", group: "Saving Throws"},
|
||||
{name: "Intelligence Save", stat: "intelligenceSave", group: "Saving Throws"},
|
||||
{name: "Wisdom Save", stat: "wisdomSave", group: "Saving Throws"},
|
||||
{name: "Charisma Save", stat: "charismaSave", group: "Saving Throws"},
|
||||
{name: "Acrobatics", stat: "acrobatics", group: "Skills"},
|
||||
{name: "Animal Handling", stat: "animalHandling", group: "Skills"},
|
||||
{name: "Arcana", stat: "arcana", group: "Skills"},
|
||||
{name: "Athletics", stat: "athletics", group: "Skills"},
|
||||
{name: "Deception", stat: "deception", group: "Skills"},
|
||||
{name: "History", stat: "history", group: "Skills"},
|
||||
{name: "Insight", stat: "insight", group: "Skills"},
|
||||
{name: "Intimidation", stat: "intimidation", group: "Skills"},
|
||||
{name: "Investigation", stat: "investigation", group: "Skills"},
|
||||
{name: "Medicine", stat: "medicine", group: "Skills"},
|
||||
{name: "Nature", stat: "nature", group: "Skills"},
|
||||
{name: "Perception", stat: "perception", group: "Skills"},
|
||||
{name: "Performance", stat: "performance", group: "Skills"},
|
||||
{name: "Persuasion", stat: "persuasion", group: "Skills"},
|
||||
{name: "Religion", stat: "religion", group: "Skills"},
|
||||
{name: "Sleight of Hand", stat: "sleightOfHand", group: "Skills"},
|
||||
{name: "Stealth", stat: "stealth", group: "Skills"},
|
||||
{name: "Survival", stat: "survival", group: "Skills"},
|
||||
{name: "Initiative", stat: "initiative", group: "Skills"},
|
||||
{stat: "hitPoints", name: "Hit Points", group: "Stats"},
|
||||
{stat: "armor", name: "Armor", group: "Stats"},
|
||||
{stat: "dexterityArmor", name: "Dexterity Armor Bonus", group: "Stats"},
|
||||
{stat: "speed", name: "Speed", group: "Stats"},
|
||||
{stat: "proficiencyBonus", name: "Proficiency Bonus", group: "Stats"},
|
||||
{stat: "ki", name: "Ki Points", group: "Stats"},
|
||||
{stat: "sorceryPoints", name: "Sorcery Points", group: "Stats"},
|
||||
{stat: "rages", name: "Rages", group: "Stats"},
|
||||
{stat: "rageDamage", name: "Rage Damage", group: "Stats"},
|
||||
{stat: "expertiseDice", name: "Expertise Dice", group: "Stats"},
|
||||
{stat: "superiorityDice", name: "Superiority Dice", group: "Stats"},
|
||||
{stat: "carryMultiplier", name: "Carry Capacity Multiplier", group: "Stats"},
|
||||
{stat: "level1SpellSlots", name: "level 1", group: "Spell Slots"},
|
||||
{stat: "level2SpellSlots", name: "level 2", group: "Spell Slots"},
|
||||
{stat: "level3SpellSlots", name: "level 3", group: "Spell Slots"},
|
||||
{stat: "level4SpellSlots", name: "level 4", group: "Spell Slots"},
|
||||
{stat: "level5SpellSlots", name: "level 5", group: "Spell Slots"},
|
||||
{stat: "level6SpellSlots", name: "level 6", group: "Spell Slots"},
|
||||
{stat: "level7SpellSlots", name: "level 7", group: "Spell Slots"},
|
||||
{stat: "level8SpellSlots", name: "level 8", group: "Spell Slots"},
|
||||
{stat: "level9SpellSlots", name: "level 9", group: "Spell Slots"},
|
||||
{stat: "d6HitDice", name: "d6", group: "Hit Dice"},
|
||||
{stat: "d8HitDice", name: "d8", group: "Hit Dice"},
|
||||
{stat: "d10HitDice", name: "d10", group: "Hit Dice"},
|
||||
{stat: "d12HitDice", name: "d12", group: "Hit Dice"},
|
||||
{stat: "acidMultiplier", name: "Acid", group: "Weakness/Resistance"},
|
||||
{stat: "bludgeoningMultiplier", name: "Bludgeoning", group: "Weakness/Resistance"},
|
||||
{stat: "coldMultiplier", name: "Cold", group: "Weakness/Resistance"},
|
||||
{stat: "fireMultiplier", name: "Fire", group: "Weakness/Resistance"},
|
||||
{stat: "forceMultiplier", name: "Force", group: "Weakness/Resistance"},
|
||||
{stat: "lightningMultiplier", name: "Lightning", group: "Weakness/Resistance"},
|
||||
{stat: "necroticMultiplier", name: "Necrotic", group: "Weakness/Resistance"},
|
||||
{stat: "piercingMultiplier", name: "Piercing", group: "Weakness/Resistance"},
|
||||
{stat: "poisonMultiplier", name: "Poison", group: "Weakness/Resistance"},
|
||||
{stat: "psychicMultiplier", name: "Psychic", group: "Weakness/Resistance"},
|
||||
{stat: "radiantMultiplier", name: "Radiant", group: "Weakness/Resistance"},
|
||||
{stat: "slashingMultiplier", name: "Slashing", group: "Weakness/Resistance"},
|
||||
{stat: "thunderMultiplier", name: "Thunder", group: "Weakness/Resistance"}
|
||||
];
|
||||
|
||||
var statsDict = _.indexBy(stats, "stat");
|
||||
var statGroups = _.groupBy(stats, "group");
|
||||
var statGroupNames = _.keys(statGroups);
|
||||
|
||||
var attributeOperations = [
|
||||
{name: "Base Value", operation: "base"},
|
||||
{name: "Add", operation: "add"},
|
||||
{name: "Multiply", operation: "mul"},
|
||||
{name: "Min", operation: "min"},
|
||||
{name: "Max", operation: "max"}
|
||||
];
|
||||
var skillOperations = [
|
||||
{name: "Add", operation: "add"},
|
||||
{name: "Multiply", operation: "mul"},
|
||||
{name: "Min", operation: "min"},
|
||||
{name: "Max", operation: "max"},
|
||||
{name: "Advantage", operation: "advantage"},
|
||||
{name: "Disadvantage", operation: "disadvantage"},
|
||||
{name: "Passive Bonus", operation: "passiveAdd"},
|
||||
{name: "Automatically Fail", operation: "fail"},
|
||||
{name: "Conditional Benefit", operation: "conditional"}
|
||||
];
|
||||
|
||||
Template.effectEdit.helpers({
|
||||
statGroups: function(){
|
||||
return statGroupNames;
|
||||
},
|
||||
stats: function(){
|
||||
var group = this;
|
||||
return statGroups[group];
|
||||
},
|
||||
operations: function(){
|
||||
var stat = statsDict[this.stat];
|
||||
var group = stat && stat.group;
|
||||
if (group === "Weakness/Resistance") return null;
|
||||
if (group === "Saving Throws" || group === "Skills"){
|
||||
return skillOperations;
|
||||
} else {
|
||||
return attributeOperations;
|
||||
}
|
||||
},
|
||||
effectValueTemplate: function(){
|
||||
//resistance/vulnerability template
|
||||
var stat = statsDict[this.stat];
|
||||
var group = stat && stat.group;
|
||||
if (group === "Weakness/Resistance") return "multiplierEffectValue";
|
||||
|
||||
var op = this.operation;
|
||||
if (!op) return null;
|
||||
//operations that don't need templates
|
||||
if (op === "advantage" || op === "disadvantage" || op === "fail") return null;
|
||||
|
||||
//default template
|
||||
return "regularEffectValue";
|
||||
}
|
||||
});
|
||||
|
||||
Template.regularEffectValue.helpers({
|
||||
effectValue: function(){
|
||||
return this.calculation || this.value;
|
||||
}
|
||||
});
|
||||
|
||||
Template.effectEdit.events({
|
||||
"tap .deleteEffect": function(event){
|
||||
Effects.softRemoveNode(this._id);
|
||||
GlobalUI.deletedToast(this._id, "Effects", "Effect");
|
||||
},
|
||||
"core-select .statDropDown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var statName = detail.item.getAttribute("name");
|
||||
if (statName == this.stat) return;
|
||||
Effects.update(this._id, {$set: {stat: statName}});
|
||||
},
|
||||
"core-select .operationDropDown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var opName = detail.item.getAttribute("name");
|
||||
if (opName == this.operation) return;
|
||||
Effects.update(this._id, {$set: {operation: opName}});
|
||||
},
|
||||
"core-select .damageMultiplierDropDown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var value = +detail.item.getAttribute("name");
|
||||
if (value == this.value) return;
|
||||
Effects.update(this._id, {$set: {
|
||||
value: value,
|
||||
calculation: "",
|
||||
operation: "mul"
|
||||
}});
|
||||
},
|
||||
"change .effectValueInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
var numValue = +value;
|
||||
if (_.isFinite(numValue)){
|
||||
if (this.value === numValue) return;
|
||||
Effects.update(this._id, {$set: {value: numValue, calculation: ""}});
|
||||
} else if (_.isString(value)){
|
||||
if (this.calculation === value) return;
|
||||
Effects.update(this._id, {$set: {value: "", calculation: value}});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
<template name="effectView">
|
||||
<tr>
|
||||
<td>{{statName}}</td>
|
||||
<td>{{operationName}}{{statValue}}</td>
|
||||
</tr>
|
||||
</template>
|
||||
@@ -0,0 +1,169 @@
|
||||
//TODO add dexterity armor
|
||||
var stats = {
|
||||
"strength":{"name":"Strength"},
|
||||
"dexterity":{"name":"Dexterity"},
|
||||
"constitution":{"name":"Constitution"},
|
||||
"intelligence":{"name":"Intelligence"},
|
||||
"wisdom":{"name":"Wisdom"},
|
||||
"charisma":{"name":"Charisma"},
|
||||
"strengthSave":{"name":"Strength Save"},
|
||||
"dexteritySave":{"name":"Dexterity Save"},
|
||||
"constitutionSave":{"name":"Constitution Save"},
|
||||
"intelligenceSave":{"name":"Intelligence Save"},
|
||||
"wisdomSave":{"name":"Wisdom Save"},
|
||||
"charismaSave":{"name":"Charisma Save"},
|
||||
"acrobatics":{"name":"Acrobatics"},
|
||||
"animalHandling":{"name":"Animal Handling"},
|
||||
"arcana":{"name":"Arcana"},
|
||||
"athletics":{"name":"Athletics"},
|
||||
"deception":{"name":"Deception"},
|
||||
"history":{"name":"History"},
|
||||
"insight":{"name":"Insight"},
|
||||
"intimidation":{"name":"Intimidation"},
|
||||
"investigation":{"name":"Investigation"},
|
||||
"medicine":{"name":"Medicine"},
|
||||
"nature":{"name":"Nature"},
|
||||
"perception":{"name":"Perception"},
|
||||
"performance":{"name":"Performance"},
|
||||
"persuasion":{"name":"Persuasion"},
|
||||
"religion":{"name":"Religion"},
|
||||
"sleightOfHand":{"name":"Sleight of Hand"},
|
||||
"stealth":{"name":"Stealth"},
|
||||
"survival":{"name":"Survival"},
|
||||
"initiative":{"name":"Initiative"},
|
||||
"hitPoints":{"name":"Hit Points"},
|
||||
"armor":{"name":"Armor"},
|
||||
"dexterityArmor":{"name":"Dexterity Armor Bonus"},
|
||||
"speed":{"name":"Speed"},
|
||||
"proficiencyBonus":{"name":"Proficiency Bonus"},
|
||||
"ki":{"name":"Ki Points"},
|
||||
"sorceryPoints":{"name":"Sorcery Points"},
|
||||
"rages":{"name":"Rages"},
|
||||
"rageDamage":{"name":"Rage Damage"},
|
||||
"expertiseDice":{"name":"Expertise Dice"},
|
||||
"superiorityDice":{"name":"Superiority Dice"},
|
||||
"carryMultiplier": {"name": "Carry Capacity Multiplier"},
|
||||
"level1SpellSlots":{"name":"level 1 Spell Slots"},
|
||||
"level2SpellSlots":{"name":"level 2 Spell Slots"},
|
||||
"level3SpellSlots":{"name":"level 3 Spell Slots"},
|
||||
"level4SpellSlots":{"name":"level 4 Spell Slots"},
|
||||
"level5SpellSlots":{"name":"level 5 Spell Slots"},
|
||||
"level6SpellSlots":{"name":"level 6 Spell Slots"},
|
||||
"level7SpellSlots":{"name":"level 7 Spell Slots"},
|
||||
"level8SpellSlots":{"name":"level 8 Spell Slots"},
|
||||
"level9SpellSlots":{"name":"level 9 Spell Slots"},
|
||||
"d6HitDice":{"name":"d6 Hit Dice"},
|
||||
"d8HitDice":{"name":"d8 Hit Dice"},
|
||||
"d10HitDice":{"name":"d10 Hit Dice"},
|
||||
"d12HitDice":{"name":"d12 Hit Dice"},
|
||||
"acidMultiplier":{"name":"Acid damage", "group": "Weakness/Resistance"},
|
||||
"bludgeoningMultiplier":{
|
||||
"name":"Bludgeoning damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
"coldMultiplier":{
|
||||
"name":"Cold damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
"fireMultiplier":{
|
||||
"name":"Fire damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
"forceMultiplier":{
|
||||
"name":"Force damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
"lightningMultiplier":{
|
||||
"name":"Lightning damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
"necroticMultiplier":{
|
||||
"name":"Necrotic damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
"piercingMultiplier":{
|
||||
"name":"Piercing damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
"poisonMultiplier":{
|
||||
"name":"Poison damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
"psychicMultiplier":{
|
||||
"name":"Psychic damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
"radiantMultiplier":{
|
||||
"name":"Radiant damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
"slashingMultiplier":{
|
||||
"name":"Slashing damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
"thunderMultiplier":{
|
||||
"name":"Thunder damage", "group": "Weakness/Resistance",
|
||||
},
|
||||
};
|
||||
|
||||
var operations = {
|
||||
base: {name: "Base Value: "},
|
||||
proficiency: {name: "Proficiency"},
|
||||
add: {name: "+"},
|
||||
mul: {name: "×"},
|
||||
min: {name: "Min: "},
|
||||
max: {name: "Max: "},
|
||||
advantage: {name: "Advantage"},
|
||||
disadvantage: {name: "Disadvantage"},
|
||||
passiveAdd: {name: "Passive Bonus: "},
|
||||
fail: {name: "Automatically Fail"},
|
||||
};
|
||||
|
||||
Template.effectView.helpers({
|
||||
sourceName: function(){
|
||||
var id = this.parent.id;
|
||||
if (!id) return;
|
||||
switch (this.parent.collection){
|
||||
case "Features":
|
||||
return "Feature - " + Features.findOne(id, {fields: {name: 1}}).name;
|
||||
case "Classes":
|
||||
return Classes.findOne(id, {fields: {name: 1}}).name;
|
||||
case "Buffs":
|
||||
return "Buff - " + Buffs.findOne(id, {fields: {name: 1}}).name;
|
||||
case "Items":
|
||||
return "Equipment - " + Items.findOne(id, {fields: {name: 1}}).name;
|
||||
case "Characters":
|
||||
return Characters.findOne(this.charId, {fields: {race: 1}}).race;
|
||||
default:
|
||||
return "Inate";
|
||||
}
|
||||
},
|
||||
statName: function(){
|
||||
return stats[this.stat] && stats[this.stat].name || "No Stat";
|
||||
},
|
||||
operationName: function(){
|
||||
if (this.operation === "proficiency" ||
|
||||
this.operation === "conditional") return null;
|
||||
if (stats[this.stat] && stats[this.stat].group === "Weakness/Resistance")
|
||||
return null;
|
||||
if (this.operation === "add" && evaluateEffect(this.charId, this) < 0)
|
||||
return null;
|
||||
return operations[this.operation] &&
|
||||
operations[this.operation].name || "No Operation";
|
||||
},
|
||||
statValue: function(){
|
||||
if (this.operation === "advantage" ||
|
||||
this.operation === "disadvantage" ||
|
||||
this.operation === "fail"){
|
||||
return null;
|
||||
}
|
||||
if (this.operation === "proficiency"){
|
||||
if (this.value == 0.5 || this.calculation == 0.5)
|
||||
return "Half Proficiency";
|
||||
if (this.value == 1 || this.calculation == 1)
|
||||
return "Proficiency";
|
||||
if (this.value == 2 || this.calculation == 2)
|
||||
return "Double Proficiency";
|
||||
}
|
||||
if (this.operation === "conditional"){
|
||||
return this.calculation || this.value;
|
||||
}
|
||||
if (stats[this.stat] && stats[this.stat].group === "Weakness/Resistance"){
|
||||
if (this.value === 0.5) return "Resistance";
|
||||
if (this.value === 2) return "Vulnerability";
|
||||
if (this.value === 0) return "Immunity";
|
||||
}
|
||||
var value = evaluateEffect(this.charId, this);
|
||||
if (_.isNumber(value)) return value;
|
||||
return this.calculation || this.value;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
<!--needs to be given charId, parentId and parentCollection-->
|
||||
<template name="effectsEditList">
|
||||
{{#if effects.count}}
|
||||
<hr class="vertMargin">
|
||||
<div id="effects">
|
||||
<h2>Effects</h2>
|
||||
{{#each effects}}
|
||||
{{>effectEdit}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<paper-button id="addEffectButton" class="red-button" raised>Add Effect</paper-button>
|
||||
</template>
|
||||
@@ -0,0 +1,33 @@
|
||||
Template.effectsEditList.helpers({
|
||||
effects: function(){
|
||||
var selector = {
|
||||
"parent.id": this.parentId,
|
||||
"parent.collection": this.parentCollection,
|
||||
"charId": this.charId,
|
||||
};
|
||||
if (this.parentGroup){
|
||||
selector["parent.group"] = this.parentGroup;
|
||||
}
|
||||
var cursor = Effects.find(selector);
|
||||
return cursor;
|
||||
}
|
||||
});
|
||||
|
||||
Template.effectsEditList.events({
|
||||
"tap #addEffectButton": function(){
|
||||
if (!_.isBoolean(this.enabled)) {
|
||||
this.enabled = true;
|
||||
}
|
||||
Effects.insert({
|
||||
name: this.name,
|
||||
charId: this.charId,
|
||||
parent: {
|
||||
id: this.parentId,
|
||||
collection: this.parentCollection,
|
||||
group: this.parentGroup,
|
||||
},
|
||||
operation: "add",
|
||||
enabled: this.enabled,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
<!--needs to be given charId, (parentId or stat) and type-->
|
||||
<template name="effectsViewList">
|
||||
{{#if effects.count}}
|
||||
<hr style="margin: 16px 0 16px 0;">
|
||||
<div class="effects">
|
||||
<h2 class="spaceAfter">Effects</h2>
|
||||
<table class="wideTable">
|
||||
{{#each effects}}
|
||||
{{>effectView}}
|
||||
{{/each}}
|
||||
</table>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
@@ -0,0 +1,12 @@
|
||||
Template.effectsViewList.helpers({
|
||||
effects: function(){
|
||||
var selector = {
|
||||
"parent.id": this.parentId,
|
||||
"charId": this.charId
|
||||
};
|
||||
if (this.parentGroup){
|
||||
selector["parent.group"] = this.parentGroup;
|
||||
}
|
||||
return Effects.find(selector, {fields: {parent: 0}});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
<template name="featureDialog">
|
||||
{{#with feature}}
|
||||
{{#baseDialog title=name class=colorClass startEditing=../startEditing}}
|
||||
{{> featureDetails}}
|
||||
{{else}}
|
||||
{{> featureEdit}}
|
||||
{{/baseDialog}}
|
||||
{{/with}}
|
||||
</template>
|
||||
|
||||
<template name="featureDetails">
|
||||
{{#if or canEnable hasUses}}
|
||||
<div layout horizontal center justified wrap>
|
||||
{{#if canEnable}}
|
||||
<div>enabled:</div>
|
||||
<paper-checkbox class="sideMargin" checked={{enabled}}></paper-checkbox>
|
||||
{{/if}}
|
||||
{{#if hasUses}}
|
||||
<div class="subhead" style="margin-right: 16px">
|
||||
Uses: {{usesLeft}}/{{usesValue}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if hasUses}}
|
||||
<div layout horizontal>
|
||||
<paper-button class="useFeature" disabled={{noUsesLeft}}>Use</paper-button>
|
||||
<paper-button class="resetFeature" disabled={{usesFull}}>Reset</paper-button>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<hr class="vertMargin">
|
||||
{{/if}}
|
||||
|
||||
{{#if description}}
|
||||
<div>{{#markdown}}{{evaluateString charId description}}{{/markdown}}</div>
|
||||
{{/if}}
|
||||
|
||||
{{> effectsViewList charId=charId parentId=_id}}
|
||||
{{> proficiencyViewList charId=charId parentId=_id}}
|
||||
</template>
|
||||
|
||||
<template name="featureEdit">
|
||||
<!--name-->
|
||||
<paper-input id="featureNameInput" class="fullwidth" label="Name" floatinglabel value={{name}}></paper-input>
|
||||
|
||||
<hr class="vertMargin">
|
||||
|
||||
<div layout horizontal center style="height: 60px;">
|
||||
<paper-dropdown-menu id="enabledDropdown" label="Enable Feature">
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu id="enabledMenu" class="menu" selected={{enabledSelection}} on-tap="onStatMenuTap">
|
||||
<paper-item name="alwaysEnabled"> Always Enabled </paper-item>
|
||||
<paper-item name="enabled"> Enabled </paper-item>
|
||||
<paper-item name="disabled"> Disabled </paper-item>
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
<div layout horizontal center class="sideMargin">
|
||||
<div>Limit Uses: </div>
|
||||
<paper-toggle-button id="limitUseCheck"
|
||||
class="sideMargin"
|
||||
checked={{usesSet}}
|
||||
role="button"
|
||||
aria-pressed="false"
|
||||
tabindex="0"
|
||||
touch-action="pan-y">
|
||||
</paper-toggle-button>
|
||||
</div>
|
||||
{{#if usesSet}}
|
||||
<paper-input flex id="usesInput" label="Uses" floatinglabel value={{uses}}></paper-input>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<hr class="vertMargin">
|
||||
|
||||
<!--description-->
|
||||
<paper-input-decorator label="Description" floatinglabel layout vertical>
|
||||
<paper-autogrow-textarea>
|
||||
<textarea id="featureDescriptionInput" placeholder aria-label="Description" value={{description}}></textarea>
|
||||
</paper-autogrow-textarea>
|
||||
</paper-input-decorator>
|
||||
|
||||
{{> effectsEditList parentId=_id parentCollection="Features" charId=charId name=name enabled=enabled}}
|
||||
{{> proficiencyEditList parentId=_id parentCollection="Features" charId=charId enabled=enabled}}
|
||||
</template>
|
||||
@@ -0,0 +1,109 @@
|
||||
Template.featureDialog.helpers({
|
||||
feature: function(){
|
||||
return Features.findOne(this.featureId);
|
||||
},
|
||||
});
|
||||
|
||||
Template.featureDialog.events({
|
||||
"color-change": function(event, instance){
|
||||
Features.update(instance.data.featureId, {$set: {color: event.color}});
|
||||
},
|
||||
"tap #deleteButton": function(event, instance){
|
||||
Features.softRemoveNode(instance.data.featureId);
|
||||
GlobalUI.deletedToast(instance.data.featureId, "Features", "Feature");
|
||||
GlobalUI.closeDetail();
|
||||
},
|
||||
});
|
||||
|
||||
Template.featureDetails.helpers({
|
||||
or: function(a, b){
|
||||
return a || b;
|
||||
},
|
||||
hasUses: function(){
|
||||
return this.usesValue() > 0;
|
||||
},
|
||||
noUsesLeft: function(){
|
||||
return this.usesLeft() <= 0;
|
||||
},
|
||||
usesFull: function(){
|
||||
return this.usesLeft() >= this.usesValue();
|
||||
},
|
||||
});
|
||||
|
||||
Template.featureDetails.events({
|
||||
"tap .useFeature": function(event){
|
||||
var featureId = this._id;
|
||||
Features.update(featureId, {$inc: {used: 1}});
|
||||
},
|
||||
"tap .resetFeature": function(event){
|
||||
var featureId = this._id;
|
||||
Features.update(featureId, {$set: {used: 0}});
|
||||
},
|
||||
|
||||
"change .enabledCheckbox": function(event){
|
||||
var enabled = !this.enabled;
|
||||
Features.update(this._id, {$set: {enabled: enabled}});
|
||||
},
|
||||
});
|
||||
|
||||
Template.featureEdit.onRendered(function(){
|
||||
updatePolymerInputs(this);
|
||||
});
|
||||
|
||||
Template.featureEdit.helpers({
|
||||
usesSet: function(){
|
||||
return _.isString(this.uses);
|
||||
},
|
||||
enabledSelection: function(){
|
||||
if (this.enabled){
|
||||
if (this.alwaysEnabled){
|
||||
return "alwaysEnabled";
|
||||
} else {
|
||||
return "enabled";
|
||||
}
|
||||
} else if (this.enabled === false){ //make sure it is false, not just falsey
|
||||
return "disabled";
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.featureEdit.events({
|
||||
"change #featureNameInput": function(event){
|
||||
var name = Template.instance().find("#featureNameInput").value;
|
||||
Features.update(this._id, {$set: {name: name}});
|
||||
},
|
||||
"change #featureDescriptionInput": function(event){
|
||||
var description = Template.instance().find("#featureDescriptionInput").value;
|
||||
Features.update(this._id, {$set: {description: description}});
|
||||
},
|
||||
"change #limitUseCheck": function(event){
|
||||
var currentUses = this.uses;
|
||||
var featureId = this._id;
|
||||
if (event.target.checked && !_.isString(currentUses)){
|
||||
Features.update(featureId, {$set: {uses: ""}}, {removeEmptyStrings: false});
|
||||
} else if (!event.target.checked && _.isString(currentUses)){
|
||||
Features.update(featureId, {$unset: {uses: ""}});
|
||||
}
|
||||
},
|
||||
"change #usesInput, input #quantityInput": function(event){
|
||||
var value = event.target.value;
|
||||
var featureId = this._id;
|
||||
Features.update(featureId, {$set: {uses: value}});
|
||||
},
|
||||
"core-select #enabledDropdown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var value = detail.item.getAttribute("name");
|
||||
var setter;
|
||||
if (value === "enabled"){
|
||||
setter = {enabled: true, alwaysEnabled: false};
|
||||
} else if (value === "disabled"){
|
||||
setter = {enabled: false, alwaysEnabled: false};
|
||||
} else {
|
||||
setter = {enabled: true, alwaysEnabled: true};
|
||||
}
|
||||
if (setter.enabled === this.enabled &&
|
||||
setter.alwaysEnabled === this.alwaysEnabled) return;
|
||||
Features.update(this._id, {$set: setter});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
.containerTop {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.features {
|
||||
display: flex !important;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.featureCardTop {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.containerMain.featureDescription {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.resourceCards paper-shadow.healthCard {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/*To change the ink color for checked state:*/
|
||||
.containerTop paper-checkbox::shadow #ink[checked] {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/*To change the checkbox checked color:*/
|
||||
.containerTop paper-checkbox::shadow #checkbox.checked {
|
||||
background-color: #ffffff;
|
||||
background-color: rgba(255,255,255,0.27);
|
||||
border-color: #ffffff;
|
||||
border-color: rgba(255,255,255,0.27);
|
||||
}
|
||||
|
||||
/*ensure the checkmark is shown when ticked*/
|
||||
.containerTop paper-checkbox::shadow #checkbox.checked #checkmark {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
/*To change the ink color for unchecked state:*/
|
||||
.containerTop paper-checkbox::shadow #ink {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/*To change the checkbox unchecked color:*/
|
||||
.containerTop paper-checkbox::shadow #checkbox {
|
||||
border-color: #ffffff;
|
||||
border-color: rgba(255,255,255,0.54);
|
||||
}
|
||||
|
||||
/*ensure checkmark isn't shown early*/
|
||||
.containerTop paper-checkbox::shadow #checkbox #checkmark {
|
||||
display: none;
|
||||
}
|
||||
174
rpg-docs/client/views/private/character/features/features.html
Normal file
174
rpg-docs/client/views/private/character/features/features.html
Normal file
@@ -0,0 +1,174 @@
|
||||
<template name="features">
|
||||
<div fit>
|
||||
<div class="scroll-y" fit>
|
||||
<div class="column-container">
|
||||
<!--expertiseDice-->
|
||||
{{>resource name="expertiseDice" title="Expertise Dice" color="teal" char=this}}
|
||||
<!--ki-->
|
||||
{{>resource name="ki" title="Ki Points" color="teal" char=this}}
|
||||
<!--rages-->
|
||||
{{>resource name="rages" title="Rages" color="teal" char=this}}
|
||||
<!--sorceryPoints-->
|
||||
{{>resource name="sorceryPoints" title="Sorcery Points" color="teal" char=this}}
|
||||
<!--superiorityDice-->
|
||||
{{>resource name="superiorityDice" title="Superiority Dice" color="teal" char=this}}
|
||||
|
||||
<!--Attacks-->
|
||||
<div>
|
||||
<paper-shadow class="card">
|
||||
<div class="top white">
|
||||
Attacks
|
||||
</div>
|
||||
<div class="bottom list">
|
||||
{{#each attacks}}
|
||||
<div class="item-slot">
|
||||
<div class="flexible attack item"
|
||||
hero-id="main" {{detailHero}}>
|
||||
<div layout horizontal>
|
||||
<div class="headline"
|
||||
style="margin-right: 16px;"
|
||||
layout horizontal center>
|
||||
{{evaluateSigned ../_id attackBonus}}
|
||||
</div>
|
||||
<div flex layout vertical>
|
||||
<div class="body2">
|
||||
{{name}}
|
||||
</div>
|
||||
<div>
|
||||
{{evaluateString ../_id damage}} {{damageType}}
|
||||
</div>
|
||||
{{#if details}}
|
||||
<div class="caption">
|
||||
{{details}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</div>
|
||||
|
||||
<!--Proficiencies-->
|
||||
<div>
|
||||
<paper-shadow class="card">
|
||||
<div class="white top">
|
||||
Proficiencies
|
||||
</div>
|
||||
<div flex class="bottom list">
|
||||
{{#if weaponProfs.count}}
|
||||
<div class="subhead">Weapons</div>
|
||||
{{/if}}
|
||||
{{#each weaponProfs}}
|
||||
{{> proficiencyListItem}}
|
||||
{{/each}}
|
||||
{{#if armorProfs.count}}
|
||||
<div class="subhead">Armor</div>
|
||||
{{/if}}
|
||||
{{#each armorProfs}}
|
||||
{{> proficiencyListItem}}
|
||||
{{/each}}
|
||||
{{#if toolProfs.count}}
|
||||
<div class="subhead">Tools</div>
|
||||
{{/if}}
|
||||
{{#each toolProfs}}
|
||||
{{> proficiencyListItem}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</div>
|
||||
|
||||
<!--features-->
|
||||
{{#each features}}
|
||||
<div>
|
||||
<paper-shadow class="card featureCard"
|
||||
hero-id="main" {{detailHero}}>
|
||||
<div class="top {{colorClass}} subhead"
|
||||
layout horizontal
|
||||
hero-id="toolbar" {{detailHero}}>
|
||||
<div flex hero-id="title" {{detailHero}}>
|
||||
{{name}}
|
||||
</div>
|
||||
{{#if hasUses}}
|
||||
<div style="margin-right: 8px">
|
||||
{{usesLeft}}/{{usesValue}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if canEnable}}
|
||||
<core-tooltip label="Feature enabled"
|
||||
position="left">
|
||||
<paper-checkbox class="enabledCheckbox"
|
||||
checked={{enabled}}
|
||||
disabled={{#unless canEditCharacter charId}}true{{/unless}}>
|
||||
</paper-checkbox>
|
||||
</core-tooltip>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if description}}
|
||||
<div flex class="bottom">
|
||||
{{#markdown}}{{evaluateString charId shortDescription}}{{/markdown}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if hasUses}}
|
||||
<div layout horizontal center end-justified>
|
||||
<paper-button class="useFeature"
|
||||
disabled={{noUsesLeft}}>
|
||||
Use
|
||||
</paper-button>
|
||||
<paper-button class="resetFeature"
|
||||
disabled={{usesFull}}>
|
||||
Reset
|
||||
</paper-button>
|
||||
</div>
|
||||
{{/if}}
|
||||
</paper-shadow>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="fab-buffer"></div>
|
||||
</div>
|
||||
{{#if canEditCharacter _id}}
|
||||
<paper-fab id="addFeature"
|
||||
class="floatyButton"
|
||||
icon="add"
|
||||
title="Add"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
aria-label="Add"
|
||||
hero-id="main"></paper-fab>
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="resource">
|
||||
{{#if characterCalculate "attributeBase" char._id name}}
|
||||
<div>
|
||||
<paper-shadow class="card"
|
||||
hero-id="main" {{detailHero name char._id}}
|
||||
layout horizontal>
|
||||
<div class="left {{getColor}} display1 white-text"
|
||||
hero-id="toolbar" {{detailHero name char._id}}
|
||||
layout horizontal center>
|
||||
<div style="margin-right: 8px;">
|
||||
<paper-icon-button class="resourceUp"
|
||||
icon="arrow-drop-up"
|
||||
disabled={{cantIncrement}}>
|
||||
</paper-icon-button>
|
||||
<paper-icon-button class="resourceDown"
|
||||
icon="arrow-drop-down"
|
||||
disabled={{cantDecrement}}>
|
||||
</paper-icon-button>
|
||||
</div>
|
||||
<div>{{characterCalculate "attributeValue" char._id name}}</div>
|
||||
<!--<div>/{{char.attributeBase name}}</div>-->
|
||||
</div>
|
||||
<div class="right clickable"
|
||||
flex layout horizontal center>
|
||||
{{title}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
149
rpg-docs/client/views/private/character/features/features.js
Normal file
149
rpg-docs/client/views/private/character/features/features.js
Normal file
@@ -0,0 +1,149 @@
|
||||
Template.features.helpers({
|
||||
features: function(){
|
||||
var features = Features.find({charId: this._id}, {sort: {color: 1, name: 1}});
|
||||
return features;
|
||||
},
|
||||
shortDescription: function() {
|
||||
if (_.isString(this.description)){
|
||||
return this.description.split(/^( *[-*_]){3,} *(?:\n+|$)/m)[0];
|
||||
}
|
||||
},
|
||||
hasUses: function(){
|
||||
return this.usesValue() > 0;
|
||||
},
|
||||
noUsesLeft: function(){
|
||||
return this.usesLeft() <= 0 || !canEditCharacter(this.charId);
|
||||
},
|
||||
usesFull: function(){
|
||||
return this.usesLeft() >= this.usesValue() || !canEditCharacter(this.charId);
|
||||
},
|
||||
colorClass: function(){
|
||||
return getColorClass(this.color);
|
||||
},
|
||||
featureOrder: function(){
|
||||
return _.indexOf(_.keys(colorOptions), this.color);
|
||||
},
|
||||
attacks: function(){
|
||||
return Attacks.find(
|
||||
{charId: this._id, enabled: true},
|
||||
{sort: {color: 1, name: 1}});
|
||||
},
|
||||
canEnable: function(){
|
||||
return !this.alwaysEnabled;
|
||||
},
|
||||
weaponProfs: function(){
|
||||
return Proficiencies.find({charId: this._id, type: "weapon"});
|
||||
},
|
||||
armorProfs: function(){
|
||||
return Proficiencies.find({charId: this._id, type: "armor"});
|
||||
},
|
||||
toolProfs: function(){
|
||||
return Proficiencies.find({charId: this._id, type: "tool"});
|
||||
},
|
||||
});
|
||||
|
||||
Template.features.events({
|
||||
"tap #addFeature": function(event){
|
||||
var featureId = Features.insert({
|
||||
name: "New Feature",
|
||||
charId: this._id,
|
||||
enabled: true,
|
||||
alwaysEnabled: true,
|
||||
});
|
||||
GlobalUI.setDetail({
|
||||
template: "featureDialog",
|
||||
data: {featureId: featureId, charId: this._id, startEditing: true},
|
||||
heroId: featureId,
|
||||
});
|
||||
},
|
||||
"tap #addAttackButton": function(event){
|
||||
var charId = this._id;
|
||||
Attacks.insert({
|
||||
charId: charId
|
||||
}, function(error, id){
|
||||
if (!error){
|
||||
GlobalUI.setDetail({
|
||||
template: "attackDialog",
|
||||
data: {attackId: id, charId: charId},
|
||||
heroId: id,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
"tap .featureCard .top": function(event){
|
||||
var featureId = this._id;
|
||||
var charId = Template.parentData()._id;
|
||||
GlobalUI.setDetail({
|
||||
template: "featureDialog",
|
||||
data: {featureId: featureId, charId: charId},
|
||||
heroId: featureId,
|
||||
});
|
||||
},
|
||||
"tap .attack": function(event){
|
||||
openParentDialog(this.parent, this.charId, this._id);
|
||||
},
|
||||
"tap .useFeature": function(event){
|
||||
var featureId = this._id;
|
||||
Features.update(featureId, {$inc: {used: 1}});
|
||||
},
|
||||
"tap .resetFeature": function(event){
|
||||
var featureId = this._id;
|
||||
Features.update(featureId, {$set: {used: 0}});
|
||||
},
|
||||
"tap .enabledCheckbox": function(event){
|
||||
event.stopPropagation();
|
||||
},
|
||||
"change .enabledCheckbox": function(event){
|
||||
var enabled = !this.enabled;
|
||||
Features.update(this._id, {$set: {enabled: enabled}});
|
||||
},
|
||||
});
|
||||
|
||||
Template.resource.helpers({
|
||||
cantIncrement: function(){
|
||||
var value = Characters.calculate.attributeValue(this.char._id, this.name);
|
||||
var base = Characters.calculate.attributeBase(this.char._id, this.name);
|
||||
var baseBigger = value < base;
|
||||
return !baseBigger || !canEditCharacter(this.char._id);
|
||||
},
|
||||
cantDecrement: function(){
|
||||
var value = Characters.calculate.attributeValue(this.char._id, this.name);
|
||||
var valuePositive = value > 0;
|
||||
return !valuePositive || !canEditCharacter(this.char._id);
|
||||
},
|
||||
getColor: function(){
|
||||
var value = Characters.calculate.attributeValue(this.char._id, this.name);
|
||||
if (value > 0){
|
||||
return this.color;
|
||||
} else {
|
||||
return "grey";
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.resource.events({
|
||||
"tap .resourceUp": function(event){
|
||||
var value = Characters.calculate.attributeValue(this.char._id, this.name);
|
||||
var base = Characters.calculate.attributeBase(this.char._id, this.name);
|
||||
if (value < base){
|
||||
var modifier = {$inc: {}};
|
||||
modifier.$inc[this.name + ".adjustment"] = 1;
|
||||
Characters.update(this.char._id, modifier, {validate: false});
|
||||
}
|
||||
},
|
||||
"tap .resourceDown": function(event){
|
||||
var value = Characters.calculate.attributeValue(this.char._id, this.name);
|
||||
if (value > 0){
|
||||
var modifier = {$inc: {}};
|
||||
modifier.$inc[this.name + ".adjustment"] = -1;
|
||||
Characters.update(this.char._id, modifier, {validate: false});
|
||||
}
|
||||
},
|
||||
"tap .right": function(event, instance) {
|
||||
GlobalUI.setDetail({
|
||||
template: "attributeDialog",
|
||||
data: {name: this.title, statName: this.name, charId: this.char._id},
|
||||
heroId: this.char._id + this.name,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
<template name="carryCapacityBar">
|
||||
<div class="carryCapacityBar">
|
||||
<div class="carriedWeightBar"
|
||||
style="width: {{carriedPercent}}%;
|
||||
background-color: {{carriedColor}}">
|
||||
</div>
|
||||
<div class="tick"
|
||||
style="width: 33.333%;">
|
||||
</div>
|
||||
<div class="tick"
|
||||
style="width: 66.666%;">
|
||||
</div>
|
||||
</div>
|
||||
{{#if overCarriedPercent}}
|
||||
<div class="carryCapacityBar">
|
||||
<div class="carriedWeightBar"
|
||||
style="width: {{overCarriedPercent}}%;
|
||||
background-color: {{overCarriedColor}}">
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
@@ -0,0 +1,67 @@
|
||||
var getFractionCarried = function(char) {
|
||||
//find out the weight
|
||||
var weight = 0;
|
||||
Containers.find(
|
||||
{charId: char._id, isCarried: true}
|
||||
).forEach(function(container){
|
||||
weight += container.totalWeight();
|
||||
});
|
||||
Items.find(
|
||||
{charId: char._id, "parent.id": char._id},
|
||||
{fields: {weight : 1, quantity: 1}}
|
||||
).forEach(function(item){
|
||||
weight += item.totalWeight();
|
||||
});
|
||||
//get strength
|
||||
var strength = Characters.calculate.attributeValue(char._id, "strength");
|
||||
var carryMultiplier = Characters.calculate
|
||||
.attributeValue(char._id, "carryMultiplier");
|
||||
var capacity = strength * 15 * carryMultiplier;
|
||||
return weight / capacity;
|
||||
};
|
||||
|
||||
Template.carryCapacityBar.onCreated(function() {
|
||||
var self = this;
|
||||
self.carriedFraction = new ReactiveVar(0);
|
||||
self.autorun(function() {
|
||||
self.carriedFraction.set(getFractionCarried(Template.currentData()));
|
||||
});
|
||||
});
|
||||
|
||||
Template.carryCapacityBar.helpers({
|
||||
carriedPercent: function() {
|
||||
var percent = 100 * Template.instance().carriedFraction.get();
|
||||
return percent > 100 ? 100 : percent;
|
||||
},
|
||||
overCarriedPercent: function() {
|
||||
var percent = 100 * Template.instance().carriedFraction.get();
|
||||
var overPercent = percent - 100;
|
||||
if (overPercent < 0) return 0;
|
||||
if (overPercent > 100) return 100;
|
||||
return overPercent;
|
||||
},
|
||||
carriedColor: function() {
|
||||
var frac = Template.instance().carriedFraction.get();
|
||||
if (frac < 1 / 3){
|
||||
return "#2196F3";
|
||||
} else if (frac < 2 / 3){
|
||||
return "#CDDC39";
|
||||
} else if (frac < 1) {
|
||||
return "#FFC107";
|
||||
} else {
|
||||
return "#F44336";
|
||||
}
|
||||
},
|
||||
overCarriedColor: function() {
|
||||
var frac = Template.instance().carriedFraction.get();
|
||||
if (frac < 1 / 3){
|
||||
return "#2196F3";
|
||||
} else if (frac < 2 / 3){
|
||||
return "#CDDC39";
|
||||
} else if (frac < 1) {
|
||||
return "#FFC107";
|
||||
} else {
|
||||
return "#F44336";
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
.carryCapacityBar {
|
||||
background-color: #7DC580;
|
||||
background-color: rgba(255,255,255,0.27);
|
||||
position: relative;
|
||||
height: 4px;
|
||||
div{
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
.tick {
|
||||
border-right: solid 2px #E5E5E5;
|
||||
border-right-color: rgba(255,255,255,0.54);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<template name="carryDialog">
|
||||
{{#baseDialog title="Weight Carried" class=color hideEdit=true}}
|
||||
<div layout horizontal center-justified end>
|
||||
<div class="display2">
|
||||
{{round carriedWeight 1}}
|
||||
</div>
|
||||
<div class="display1">
|
||||
lbs
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="vertMargin">
|
||||
|
||||
{{> carryCapacityTable}}
|
||||
|
||||
{{/baseDialog}}
|
||||
</template>
|
||||
@@ -0,0 +1,20 @@
|
||||
Template.carryDialog.helpers({
|
||||
carriedWeight: function() {
|
||||
var weight = 0;
|
||||
Containers.find(
|
||||
{charId: this.charId, isCarried: true}
|
||||
).forEach(function(container){
|
||||
weight += container.totalWeight();
|
||||
});
|
||||
Items.find(
|
||||
{charId: this.charId, "parent.id": this.charId},
|
||||
{fields: {weight : 1, quantity: 1}}
|
||||
).forEach(function(item){
|
||||
weight += item.totalWeight();
|
||||
});
|
||||
return weight;
|
||||
},
|
||||
color: function() {
|
||||
if (this.color) return this.color + " white-text";
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
<template name="containerDialog">
|
||||
{{#with container}}
|
||||
{{#baseDialog title=name class=colorClass startEditing=../startEditing}}
|
||||
{{> containerView}}
|
||||
{{else}}
|
||||
{{> containerEdit}}
|
||||
{{/baseDialog}}
|
||||
{{/with}}
|
||||
</template>
|
||||
|
||||
<template name="containerEdit">
|
||||
<paper-input id="containerNameInput"
|
||||
label="Name"
|
||||
floatinglabel
|
||||
value={{name}}></paper-input>
|
||||
<div layout horizontal around-justified wrap>
|
||||
<paper-input-decorator label="Weight" floatinglabel>
|
||||
<input id="weightInput" type="number" value={{weight}}>
|
||||
</paper-input-decorator>
|
||||
<paper-input-decorator label="Value" floatinglabel>
|
||||
<input id="valueInput" type="number" value={{value}}>
|
||||
</paper-input-decorator>
|
||||
</div>
|
||||
|
||||
<hr class="vertMargin">
|
||||
|
||||
<paper-input-decorator label="Description" floatinglabel layout vertical>
|
||||
<paper-autogrow-textarea>
|
||||
<textarea id="containerDescriptionInput" placeholder aria-label="Description" value={{description}}></textarea>
|
||||
</paper-autogrow-textarea>
|
||||
</paper-input-decorator>
|
||||
</template>
|
||||
|
||||
<template name="containerView">
|
||||
<div layout horizontal wrap center justified>
|
||||
<table class="summaryTable fullwidth">
|
||||
<tr><td>Container</td><td>{{round weight}}lbs</td><td>{{longValueString value}}</td></tr>
|
||||
<tr><td>Contents</td><td>{{round contentsWeight}}lbs</td><td>{{longValueString contentsValue}}</td></tr>
|
||||
<tr class="body2"><td>Total</td><td>{{round totalWeight}}lbs</td><td>{{longValueString totalValue}}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
{{#if description}}
|
||||
<hr class="vertMargin">
|
||||
<div>{{#markdown}}{{evaluateString charId description}}{{/markdown}}</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
@@ -0,0 +1,43 @@
|
||||
Template.containerDialog.helpers({
|
||||
container: function(){
|
||||
return Containers.findOne(this.containerId);
|
||||
}
|
||||
});
|
||||
|
||||
Template.containerDialog.events({
|
||||
"color-change": function(event, instance){
|
||||
Containers.update(instance.data.containerId, {$set: {color: event.color}});
|
||||
},
|
||||
"tap #deleteButton": function(event, instance){
|
||||
Containers.softRemoveNode(instance.data.containerId);
|
||||
GlobalUI.deletedToast(
|
||||
instance.data.containerId,
|
||||
"Containers", "Container and contents"
|
||||
);
|
||||
GlobalUI.closeDetail();
|
||||
},
|
||||
});
|
||||
|
||||
Template.containerEdit.onRendered(function(){
|
||||
updatePolymerInputs(this);
|
||||
});
|
||||
|
||||
Template.containerEdit.events({
|
||||
//TODO validate input (integer, non-negative, etc) for these inputs and give validation errors
|
||||
"change #containerNameInput": function(event){
|
||||
var name = Template.instance().find("#containerNameInput").value;
|
||||
Containers.update(this._id, {$set: {name: name}});
|
||||
},
|
||||
"change #weightInput, input #weightInput": function(event){
|
||||
var weight = +Template.instance().find("#weightInput").value;
|
||||
Containers.update(this._id, {$set: {weight: weight}});
|
||||
},
|
||||
"change #valueInput, input #valueInput": function(event){
|
||||
var value = +Template.instance().find("#valueInput").value;
|
||||
Containers.update(this._id, {$set: {value: value}});
|
||||
},
|
||||
"change #containerDescriptionInput": function(event, instance){
|
||||
var description = instance.find("#containerDescriptionInput").value;
|
||||
Containers.update(this._id, {$set: {description: description}});
|
||||
},
|
||||
});
|
||||
182
rpg-docs/client/views/private/character/inventory/inventory.html
Normal file
182
rpg-docs/client/views/private/character/inventory/inventory.html
Normal file
@@ -0,0 +1,182 @@
|
||||
<template name="inventory">
|
||||
<div fit>
|
||||
<div id="inventory" class="scroll-y" fit>
|
||||
<div class="column-container">
|
||||
<!--Net Worth-->
|
||||
<div>
|
||||
<paper-shadow class="card">
|
||||
<div class="white top" layout horizontal center>
|
||||
<div class="subhead" flex>
|
||||
Net Worth
|
||||
</div>
|
||||
<div>
|
||||
{{valueString netWorth}}
|
||||
</div>
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</div>
|
||||
<!--Weight Carried-->
|
||||
<div>
|
||||
<paper-shadow class="card"
|
||||
hero-id="main" {{detailHero "weightCarried" _id}}>
|
||||
<div class="top green white-text weightCarried"
|
||||
hero-id="toolbar" {{detailHero "weightCarried" _id}}
|
||||
layout horizontal center>
|
||||
<div class="subhead" flex>
|
||||
Weight Carried
|
||||
</div>
|
||||
<div>
|
||||
{{round weightCarried}}lbs
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom green" style="padding: 0;">
|
||||
{{> carryCapacityBar}}
|
||||
</div>
|
||||
{{#if encumberedBuffs.count}}
|
||||
<div class="bottom list">
|
||||
{{#each encumberedBuffs}}
|
||||
<div class="item-slot">
|
||||
<div class="item buff"
|
||||
hero-id="main" {{detailHero}}
|
||||
layout horizontal center>
|
||||
<div flex>
|
||||
<core-icon icon="work"
|
||||
style="margin-right: 16px">
|
||||
</core-icon>
|
||||
{{name}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</paper-shadow>
|
||||
</div>
|
||||
<!--Equipment-->
|
||||
<div>
|
||||
<paper-shadow class="card equipmentContainer">
|
||||
<div class="white top" layout horizontal center>
|
||||
<div class="subhead" flex>
|
||||
Equipment
|
||||
</div>
|
||||
<div class="caption" style="margin-right: 8px">
|
||||
{{valueString equipmentValue}}
|
||||
</div>
|
||||
<div class="caption">
|
||||
{{round equipmentWeight}}lbs
|
||||
</div>
|
||||
</div>
|
||||
<div flex class="bottom list">
|
||||
{{#if attuned.count}}
|
||||
<div class="subhead">Attuned</div>
|
||||
{{/if}}
|
||||
{{#each attuned}}
|
||||
{{>inventoryItem}}
|
||||
{{/each}}
|
||||
{{#if attuned.count}}
|
||||
<div class="subhead">Equipment</div>
|
||||
{{/if}}
|
||||
{{#each equipment}}
|
||||
{{>inventoryItem}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</div>
|
||||
<!--Carried Items-->
|
||||
<div>
|
||||
<paper-shadow class="card carriedContainer">
|
||||
<div class="white top" layout horizontal center>
|
||||
<div class="subhead" flex>
|
||||
Carried
|
||||
</div>
|
||||
<div class="caption" style="margin-right: 8px">
|
||||
{{valueString carriedValue}}
|
||||
</div>
|
||||
<div class="caption">
|
||||
{{round carriedWeight}}lbs
|
||||
</div>
|
||||
</div>
|
||||
<div flex class="bottom list">
|
||||
{{#each carriedItems}}
|
||||
{{>inventoryItem}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</div>
|
||||
{{#each containers}}
|
||||
<div>
|
||||
<paper-shadow class="card itemContainer"
|
||||
hero-id="main" {{detailHero}}>
|
||||
<div class="top {{colorClass}}"
|
||||
hero-id="toolbar" {{detailHero}}
|
||||
layout horizontal center>
|
||||
<div class="subhead" flex
|
||||
hero-id="title" {{detailHero}}>
|
||||
{{name}}
|
||||
</div>
|
||||
<div class="caption" style="margin-right: 8px">
|
||||
{{valueString totalValue}}
|
||||
</div>
|
||||
<div class="caption" style="margin-right: 8px">
|
||||
{{round totalWeight}}lbs
|
||||
</div>
|
||||
<core-tooltip label="Container carried" position="left">
|
||||
<paper-checkbox class="carriedCheckbox"
|
||||
disabled={{#unless canEditCharacter charId}}true{{/unless}}
|
||||
checked={{isCarried}}>
|
||||
</paper-checkbox>
|
||||
</core-tooltip>
|
||||
</div>
|
||||
<div class="bottom list">
|
||||
{{#each items ../_id _id}}
|
||||
{{>inventoryItem}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="fab-buffer"></div>
|
||||
</div>
|
||||
{{#if canEditCharacter _id}}
|
||||
{{#fabMenu}}
|
||||
<core-tooltip label="New container" position="left">
|
||||
<paper-fab icon="work"
|
||||
class="addContainer"
|
||||
mini>
|
||||
</paper-fab>
|
||||
</core-tooltip>
|
||||
<core-tooltip label="New item" position="left">
|
||||
<paper-fab icon="note-add"
|
||||
class="addItem"
|
||||
mini>
|
||||
</paper-fab>
|
||||
</core-tooltip>
|
||||
{{/fabMenu}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="inventoryItem">
|
||||
<div class="item-slot">
|
||||
<div class="item {{hidden}} inventoryItem"
|
||||
hero-id="main" {{detailHero}}
|
||||
layout horizontal center
|
||||
draggable={{canEditCharacter charId}}>
|
||||
<div flex class="itemName">
|
||||
{{#if ne1 quantity}}{{quantity}} {{/if}}{{pluralName}}
|
||||
</div>
|
||||
{{#if settings.showIncrement}}{{#if canEditCharacter charId}}
|
||||
<div class="incrementButtons">
|
||||
<paper-icon-button class="addItemQuantity"
|
||||
icon="add"
|
||||
style="margin-right: -8px"></paper-icon-button>
|
||||
<paper-icon-button class="subItemQuantity"
|
||||
disabled={{lt1 quantity}}
|
||||
icon="remove"
|
||||
style="margin-right: -8px"></paper-icon-button>
|
||||
</div>
|
||||
{{/if}}{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
329
rpg-docs/client/views/private/character/inventory/inventory.js
Normal file
329
rpg-docs/client/views/private/character/inventory/inventory.js
Normal file
@@ -0,0 +1,329 @@
|
||||
Template.inventory.created = function(){
|
||||
this.showAddButtons = new ReactiveVar(false);
|
||||
};
|
||||
|
||||
Template.inventory.helpers({
|
||||
containers: function(){
|
||||
return Containers.find({charId: this._id}, {sort: {color: 1, name: 1}});
|
||||
},
|
||||
items: function(charId, containerId){
|
||||
return Items.find(
|
||||
{charId: charId, "parent.id": containerId},
|
||||
{sort: {color: 1, name: 1}}
|
||||
);
|
||||
},
|
||||
attuned: function(){
|
||||
return Items.find(
|
||||
{charId: this._id, enabled: true, requiresAttunement: true},
|
||||
{sort: {color: 1, name: 1}}
|
||||
);
|
||||
},
|
||||
equipment: function(){
|
||||
return Items.find(
|
||||
{charId: this._id, enabled: true, requiresAttunement: false},
|
||||
{sort: {color: 1, name: 1}}
|
||||
);
|
||||
},
|
||||
carriedItems: function(){
|
||||
return Items.find(
|
||||
{charId: this._id, enabled: false, "parent.id": this._id},
|
||||
{sort: {color: 1, name: 1}}
|
||||
);
|
||||
},
|
||||
showAddButtons: function(){
|
||||
return Template.instance().showAddButtons.get();
|
||||
},
|
||||
colorClass: function(){
|
||||
return getColorClass(this.color);
|
||||
},
|
||||
netWorth: function(){
|
||||
var worth = 0;
|
||||
Items.find(
|
||||
{charId: this._id},
|
||||
{fields: {value : 1, quantity: 1}}
|
||||
).forEach(function(item){
|
||||
worth += item.totalValue();
|
||||
});
|
||||
Containers.find(
|
||||
{charId: this._id},
|
||||
{fields: {value : 1}}
|
||||
).forEach(function(container) {
|
||||
if (container.value) worth += container.value;
|
||||
});
|
||||
return worth;
|
||||
},
|
||||
weightCarried: function(){
|
||||
var weight = 0;
|
||||
Containers.find(
|
||||
{charId: this._id, isCarried: true}
|
||||
).forEach(function(container){
|
||||
weight += container.totalWeight();
|
||||
});
|
||||
Items.find(
|
||||
{charId: this._id, "parent.id": this._id},
|
||||
{fields: {weight : 1, quantity: 1}}
|
||||
).forEach(function(item){
|
||||
weight += item.totalWeight();
|
||||
});
|
||||
return weight;
|
||||
},
|
||||
encumberedBuffs: function(){
|
||||
return Buffs.find({
|
||||
charId: this._id,
|
||||
type: "inate",
|
||||
name: {$in: [
|
||||
"Encumbered",
|
||||
"Heavily encumbered",
|
||||
"Over encumbered",
|
||||
"Can't move load",
|
||||
]},
|
||||
});
|
||||
},
|
||||
equipmentValue: function(){
|
||||
var value = 0;
|
||||
Items.find(
|
||||
{charId: this._id, enabled: true},
|
||||
{fields: {value : 1, quantity: 1}}
|
||||
).forEach(function(item){
|
||||
value += item.totalValue();
|
||||
});
|
||||
return value;
|
||||
},
|
||||
equipmentWeight: function(){
|
||||
var weight = 0;
|
||||
Items.find({charId: this._id, enabled: true},
|
||||
{fields: {weight : 1, quantity: 1}}
|
||||
).forEach(function(item){
|
||||
weight += item.totalWeight();
|
||||
});
|
||||
return weight;
|
||||
},
|
||||
carriedValue: function(){
|
||||
var value = 0;
|
||||
Items.find(
|
||||
{charId: this._id, enabled: false, "parent.id": this._id},
|
||||
{fields: {value : 1, quantity: 1}}
|
||||
).forEach(function(item){
|
||||
value += item.totalValue();
|
||||
});
|
||||
return value;
|
||||
},
|
||||
carriedWeight: function(){
|
||||
var weight = 0;
|
||||
Items.find(
|
||||
{charId: this._id, enabled: false, "parent.id": this._id},
|
||||
{fields: {weight : 1, quantity: 1}}
|
||||
).forEach(function(item){
|
||||
weight += item.totalWeight();
|
||||
});
|
||||
return weight;
|
||||
},
|
||||
});
|
||||
|
||||
Template.inventory.events({
|
||||
"tap .addItem": function(event){
|
||||
var charId = this._id;
|
||||
Items.insert({
|
||||
charId: charId,
|
||||
parent:{
|
||||
id: charId,
|
||||
collection: "Characters",
|
||||
},
|
||||
}, function(err, itemId){
|
||||
if (err) throw err;
|
||||
GlobalUI.setDetail({
|
||||
template: "itemDialog",
|
||||
data: {itemId: itemId, charId: charId, startEditing: true},
|
||||
heroId: itemId,
|
||||
});
|
||||
});
|
||||
},
|
||||
"tap .addContainer": function(event){
|
||||
var containerId = Containers.insert({
|
||||
name: "New Container",
|
||||
isCarried: true,
|
||||
charId: this._id,
|
||||
});
|
||||
GlobalUI.setDetail({
|
||||
template: "containerDialog",
|
||||
data: {
|
||||
containerId: containerId,
|
||||
charId: this.charId,
|
||||
startEditing: true,
|
||||
},
|
||||
heroId: containerId,
|
||||
});
|
||||
},
|
||||
"tap .weightCarried": function(event) {
|
||||
var charId = this._id;
|
||||
GlobalUI.setDetail({
|
||||
template: "carryDialog",
|
||||
data: {charId: charId, color: "green"},
|
||||
heroId: charId + "weightCarried",
|
||||
});
|
||||
},
|
||||
"tap .buff": function(event){
|
||||
var buffId = this._id;
|
||||
var charId = Template.parentData()._id;
|
||||
GlobalUI.setDetail({
|
||||
template: "buffDialog",
|
||||
data: {buffId: buffId, charId: charId},
|
||||
heroId: buffId,
|
||||
});
|
||||
},
|
||||
"tap .inventoryItem": function(event){
|
||||
var itemId = this._id;
|
||||
var charId = Template.parentData()._id;
|
||||
GlobalUI.setDetail({
|
||||
template: "itemDialog",
|
||||
data: {itemId: itemId, charId: charId},
|
||||
heroId: itemId,
|
||||
});
|
||||
},
|
||||
"hold .inventoryItem": function(event, instance) {
|
||||
var itemId = this._id;
|
||||
var charId = Template.parentData()._id;
|
||||
var containerId = this.parent.id;
|
||||
GlobalUI.showDialog({
|
||||
template: "moveItemDialog",
|
||||
data: {
|
||||
charId: charId,
|
||||
itemId: itemId,
|
||||
containerId: containerId,
|
||||
},
|
||||
heading: "Move " + this.pluralName(),
|
||||
});
|
||||
},
|
||||
"tap .incrementButtons": function(event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
"tap .addItemQuantity": function(event) {
|
||||
var itemId = this._id;
|
||||
Items.update(itemId, {$set: {quantity: this.quantity + 1}});
|
||||
},
|
||||
"tap .subItemQuantity": function(event) {
|
||||
var itemId = this._id;
|
||||
Items.update(itemId, {$set: {quantity: this.quantity - 1}});
|
||||
},
|
||||
"tap .itemContainer .top": function(event){
|
||||
GlobalUI.setDetail({
|
||||
template: "containerDialog",
|
||||
data: {containerId: this._id, charId: this.charId},
|
||||
heroId: this._id,
|
||||
});
|
||||
},
|
||||
"tap .carriedCheckbox": function(event){
|
||||
event.stopPropagation();
|
||||
},
|
||||
"change .carriedCheckbox": function(event){
|
||||
var carried;
|
||||
if (this.isCarried) carried = false;
|
||||
else carried = true;
|
||||
Containers.update(this._id, {$set: {isCarried: carried}});
|
||||
},
|
||||
});
|
||||
|
||||
Template.inventoryItem.helpers({
|
||||
ne1: function(num){
|
||||
return num !== 1;
|
||||
},
|
||||
lt1: function(num) {
|
||||
return num < 1;
|
||||
},
|
||||
hidden: function(){
|
||||
return Session.equals("inventory.dragItemId", this._id) ? "hidden" : null;
|
||||
},
|
||||
});
|
||||
|
||||
Template.layout.events({
|
||||
"dragstart .inventoryItem": function(event, instance){
|
||||
event.originalEvent.dataTransfer.setData("dicecloud-id/items", this._id);
|
||||
Session.set("inventory.dragItemId", this._id);
|
||||
},
|
||||
"dragover .itemContainer, dragenter .itemContainer":
|
||||
function(event, instance){
|
||||
if (_.contains(event.originalEvent.dataTransfer.types, "dicecloud-id/items")){
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
"dragover .equipmentContainer, dragenter .equipmentContainer":
|
||||
function(event, instance){
|
||||
if (_.contains(event.originalEvent.dataTransfer.types, "dicecloud-id/items")){
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
"dragover .carriedContainer, dragenter .carriedContainer":
|
||||
function(event, instance){
|
||||
if (_.contains(event.originalEvent.dataTransfer.types, "dicecloud-id/items")){
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
"dragover .characterRepresentative, dragenter .characterRepresentative":
|
||||
function(event, instance){
|
||||
if (_.contains(event.originalEvent.dataTransfer.types, "dicecloud-id/items")){
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
"dragend .inventoryItem": function(event, instance){
|
||||
Session.set("inventory.dragItemId", null);
|
||||
},
|
||||
"drop .itemContainer": function(event, instance){
|
||||
var itemId = event.originalEvent.dataTransfer.getData("dicecloud-id/items");
|
||||
if (event.ctrlKey){
|
||||
//split the stack to the container
|
||||
GlobalUI.showDialog({
|
||||
template: "splitStackDialog",
|
||||
data: {
|
||||
id: itemId,
|
||||
parentCollection: "Containers",
|
||||
parentId: this._id,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
//move item to the container
|
||||
Meteor.call("moveItemToContainer", itemId, this._id);
|
||||
}
|
||||
Session.set("inventory.dragItemId", null);
|
||||
},
|
||||
"drop .equipmentContainer": function(event, instance){
|
||||
var itemId = event.originalEvent.dataTransfer.getData("dicecloud-id/items");
|
||||
Meteor.call("equipItem", itemId, this._id);
|
||||
Session.set("inventory.dragItemId", null);
|
||||
},
|
||||
"drop .carriedContainer": function(event, instance){
|
||||
var itemId = event.originalEvent.dataTransfer.getData("dicecloud-id/items");
|
||||
if (event.ctrlKey){
|
||||
//split the stack to the container
|
||||
GlobalUI.showDialog({
|
||||
template: "splitStackDialog",
|
||||
data: {
|
||||
id: itemId,
|
||||
parentCollection: "Characters",
|
||||
parentId: this._id,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
//move item to the character
|
||||
Meteor.call("moveItemToCharacter", itemId, this._id);
|
||||
}
|
||||
Session.set("inventory.dragItemId", null);
|
||||
},
|
||||
"drop .characterRepresentative": function(event, instance) {
|
||||
var itemId = event.originalEvent.dataTransfer.getData("dicecloud-id/items");
|
||||
if (event.ctrlKey){
|
||||
//split the stack to the container
|
||||
GlobalUI.showDialog({
|
||||
template: "splitStackDialog",
|
||||
data: {
|
||||
id: itemId,
|
||||
parentCollection: "Characters",
|
||||
parentId: this._id,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
//move item to the character
|
||||
Meteor.call("moveItemToCharacter", itemId, this._id);
|
||||
}
|
||||
Session.set("inventory.dragItemId", null);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
body /deep/ .itemDialogWidth {
|
||||
width: 560px;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<template name="itemDialog">
|
||||
{{#with item}}
|
||||
{{#baseDialog title=itemHeading class=colorClass startEditing=../startEditing}}
|
||||
{{> itemDetails}}
|
||||
{{else}}
|
||||
{{> itemEdit}}
|
||||
{{/baseDialog}}
|
||||
{{/with}}
|
||||
</template>
|
||||
|
||||
<template name="itemDetails">
|
||||
<div layout horizontal wrap center justified class="headline">
|
||||
{{#if weight}}<div class="sideMargin">{{round totalWeight}}lbs</div>{{/if}}
|
||||
{{#if value}}<div>{{valueString totalValue}}</div>{{/if}}
|
||||
</div>
|
||||
<div layout horizontal wrap class="caption">
|
||||
{{#if enabled}}<div class="vertMargin" style="margin-right: 16px">Equipped</div>{{/if}}
|
||||
{{#if requiresAttunement}}<div class="vertMargin">Requires Attunement</div>{{/if}}
|
||||
</div>
|
||||
{{#if description}}
|
||||
<hr style="margin: 16px 0 16px 0;">
|
||||
<div>{{#markdown}}{{evaluateString charId description}}{{/markdown}}</div>
|
||||
{{/if}}
|
||||
{{> effectsViewList charId=charId parentId=_id}}
|
||||
{{> attacksViewList charId=charId parentId=_id}}
|
||||
</template>
|
||||
|
||||
<template name="itemEdit">
|
||||
<paper-input class="fullwidth" id="itemNameInput" label="Name" floatinglabel value={{name}}></paper-input>
|
||||
<div layout horizontal wrap>
|
||||
<paper-input-decorator label="Quantity"
|
||||
floatinglabel
|
||||
style="width: 80px">
|
||||
<input id="quantityInput"
|
||||
type="number"
|
||||
value={{quantity}}>
|
||||
</paper-input-decorator>
|
||||
{{# if ne1 quantity}}
|
||||
<paper-input flex id="itemPluralInput"
|
||||
label="Plural Name"
|
||||
floatinglabel
|
||||
value={{plural}}></paper-input>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div center horizontal layout>
|
||||
<div class="padded">Show increment buttons</div>
|
||||
<paper-checkbox id="incrementCheckbox"
|
||||
checked={{settings.showIncrement}}>
|
||||
</paper-checkbox>
|
||||
</div>
|
||||
|
||||
<hr class="vertMargin">
|
||||
|
||||
<div layout horizontal wrap justified>
|
||||
<div center horizontal layout>
|
||||
<div class="padded">Container</div>
|
||||
{{> containerDropdown}}
|
||||
</div>
|
||||
<div center horizontal layout>
|
||||
<div class="padded">Equipped</div>
|
||||
<paper-toggle-button id="equippedInput"
|
||||
checked={{enabled}}
|
||||
role="button"
|
||||
aria-pressed="false"
|
||||
tabindex="0"
|
||||
touch-action="pan-y">
|
||||
</paper-toggle-button>
|
||||
</div>
|
||||
<div center horizontal layout>
|
||||
<div class="padded">Requires Attunement</div>
|
||||
<paper-checkbox id="attunementCheckbox"
|
||||
checked={{requiresAttunement}}>
|
||||
</paper-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="vertMargin">
|
||||
|
||||
<div layout horizontal around-justified>
|
||||
<paper-input-decorator label="Weight Each (lbs)" floatinglabel>
|
||||
<input id="weightInput" type="number" value={{weight}}>
|
||||
</paper-input-decorator>
|
||||
<!--Value-->
|
||||
<paper-input-decorator label="Value Each (GP)" floatinglabel>
|
||||
<input id="valueInput" type="number" value={{value}}>
|
||||
</paper-input-decorator>
|
||||
</div>
|
||||
|
||||
<hr class="vertMargin">
|
||||
|
||||
<!--Description-->
|
||||
<paper-input-decorator label="Description" floatinglabel layout vertical>
|
||||
<paper-autogrow-textarea>
|
||||
<textarea id="itemDescriptionInput" placeholder aria-label="Description" value={{description}}></textarea>
|
||||
</paper-autogrow-textarea>
|
||||
</paper-input-decorator>
|
||||
<!--Effects-->
|
||||
{{> effectsEditList parentId=_id parentCollection="Items" charId=charId enabled=equipped name=name}}
|
||||
<!--Attacks-->
|
||||
{{> attackEditList parentId=_id parentCollection="Items" charId=charId enabled=equipped name=name}}
|
||||
</template>
|
||||
|
||||
<template name="containerDropdown">
|
||||
<paper-dropdown-menu id="containerDropDown" label="Container">
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu" selected={{parent.id}}>
|
||||
{{#each containers}}
|
||||
<paper-item name={{_id}} class="containerMenuItem">{{name}}</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
</template>
|
||||
@@ -0,0 +1,113 @@
|
||||
var getContainers = function(charId){
|
||||
return Containers.find(
|
||||
{charId: charId},
|
||||
{sort: {name: 1, _id: 1}, fields: {name: 1}}
|
||||
);
|
||||
};
|
||||
|
||||
Template.itemDialog.onCreated(function(){
|
||||
this.editing = new ReactiveVar(!!this.data.startEditing);
|
||||
});
|
||||
|
||||
Template.itemDialog.helpers({
|
||||
item: function(){
|
||||
return Items.findOne(this.itemId);
|
||||
},
|
||||
editing: function(){
|
||||
return Template.instance().editing.get();
|
||||
},
|
||||
itemHeading: function(){
|
||||
if (this.quantity === 1){
|
||||
return this.name;
|
||||
} else {
|
||||
var pName = this.plural || this.name;
|
||||
return this.quantity + " " + pName;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.itemDialog.events({
|
||||
"tap #editButton": function(event, instance){
|
||||
instance.editing.set(true);
|
||||
},
|
||||
"tap #doneEditingButton": function(event, instance){
|
||||
instance.editing.set(false);
|
||||
},
|
||||
"color-change": function(event, instance){
|
||||
Items.update(instance.data.itemId, {$set: {color: event.color}});
|
||||
},
|
||||
"tap #deleteButton": function(event, instance){
|
||||
Items.softRemoveNode(instance.data.itemId);
|
||||
GlobalUI.deletedToast(instance.data.itemId, "Items", "Item");
|
||||
GlobalUI.closeDetail();
|
||||
},
|
||||
});
|
||||
|
||||
Template.itemEdit.onRendered(function(){
|
||||
updatePolymerInputs(this);
|
||||
});
|
||||
|
||||
Template.itemEdit.helpers({
|
||||
ne1: function(num){
|
||||
return num != 1;
|
||||
},
|
||||
});
|
||||
|
||||
Template.itemEdit.events({
|
||||
//TODO validate input (integer, non-negative, etc) for these inputs and give validation errors
|
||||
"change #itemNameInput": function(event){
|
||||
var name = Template.instance().find("#itemNameInput").value;
|
||||
Items.update(this._id, {$set: {name: name}});
|
||||
},
|
||||
"change #itemPluralInput": function(event){
|
||||
var plural = Template.instance().find("#itemPluralInput").value;
|
||||
Items.update(this._id, {$set: {plural: plural}});
|
||||
},
|
||||
"change #quantityInput": function(event){
|
||||
var quantity = +Template.instance().find("#quantityInput").value;
|
||||
Items.update(this._id, {$set: {quantity: quantity}});
|
||||
},
|
||||
"change #weightInput": function(event){
|
||||
var weight = +Template.instance().find("#weightInput").value;
|
||||
Items.update(this._id, {$set: {weight: weight}});
|
||||
},
|
||||
"change #valueInput": function(event){
|
||||
var value = +Template.instance().find("#valueInput").value;
|
||||
Items.update(this._id, {$set: {value: value}});
|
||||
},
|
||||
"change #itemDescriptionInput": function(event){
|
||||
var description = Template.instance().find("#itemDescriptionInput").value;
|
||||
Items.update(this._id, {$set: {description: description}});
|
||||
},
|
||||
"change #equippedInput": function(event){
|
||||
var equipped = Template.instance().find("#equippedInput").checked;
|
||||
if (equipped){
|
||||
Meteor.call("equipItem", this._id, this.charId);
|
||||
} else {
|
||||
Meteor.call("unequipItem", this._id, this.charId);
|
||||
}
|
||||
},
|
||||
"change #incrementCheckbox": function(event){
|
||||
var value = event.currentTarget.checked;
|
||||
Items.update(this._id, {$set: {"settings.showIncrement": value}});
|
||||
},
|
||||
"change #attunementCheckbox": function(event){
|
||||
var value = event.currentTarget.checked;
|
||||
Items.update(this._id, {$set: {requiresAttunement: value}});
|
||||
},
|
||||
});
|
||||
|
||||
Template.containerDropdown.helpers({
|
||||
containers: function(){
|
||||
return getContainers(this.charId);
|
||||
}
|
||||
});
|
||||
|
||||
Template.containerDropdown.events({
|
||||
"core-select #containerDropDown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var containerId = detail.item.getAttribute("name");
|
||||
Meteor.call("moveItemToContainer", Template.currentData()._id, containerId);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
html /deep/ .moveItemDialog paper-tabs::shadow #selectionBar {
|
||||
background-color: #D50000;
|
||||
}
|
||||
|
||||
html /deep/ .moveItemDialog paper-tab::shadow #ink {
|
||||
color: #D50000;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<template name="moveItemDialog">
|
||||
<div class="moveItemDialog">
|
||||
<paper-tabs selected="{{selectedTab}}">
|
||||
<paper-tab name="containers"
|
||||
class="clickable">
|
||||
Containers
|
||||
</paper-tab>
|
||||
<paper-tab name="characters"
|
||||
class="clickable">
|
||||
Characters
|
||||
</paper-tab>
|
||||
</paper-tabs>
|
||||
<core-animated-pages selected="{{selectedTab}}"
|
||||
transitions="slide-from-right"
|
||||
style="width: 250px;
|
||||
height: 200px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;">
|
||||
<section name="containers">
|
||||
<core-menu id="containerMenu" style="margin: 0;">
|
||||
{{#each containers}}
|
||||
<paper-item name={{_id}}
|
||||
layout horizontal center>
|
||||
<core-icon icon="image:brightness-1"
|
||||
style="color: {{hexColor color}};
|
||||
margin-right: 16px;">
|
||||
</core-icon>
|
||||
<div>{{name}}</div>
|
||||
</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</section>
|
||||
<section name="characters">
|
||||
<core-menu id="characterMenu" style="margin: 0;">
|
||||
{{#each characters}}
|
||||
<paper-item name={{_id}}
|
||||
layout horizontal center>
|
||||
<div class="item small">
|
||||
{{name}}
|
||||
</div>
|
||||
</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</section>
|
||||
</core-animated-pages>
|
||||
</div>
|
||||
<paper-button id="cancelButton" affirmative> Cancel </paper-button>
|
||||
<paper-button id="moveButton" affirmative> Move </paper-button>
|
||||
</template>
|
||||
@@ -0,0 +1,56 @@
|
||||
Template.moveItemDialog.onCreated(function() {
|
||||
Session.setDefault("moveItemDialogTab", "containers");
|
||||
});
|
||||
|
||||
Template.moveItemDialog.helpers({
|
||||
selectedTab: function() {
|
||||
return Session.get("moveItemDialogTab");
|
||||
},
|
||||
characters: function() {
|
||||
var userId = Meteor.userId();
|
||||
return Characters.find(
|
||||
{
|
||||
$or: [
|
||||
{readers: userId},
|
||||
{writers: userId},
|
||||
{owner: userId},
|
||||
],
|
||||
_id: {$ne: this.charId},
|
||||
},
|
||||
{fields: {name: 1}}
|
||||
);
|
||||
},
|
||||
containers: function(){
|
||||
return Containers.find(
|
||||
{
|
||||
charId: this.charId,
|
||||
_id: {$ne: this.containerId},
|
||||
},
|
||||
{
|
||||
fields: {color: 1, name: 1},
|
||||
sort: {color: 1, name: 1},
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Template.moveItemDialog.events({
|
||||
"tap paper-tab": function(event) {
|
||||
Session.set("moveItemDialogTab", event.currentTarget.getAttribute("name"));
|
||||
},
|
||||
"tap #moveButton": function(event, instance) {
|
||||
var tab = Session.get("moveItemDialogTab");
|
||||
if (tab === "containers"){
|
||||
var containerId = instance.find("#containerMenu").selected;
|
||||
if (!containerId) throw "no menu selection";
|
||||
Meteor.call("moveItemToContainer", this.itemId, containerId);
|
||||
} else if (tab === "characters"){
|
||||
var characterId = instance.find("#characterMenu").selected;
|
||||
if (!characterId) throw "no menu selection";
|
||||
Meteor.call("moveItemToCharacter", this.itemId, characterId);
|
||||
} else {
|
||||
throw "Move item dialog tab is not set to containers or character," +
|
||||
" it is set to " + tab;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
<!-- data needs to include id of item, parentCollection, parentId -->
|
||||
<template name="splitStackDialog">
|
||||
<div style="width: 300px; height: 110px;">
|
||||
<paper-input-decorator label="Quantity" floatinglabel>
|
||||
<input autoFocus id="quantityInput" type="number" value={{quantity}}>
|
||||
</paper-input-decorator>
|
||||
<paper-button id="oneButton"> One </paper-button>
|
||||
<paper-button id="halfButton"> Half </paper-button>
|
||||
<paper-button id="allButton"> All </paper-button>
|
||||
</div>
|
||||
<paper-button id="cancelButton" affirmative> Cancel </paper-button>
|
||||
<paper-button id="moveButton" affirmative> Move </paper-button>
|
||||
</template>
|
||||
@@ -0,0 +1,27 @@
|
||||
Template.splitStackDialog.helpers({
|
||||
quantity: function(){
|
||||
var item = Items.findOne(this.id);
|
||||
if (item) return Math.round(item.quantity / 2);
|
||||
}
|
||||
});
|
||||
|
||||
Template.splitStackDialog.events({
|
||||
"tap #moveButton": function(event, instance){
|
||||
Meteor.call(
|
||||
"splitItemToParent",
|
||||
this.id,
|
||||
+instance.find("#quantityInput").value,
|
||||
{collection: this.parentCollection , id: this.parentId}
|
||||
);
|
||||
},
|
||||
"tap #oneButton":function(event, instance){
|
||||
instance.find("#quantityInput").value = 1;
|
||||
},
|
||||
"tap #halfButton":function(event, instance){
|
||||
var val = Math.round(Items.findOne(this.id).quantity / 2);
|
||||
instance.find("#quantityInput").value = val;
|
||||
},
|
||||
"tap #allButton":function(event, instance){
|
||||
instance.find("#quantityInput").value = Items.findOne(this.id).quantity;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
<template name="classDialog">
|
||||
{{#with class}}
|
||||
{{#baseDialog title=name class=colorClass startEditing=../startEditing}}
|
||||
<div layout vertical center>
|
||||
<div class="display2">
|
||||
{{level}}
|
||||
</div>
|
||||
<div>
|
||||
level
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{> effectsViewList charId=charId parentId=_id}}
|
||||
{{> proficiencyViewList charId=charId parentId=_id}}
|
||||
{{else}}
|
||||
<!--Name-->
|
||||
<paper-input id="classNameInput" label="Class Name" floatinglabel value={{name}}></paper-input>
|
||||
<!--Level-->
|
||||
<paper-input id="levelValueInput" label="Level" floatinglabel value={{level}}></paper-input>
|
||||
<!--Effects-->
|
||||
{{> effectsEditList parentId=_id parentCollection="Classes" charId=charId}}
|
||||
{{> proficiencyEditList parentId=_id parentCollection="Classes" charId=charId}}
|
||||
{{/baseDialog}}
|
||||
{{/with}}
|
||||
</template>
|
||||
@@ -0,0 +1,28 @@
|
||||
Template.classDialog.onRendered(function(){
|
||||
updatePolymerInputs(this);
|
||||
});
|
||||
|
||||
Template.classDialog.events({
|
||||
"color-change": function(event, instance){
|
||||
Classes.update(instance.data.classId, {$set: {color: event.color}});
|
||||
},
|
||||
"tap #deleteButton": function(event, instance){
|
||||
Classes.softRemoveNode(instance.data.classId);
|
||||
GlobalUI.deletedToast(instance.data.classId, "Classes", "Class");
|
||||
GlobalUI.closeDetail();
|
||||
},
|
||||
"change #classNameInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Classes.update(this._id, {$set: {name: value}});
|
||||
},
|
||||
"change #levelValueInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Classes.update(this._id, {$set: {level: value}});
|
||||
},
|
||||
});
|
||||
|
||||
Template.classDialog.helpers({
|
||||
class: function(){
|
||||
return Classes.findOne(this.classId);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
.noteDialog .colorDropdown {
|
||||
top: 0;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<template name="experienceDialog">
|
||||
{{#with experience}}
|
||||
{{#baseDialog title=name class=color hideColor="true" startEditing=../startEditing}}
|
||||
<div horizontal layout center-justified class= "display2">
|
||||
{{value}}
|
||||
</div>
|
||||
{{#if description}}
|
||||
<hr class="vertMargin">
|
||||
<div>{{#markdown}}{{description}}{{/markdown}}</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{> experienceEdit}}
|
||||
{{/baseDialog}}
|
||||
{{/with}}
|
||||
</template>
|
||||
|
||||
<template name="experienceEdit">
|
||||
<div horizontal layout>
|
||||
<!--Name-->
|
||||
<paper-input id="experienceNameInput" label="Name" floatinglabel value={{name}} flex></paper-input>
|
||||
<!--Value-->
|
||||
<paper-input-decorator label="Value" floatinglabel>
|
||||
<input id="valueInput" type="number" value={{value}}>
|
||||
</paper-input-decorator>
|
||||
</div>
|
||||
<!--Description-->
|
||||
<paper-input-decorator label="Description" floatinglabel layout vertical>
|
||||
<paper-autogrow-textarea>
|
||||
<textarea id="experienceDescriptionInput" placeholder value={{description}}></textarea>
|
||||
</paper-autogrow-textarea>
|
||||
</paper-input-decorator>
|
||||
</template>
|
||||
@@ -0,0 +1,40 @@
|
||||
Template.experienceEdit.onRendered(function(){
|
||||
updatePolymerInputs(this);
|
||||
});
|
||||
|
||||
Template.experienceDialog.helpers({
|
||||
experience: function(){
|
||||
Experiences.findOne(this.experienceId);
|
||||
return Experiences.findOne(this.experienceId);
|
||||
},
|
||||
color: function() {
|
||||
var char = Characters.findOne(this.charId, {fields: {color: 1}});
|
||||
if (char) return getColorClass(char.color);
|
||||
},
|
||||
});
|
||||
|
||||
Template.experienceDialog.events({
|
||||
"tap #deleteButton": function(event, instance){
|
||||
Experiences.softRemove(instance.data.experienceId);
|
||||
GlobalUI.deletedToast(
|
||||
instance.data.experienceId,
|
||||
"Experiences", "Experience"
|
||||
);
|
||||
GlobalUI.closeDetail();
|
||||
},
|
||||
});
|
||||
|
||||
Template.experienceEdit.events({
|
||||
"change #experienceNameInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Experiences.update(this._id, {$set: {name: value}});
|
||||
},
|
||||
"change #valueInput": function(event){
|
||||
var value = +event.currentTarget.value;
|
||||
Experiences.update(this._id, {$set: {value: value}});
|
||||
},
|
||||
"change #experienceDescriptionInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Experiences.update(this._id, {$set: {description: value}});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
.experiences {
|
||||
padding: 0 0 16px 0;
|
||||
}
|
||||
|
||||
.experience {
|
||||
height: 48px;
|
||||
}
|
||||
108
rpg-docs/client/views/private/character/journal/journal.html
Normal file
108
rpg-docs/client/views/private/character/journal/journal.html
Normal file
@@ -0,0 +1,108 @@
|
||||
<template name="journal">
|
||||
<div fit>
|
||||
<div id="journal" class="scroll-y" fit>
|
||||
<div class="column-container">
|
||||
<!--Experience Table-->
|
||||
<div><paper-shadow class="card experiencesCard"
|
||||
hero-id="main" {{detailHero}}>
|
||||
<div class="top white subhead"
|
||||
hero-id="toolbar" {{detailHero}}
|
||||
layout horizontal center>
|
||||
<div flex>Experience</div>
|
||||
<div >{{characterCalculate "experience" _id}} XP</div>
|
||||
<paper-icon-button class="black54" id="addXP" icon="add"
|
||||
disabled={{#unless canEditCharacter _id}}true{{/unless}}></paper-icon-button>
|
||||
</div>
|
||||
<div class="bottom list">
|
||||
{{#each experiences}}
|
||||
<div class="item-slot">
|
||||
<div class="item experience"
|
||||
hero-id="main" {{detailHero}}
|
||||
layout horizontal center>
|
||||
<div flex>{{name}}</div>
|
||||
<div class="xpValue">{{value}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{#if moreExperiencesOrCollapse}}
|
||||
<div layout horizontal center end-justified>
|
||||
<paper-button id="moreExperiences"
|
||||
disabled={{notMoreExperiences}}>
|
||||
Load More
|
||||
</paper-button>
|
||||
<paper-button id="lessExperiences"
|
||||
disabled={{cantCollapse}}>
|
||||
Collapse
|
||||
</paper-button>
|
||||
</div>
|
||||
{{/if}}
|
||||
</paper-shadow></div>
|
||||
<!--Class Table-->
|
||||
<div><paper-shadow class="card"
|
||||
hero-id="main" {{detailHero}}>
|
||||
<div class="white top"
|
||||
hero-id="toolbar" {{detailHero}}
|
||||
layout horizontal center>
|
||||
<div flex>
|
||||
<div class="containerName subhead">
|
||||
Level {{characterCalculate "level" _id}}
|
||||
</div>
|
||||
{{#if nextLevelXP}}
|
||||
<div class="caption">
|
||||
Next Level: {{nextLevelXP}}XP
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<paper-icon-button class="black54"
|
||||
id="addClassButton"
|
||||
icon="add"
|
||||
disabled={{#unless canEditCharacter _id}}true{{/unless}}>
|
||||
</paper-icon-button>
|
||||
</div>
|
||||
<div class="bottom list">
|
||||
<div class="item-slot">
|
||||
<div class="item race"
|
||||
hero-id="main" {{detailHero "race" _id}}
|
||||
layout horizontal center>
|
||||
{{race}}
|
||||
</div>
|
||||
</div>
|
||||
{{#each classes}}
|
||||
<div class="item-slot">
|
||||
<div class="item class"
|
||||
hero-id="main" {{detailHero}}
|
||||
layout horizontal center>
|
||||
{{name}} {{level}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-shadow></div>
|
||||
<!--Notes-->
|
||||
{{#each notes}}
|
||||
<div>
|
||||
<paper-shadow class="card" hero-id="main" {{detailHero}}>
|
||||
<div class="top {{colorClass}} noteTop subhead"
|
||||
hero-id="toolbar" {{detailHero}}
|
||||
layout horizontal center>
|
||||
{{name}}
|
||||
</div>
|
||||
<div class="bottom">{{#markdown}}{{description}}{{/markdown}}</div>
|
||||
</paper-shadow>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="fab-buffer"></div>
|
||||
</div>
|
||||
</div>
|
||||
{{#if canEditCharacter _id}}
|
||||
<paper-fab id="addNote"
|
||||
class="floatyButton"
|
||||
icon="add"
|
||||
title="Add"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
hero-id="main"></paper-fab>
|
||||
{{/if}}
|
||||
</template>
|
||||
153
rpg-docs/client/views/private/character/journal/journal.js
Normal file
153
rpg-docs/client/views/private/character/journal/journal.js
Normal file
@@ -0,0 +1,153 @@
|
||||
Template.journal.created = function(){
|
||||
var self = this;
|
||||
self.experiencesLimit = new ReactiveVar(
|
||||
self.data.settings && self.data.settings.experiencesInc || 10
|
||||
);
|
||||
};
|
||||
|
||||
Template.journal.helpers({
|
||||
notes: function(){
|
||||
return Notes.find({charId: this._id}, {sort: {color: 1, name: 1}});
|
||||
},
|
||||
experiences: function(){
|
||||
return Experiences.find(
|
||||
{charId: this._id},
|
||||
{
|
||||
sort: {dateAdded: -1},
|
||||
limit: Template.instance().experiencesLimit.get(),
|
||||
}
|
||||
);
|
||||
},
|
||||
notMoreExperiences: function(){
|
||||
return Experiences.find(
|
||||
{charId: this._id}
|
||||
).count() < Template.instance().experiencesLimit.get();
|
||||
},
|
||||
cantCollapse: function(){
|
||||
return Template.instance().experiencesLimit.get() <=
|
||||
(this.settings && this.settings.experiencesInc || 10);
|
||||
},
|
||||
moreExperiencesOrCollapse: function(){
|
||||
var allShown = Experiences.find({charId: this._id}).count() <
|
||||
Template.instance().experiencesLimit.get();
|
||||
var canCollapse = Template.instance().experiencesLimit.get() >
|
||||
(this.settings && this.settings.experiencesInc || 10);
|
||||
return !allShown || canCollapse;
|
||||
},
|
||||
classes: function(){
|
||||
return Classes.find({charId: this._id}, {sort: {createdAt: 1}});
|
||||
},
|
||||
levels: function(charId){
|
||||
return Levels.find({charId: charId, classId: this._id}, {sort: {value: 1}});
|
||||
},
|
||||
nextLevelXP: function(){
|
||||
var currentLevel = Characters.calculate.level(this._id);
|
||||
if (currentLevel < 20){
|
||||
return XP_TABLE[currentLevel];
|
||||
}
|
||||
},
|
||||
race: function(){
|
||||
var char = Characters.findOne(this._id, {fields: {race: 1}});
|
||||
return char && char.race;
|
||||
},
|
||||
});
|
||||
|
||||
Template.journal.events({
|
||||
"tap .noteTop": function(event){
|
||||
GlobalUI.setDetail({
|
||||
template: "noteDialog",
|
||||
data: {noteId: this._id, charId: this.charId},
|
||||
heroId: this._id,
|
||||
});
|
||||
},
|
||||
"tap .experience": function(event){
|
||||
GlobalUI.setDetail({
|
||||
template: "experienceDialog",
|
||||
data: {experienceId: this._id, charId: this.charId},
|
||||
heroId: this._id,
|
||||
});
|
||||
},
|
||||
"tap .class": function(event){
|
||||
GlobalUI.setDetail({
|
||||
template: "classDialog",
|
||||
data: {classId: this._id, charId: this.charId},
|
||||
heroId: this._id,
|
||||
});
|
||||
},
|
||||
"tap .race": function(event){
|
||||
GlobalUI.setDetail({
|
||||
template: "raceDialog",
|
||||
data: {charId: this._id},
|
||||
heroId: this._id + "race",
|
||||
});
|
||||
},
|
||||
"tap #addNote": function(event){
|
||||
var charId = this._id;
|
||||
Notes.insert({
|
||||
name: "New Note",
|
||||
charId: charId,
|
||||
}, function(error, id){
|
||||
if (!error){
|
||||
GlobalUI.setDetail({
|
||||
template: "noteDialog",
|
||||
data: {noteId: id, charId: charId, startEditing: true},
|
||||
heroId: id,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
"tap #addXP": function(event){
|
||||
var charId = this._id;
|
||||
Experiences.insert({
|
||||
charId: charId
|
||||
}, function(error, id){
|
||||
if (!error){
|
||||
GlobalUI.setDetail({
|
||||
template: "experienceDialog",
|
||||
data: {experienceId: id, charId: charId, startEditing: true},
|
||||
heroId: id,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
"tap #addClassButton":function(event){
|
||||
var charId = this._id;
|
||||
Classes.insert({
|
||||
charId: charId,
|
||||
name: "new Class",
|
||||
level: 1,
|
||||
}, function(error, id){
|
||||
if (!error){
|
||||
GlobalUI.setDetail({
|
||||
template: "classDialog",
|
||||
data: {classId: id, charId: charId, startEditing: true},
|
||||
heroId: id,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
"tap #moreExperiences": function(event){
|
||||
var inst = Template.instance();
|
||||
inst.experiencesLimit.set(
|
||||
inst.experiencesLimit.get() +
|
||||
(this.settings && this.settings.experiencesInc || 10)
|
||||
);
|
||||
},
|
||||
"tap #lessExperiences": function(event){
|
||||
var inst = Template.instance();
|
||||
inst.experiencesLimit.set(
|
||||
this.settings && this.settings.experiencesInc || 10
|
||||
);
|
||||
//scroll to the top of the div
|
||||
inst.$(".scroll-y").animate({
|
||||
scrollTop: (
|
||||
inst.$(".scroll-y").scrollTop() +
|
||||
inst.$(".experiencesCard").position().top -
|
||||
8
|
||||
)
|
||||
}, 300);
|
||||
//HACK giggle the columns :( to workaround chrome bug that stops .containers height from updating
|
||||
var cs = inst.$(".containers").removeClass("containers");
|
||||
_.defer(function(){cs.addClass("containers");});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
.noteDialog .colorDropdown {
|
||||
top: 0;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<template name="noteDialog">
|
||||
{{#with note}}
|
||||
{{#baseDialog title=name class=colorClass startEditing=../startEditing}}
|
||||
<div>{{#markdown}}{{description}}{{/markdown}}</div>
|
||||
{{else}}
|
||||
{{> noteDialogEdit}}
|
||||
{{/baseDialog}}
|
||||
{{/with}}
|
||||
</template>
|
||||
|
||||
<template name="noteDialogEdit">
|
||||
<!--Name-->
|
||||
<div horizontal layout>
|
||||
<paper-input id="noteNameInput"
|
||||
label="Name"
|
||||
floatinglabel
|
||||
value={{name}}
|
||||
flex>
|
||||
</paper-input>
|
||||
</div>
|
||||
<!--Description, formatting this nicely breaks it, leave it as is-->
|
||||
<paper-input-decorator label="Description"
|
||||
floatinglabel
|
||||
layout vertical>
|
||||
<paper-autogrow-textarea>
|
||||
<textarea id="noteDescriptionInput"
|
||||
value={{description}}></textarea>
|
||||
</paper-autogrow-textarea>
|
||||
</paper-input-decorator>
|
||||
</template>
|
||||
@@ -0,0 +1,31 @@
|
||||
Template.noteDialog.helpers({
|
||||
note: function(){
|
||||
return Notes.findOne(this.noteId);
|
||||
}
|
||||
});
|
||||
|
||||
Template.noteDialog.events({
|
||||
"color-change": function(event, instance){
|
||||
Notes.update(instance.data.noteId, {$set: {color: event.color}});
|
||||
},
|
||||
"tap #deleteButton": function(event, instance){
|
||||
Notes.softRemove(instance.data.noteId);
|
||||
GlobalUI.deletedToast(instance.data.noteId, "Notes", "Note");
|
||||
GlobalUI.closeDetail();
|
||||
},
|
||||
});
|
||||
|
||||
Template.noteDialogEdit.onRendered(function(){
|
||||
updatePolymerInputs(this);
|
||||
});
|
||||
|
||||
Template.noteDialogEdit.events({
|
||||
"change #noteNameInput, input #noteNameInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Notes.update(this._id, {$set: {name: value}});
|
||||
},
|
||||
"change #noteDescriptionInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Notes.update(this._id, {$set: {description: value}});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
<template name="raceDialog">
|
||||
{{#baseDialog title="Race" class=color hideColor="true" hideDelete="true" startEditing=startEditing}}
|
||||
<div horizontal layout center-justified class= "display2">
|
||||
{{race}}
|
||||
</div>
|
||||
{{> effectsViewList charId=charId parentId=charId parentGroup="racial"}}
|
||||
{{> proficiencyViewList charId=charId parentId=charId parentGroup="racial"}}
|
||||
{{else}}
|
||||
<paper-input id="raceInput" label="Race" floatinglabel value={{race}}></paper-input>
|
||||
{{> effectsEditList parentId=charId parentCollection="Characters" charId=charId parentGroup="racial"}}
|
||||
{{> proficiencyEditList parentId=charId parentCollection="Characters" charId=charId parentGroup="racial"}}
|
||||
{{/baseDialog}}
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
Template.raceDialog.onRendered(function(){
|
||||
updatePolymerInputs(this);
|
||||
});
|
||||
|
||||
Template.raceDialog.events({
|
||||
"change #raceInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Characters.update(this.charId, {$set: {race: value}});
|
||||
}
|
||||
});
|
||||
|
||||
Template.raceDialog.helpers({
|
||||
race: function(){
|
||||
var char = Characters.findOne(this.charId, {fields: {race: 1}});
|
||||
return char && char.race;
|
||||
},
|
||||
color: function() {
|
||||
var char = Characters.findOne(this.charId, {fields: {color: 1}});
|
||||
if (char) return getColorClass(char.color);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
<template name="newCharacterDialog">
|
||||
<div>
|
||||
<paper-input id="nameInput" label="Name"></paper-input><br>
|
||||
<paper-input id="genderInput" label="Gender"></paper-input><br>
|
||||
<paper-input id="raceInput" label="Race"></paper-input>
|
||||
<!--
|
||||
<div>
|
||||
<div layout horizontal center-justified>
|
||||
{{pointsUsed}}/<paper-input-decorator><input type="number" value="27"></paper-input-decorator>
|
||||
</div>
|
||||
<div layout horizontal wrap>
|
||||
<div>Strength</div>
|
||||
<paper-slider id="strSlider" min="8" max="15" value="8" secondaryProgress={{secondaryProgress}}></paper-slider>
|
||||
</div>
|
||||
<div layout horizontal wrap>
|
||||
<div>Dexterity</div>
|
||||
<paper-slider id="dexSlider" min="8" max="15" value="8" secondaryProgress={{secondaryProgress}}></paper-slider>
|
||||
</div>
|
||||
<div layout horizontal wrap>
|
||||
<div>Constitution</div>
|
||||
<paper-slider id="conSlider" min="8" max="15" value="8" secondaryProgress={{secondaryProgress}}></paper-slider>
|
||||
</div>
|
||||
<div layout horizontal wrap>
|
||||
<div>Intelligence</div>
|
||||
<paper-slider id="intSlider" min="8" max="15" value="8" secondaryProgress={{secondaryProgress}}></paper-slider>
|
||||
</div>
|
||||
<div layout horizontal wrap>
|
||||
<div>Wisdom</div>
|
||||
<paper-slider id="wisSlider" min="8" max="15" value="8" secondaryProgress={{secondaryProgress}}></paper-slider>
|
||||
</div>
|
||||
<div layout horizontal wrap>
|
||||
<div>Charisma</div>
|
||||
<paper-slider id="chaSlider" min="8" max="15" value="8" secondaryProgress={{secondaryProgress}}></paper-slider>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
<paper-button id="cancelButton" affirmative> Cancel </paper-button>
|
||||
<paper-button id="addButton" affirmative> Add </paper-button>
|
||||
</template>
|
||||
@@ -0,0 +1,13 @@
|
||||
Template.newCharacterDialog.events({
|
||||
"tap #addButton": function(event, instance){
|
||||
Characters.insert({
|
||||
name: instance.find("#nameInput").value,
|
||||
gender: instance.find("#genderInput").value,
|
||||
race: instance.find("#raceInput").value,
|
||||
owner: Meteor.userId(),
|
||||
}, function(err, id){
|
||||
if (err) throw err;
|
||||
Router.go("characterSheet", {_id: id});
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
<template name="backgroundDialog">
|
||||
{{#baseDialog title=title class=colorClass hideColor="true" hideDelete="true"}}
|
||||
<div>{{#markdown}}{{evaluateString charId value}}{{/markdown}}</div>
|
||||
{{> proficiencyViewList charId=charId parentId=charId parentGroup="background"}}
|
||||
{{else}}
|
||||
{{> textDialogEdit}}
|
||||
{{> proficiencyEditList parentId=charId parentCollection="Characters" charId=charId parentGroup="background"}}
|
||||
{{/baseDialog}}
|
||||
</template>
|
||||
@@ -0,0 +1,8 @@
|
||||
Template.backgroundDialog.helpers({
|
||||
value: function(){
|
||||
var fieldSelector = {fields: {}};
|
||||
fieldSelector.fields[this.field] = 1;
|
||||
var char = Characters.findOne(this.charId, fieldSelector);
|
||||
return char[this.field];
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
<template name="personaDetailsDialog">
|
||||
{{#baseDialog title=name class="deep-purple white-text" hideColor="true" hideDelete="true" startEditing=startEditing}}
|
||||
{{#with char}}
|
||||
<div>{{alignment}} {{gender}} {{race}}</div>
|
||||
<core-image style="width: 350px; height: 350px; margin-top: 8px;"
|
||||
sizing="cover"
|
||||
hero-id="image" hero
|
||||
src={{picture}}></core-image>
|
||||
{{/with}}
|
||||
{{else}}
|
||||
{{#with char}}
|
||||
{{> personaDetailsEdit}}
|
||||
{{/with}}
|
||||
{{/baseDialog}}
|
||||
</template>
|
||||
|
||||
<template name="personaDetailsEdit">
|
||||
<div layout horizontal center-justified>
|
||||
<div flex style="max-width: 350px;" layout vertical>
|
||||
<!--Name-->
|
||||
<paper-input id="nameInput" label="Name" floatinglabel value={{name}}></paper-input>
|
||||
<!--Alignment-->
|
||||
<paper-input id="alignmentInput" label="Alignment" floatinglabel value={{alignment}}></paper-input>
|
||||
<!--Gender-->
|
||||
<paper-input id="genderInput" label="Gender" floatinglabel value={{gender}}></paper-input>
|
||||
<!--Race-->
|
||||
<paper-input id="raceInput" label="Race" floatinglabel value={{race}}></paper-input>
|
||||
<!--Picture-->
|
||||
<paper-input id="pictureInput" label="Picture URL" floatinglabel value={{picture}}></paper-input>
|
||||
<core-image style="height:350px; width: 100%; margin-top: 8px;"
|
||||
sizing="cover"
|
||||
hero-id="image" hero
|
||||
src={{picture}}></core-image>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,35 @@
|
||||
Template.personaDetailsEdit.onRendered(function(){
|
||||
updatePolymerInputs(this);
|
||||
});
|
||||
|
||||
Template.personaDetailsDialog.helpers({
|
||||
char: function() {
|
||||
return Characters.findOne(
|
||||
this._id,
|
||||
{fields: {name: 1, alignment: 1, gender: 1, race: 1, picture: 1}}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Template.personaDetailsEdit.events({
|
||||
"change #nameInput": function(event){
|
||||
var input = event.currentTarget.value;
|
||||
Characters.update(this._id, {$set: {name: input}});
|
||||
},
|
||||
"change #alignmentInput": function(event){
|
||||
var input = event.currentTarget.value;
|
||||
Characters.update(this._id, {$set: {alignment: input}});
|
||||
},
|
||||
"change #genderInput": function(event){
|
||||
var input = event.currentTarget.value;
|
||||
Characters.update(this._id, {$set: {gender: input}});
|
||||
},
|
||||
"change #raceInput": function(event){
|
||||
var input = event.currentTarget.value;
|
||||
Characters.update(this._id, {$set: {race: input}});
|
||||
},
|
||||
"change #pictureInput": function(event){
|
||||
var input = event.currentTarget.value;
|
||||
Characters.update(this._id, {$set: {picture: input}});
|
||||
},
|
||||
});
|
||||
77
rpg-docs/client/views/private/character/persona/persona.html
Normal file
77
rpg-docs/client/views/private/character/persona/persona.html
Normal file
@@ -0,0 +1,77 @@
|
||||
<template name="persona">
|
||||
<div fit>
|
||||
<div id="persona" class="scroll-y" fit>
|
||||
<div class="column-container">
|
||||
{{#with characterDetails}}
|
||||
<div>
|
||||
<paper-shadow class="card"
|
||||
hero-id="main" {{detailHero "details" _id}}>
|
||||
{{#unless picture}}
|
||||
<div class="top subhead characterField {{colorClass}}"
|
||||
hero-id="toolbar" {{detailHero "details" _id}}>
|
||||
<div class="subhead" flex
|
||||
hero-id="title" {{detailHero "details" _id}}>
|
||||
{{name}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<core-image class="characterField clickable"
|
||||
style="height:350px; width: 100%;
|
||||
background-color: #e8e8e8;"
|
||||
sizing="cover"
|
||||
hero-id="image" {{detailHero "details" _id}}
|
||||
src={{picture}}></core-image>
|
||||
{{/unless}}
|
||||
<div class="bottom">
|
||||
{{#if picture}}
|
||||
<div class="title" hero-id="title" {{detailHero "details" _id}}>
|
||||
{{name}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="subhead">
|
||||
{{alignment}} {{gender}} {{race}}
|
||||
</div>
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</div>
|
||||
{{/with}}
|
||||
<div>{{> containerCard characterField "description" "Description"}}</div>
|
||||
<div>{{> containerCard characterField "personality" "Personality Traits"}}</div>
|
||||
<div>{{> containerCard characterField "ideals" "Ideals"}}</div>
|
||||
<div>{{> containerCard characterField "bonds" "Bonds"}}</div>
|
||||
<div>{{> containerCard characterField "flaws" "Flaws"}}</div>
|
||||
<div>{{> containerCard characterField "backstory" "Background"}}</div>
|
||||
<div>
|
||||
<paper-shadow class="card">
|
||||
<div class="white top subhead">
|
||||
Languages
|
||||
</div>
|
||||
<div class="bottom list">
|
||||
{{#each languages}}
|
||||
{{> proficiencyListItem}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="containerCard">
|
||||
{{#containerCardHelper this}}{{evaluateString _id body}}{{/containerCardHelper}}
|
||||
</template>
|
||||
|
||||
<template name="containerCardHelper">
|
||||
<paper-shadow class="card {{class}}"
|
||||
hero-id="main" {{detailHero field ../_id}}>
|
||||
<div class="top subhead {{colorClass}} {{topClass}}"
|
||||
hero-id="toolbar" {{detailHero field ../_id}}>
|
||||
<div class="subhead" flex
|
||||
hero-id="title" {{detailHero field ../_id}}>
|
||||
{{title}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">{{#markdown}}{{> UI.contentBlock}}{{/markdown}}</div>
|
||||
</paper-shadow>
|
||||
</template>
|
||||
67
rpg-docs/client/views/private/character/persona/persona.js
Normal file
67
rpg-docs/client/views/private/character/persona/persona.js
Normal file
@@ -0,0 +1,67 @@
|
||||
var colorMap = {
|
||||
description: "e",
|
||||
personality: "f",
|
||||
ideals: "g",
|
||||
bonds: "h",
|
||||
flaws: "i",
|
||||
backstory: "j",
|
||||
};
|
||||
|
||||
Template.persona.helpers({
|
||||
characterDetails: function(){
|
||||
var char = Characters.findOne(
|
||||
this._id,
|
||||
{fields: {name: 1, gender: 1, alignment: 1, race:1, picture: 1}}
|
||||
);
|
||||
char.field = "details";
|
||||
char.title = char.name;
|
||||
char.color = "d";
|
||||
char.startEditing = true;
|
||||
return char;
|
||||
},
|
||||
characterField: function(field, title){
|
||||
var fieldSelector = {fields: {}};
|
||||
fieldSelector.fields[field] = 1;
|
||||
var char = Characters.findOne(this._id, fieldSelector);
|
||||
var color = colorMap[field];
|
||||
return {
|
||||
_id: char._id,
|
||||
title: title,
|
||||
field: field,
|
||||
color: color,
|
||||
body: char[field],
|
||||
topClass: "characterField",
|
||||
};
|
||||
},
|
||||
languages: function(){
|
||||
return Proficiencies.find({charId: this._id, type: "language"});
|
||||
},
|
||||
});
|
||||
|
||||
Template.persona.events({
|
||||
"tap .characterField": function(event){
|
||||
if (this.field == "details"){
|
||||
this.charId = Template.parentData()._id;
|
||||
GlobalUI.setDetail({
|
||||
template: "personaDetailsDialog",
|
||||
data: this,
|
||||
heroId: this._id + this.field,
|
||||
});
|
||||
} else {
|
||||
var template = "textDialog";
|
||||
if (this.field === "backstory") template = "backgroundDialog";
|
||||
var charId = Template.parentData()._id;
|
||||
GlobalUI.setDetail({
|
||||
template: template,
|
||||
data: {
|
||||
charId: charId,
|
||||
field: this.field,
|
||||
title: this.title,
|
||||
color: this.color,
|
||||
startEditing: true,
|
||||
},
|
||||
heroId: this._id + this.field,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
<template name="textDialog">
|
||||
{{#baseDialog title=title class=colorClass hideColor="true" hideDelete="true" startEditing=startEditing}}
|
||||
<div>{{#markdown}}{{evaluateString charId value}}{{/markdown}}</div>
|
||||
{{else}}
|
||||
{{> textDialogEdit}}
|
||||
{{/baseDialog}}
|
||||
</template>
|
||||
|
||||
<template name="textDialogEdit">
|
||||
<paper-input-decorator label={{title}} floatinglabel layout vertical>
|
||||
<paper-autogrow-textarea>
|
||||
<textarea id="textInput" placeholder value={{value}}></textarea>
|
||||
</paper-autogrow-textarea>
|
||||
</paper-input-decorator>
|
||||
</template>
|
||||
@@ -0,0 +1,30 @@
|
||||
Template.textDialog.helpers({
|
||||
value: function(){
|
||||
var fieldSelector = {fields: {}};
|
||||
fieldSelector.fields[this.field] = 1;
|
||||
var char = Characters.findOne(this.charId, fieldSelector);
|
||||
return char[this.field];
|
||||
}
|
||||
});
|
||||
|
||||
Template.textDialogEdit.onRendered(function(){
|
||||
updatePolymerInputs(this);
|
||||
});
|
||||
|
||||
Template.textDialogEdit.helpers({
|
||||
value: function(){
|
||||
var fieldSelector = {fields: {}};
|
||||
fieldSelector.fields[this.field] = 1;
|
||||
var char = Characters.findOne(this.charId, fieldSelector);
|
||||
return char[this.field];
|
||||
}
|
||||
});
|
||||
|
||||
Template.textDialogEdit.events({
|
||||
"change #textInput": function(event){
|
||||
var input = event.currentTarget.value;
|
||||
var setter = {$set: {}};
|
||||
setter.$set[this.field] = input;
|
||||
Characters.update(this.charId, setter);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
<template name="proficiencyEdit">
|
||||
<div layout horizontal around-justified>
|
||||
<paper-dropdown-menu class="typeDropDown" label="Stat Group" flex>
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu typeMenu" selected={{type}}>
|
||||
{{#each proficiencyTypes}}
|
||||
<paper-item class="statGroupSelect" name={{type}}>{{name}}</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
{{> UI.dynamic template=nameInputTemplate}}
|
||||
<paper-dropdown-menu class="valueDropDown" label="Proficiency" flex>
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu valueMenu" selected={{value}}>
|
||||
<paper-item name="1">Proficient</paper-item>
|
||||
<paper-item name="0.5">Half Prof. Bonus</paper-item>
|
||||
<paper-item name="2">Double Prof. Bonus</paper-item>
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
<paper-icon-button class="deleteProficiency"
|
||||
icon="delete">
|
||||
</paper-icon-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="nameDropdown">
|
||||
<paper-dropdown-menu class="nameDropDown sideMargin" label="Proficiency" flex>
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu nameMenu" selected={{name}}>
|
||||
{{#each nameDropdownItems}}
|
||||
<paper-item name={{stat}}>{{name}}</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
</template>
|
||||
|
||||
<template name="nameInput">
|
||||
<paper-input class="nameInput sideMargin"
|
||||
label="Name"
|
||||
floatinglabel
|
||||
value={{name}}
|
||||
flex></paper-input>
|
||||
</template>
|
||||
@@ -0,0 +1,90 @@
|
||||
var profTypes = [
|
||||
{type: "skill", name: "Skill"},
|
||||
{type: "save", name: "Saving Throw"},
|
||||
{type: "weapon", name: "Weapon"},
|
||||
{type: "armor", name: "Armor"},
|
||||
{type: "tool", name: "Tool"},
|
||||
{type: "language", name: "Language"},
|
||||
];
|
||||
|
||||
var saves = [
|
||||
{name: "Strength Save", stat: "strengthSave"},
|
||||
{name: "Dexterity Save", stat: "dexteritySave"},
|
||||
{name: "Constitution Save", stat: "constitutionSave"},
|
||||
{name: "Intelligence Save", stat: "intelligenceSave"},
|
||||
{name: "Wisdom Save", stat: "wisdomSave"},
|
||||
{name: "Charisma Save", stat: "charismaSave"},
|
||||
];
|
||||
|
||||
var skills = [
|
||||
{name: "Acrobatics", stat: "acrobatics"},
|
||||
{name: "Animal Handling", stat: "animalHandling"},
|
||||
{name: "Arcana", stat: "arcana"},
|
||||
{name: "Athletics", stat: "athletics"},
|
||||
{name: "Deception", stat: "deception"},
|
||||
{name: "History", stat: "history"},
|
||||
{name: "Insight", stat: "insight"},
|
||||
{name: "Intimidation", stat: "intimidation"},
|
||||
{name: "Investigation", stat: "investigation"},
|
||||
{name: "Medicine", stat: "medicine"},
|
||||
{name: "Nature", stat: "nature"},
|
||||
{name: "Perception", stat: "perception"},
|
||||
{name: "Performance", stat: "performance"},
|
||||
{name: "Persuasion", stat: "persuasion"},
|
||||
{name: "Religion", stat: "religion"},
|
||||
{name: "Sleight of Hand", stat: "sleightOfHand"},
|
||||
{name: "Stealth", stat: "stealth"},
|
||||
{name: "Survival", stat: "survival"},
|
||||
{name: "Initiative", stat: "initiative"},
|
||||
];
|
||||
|
||||
Template.proficiencyEdit.helpers({
|
||||
proficiencyTypes: function(){
|
||||
return profTypes;
|
||||
},
|
||||
nameInputTemplate: function(){
|
||||
if (!this.type) return null;
|
||||
if (this.type === "skill" ||
|
||||
this.type === "save") return "nameDropdown";
|
||||
return "nameInput";
|
||||
},
|
||||
});
|
||||
|
||||
Template.proficiencyEdit.events({
|
||||
"tap .deleteProficiency": function(event){
|
||||
Proficiencies.softRemoveNode(this._id);
|
||||
GlobalUI.deletedToast(this._id, "Proficiencies", "Proficiency");
|
||||
},
|
||||
"core-select .typeDropDown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var type = detail.item.getAttribute("name");
|
||||
if (type == this.type) return;
|
||||
Proficiencies.update(this._id, {$set: {type: type}});
|
||||
},
|
||||
"core-select .valueDropDown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var value = +detail.item.getAttribute("name");
|
||||
if (value == this.value) return;
|
||||
Proficiencies.update(this._id, {$set: {value: value}});
|
||||
},
|
||||
"core-select .nameDropDown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var name = detail.item.getAttribute("name");
|
||||
if (name == this.name) return;
|
||||
Proficiencies.update(this._id, {$set: {name: name}});
|
||||
},
|
||||
"change .nameInput": function(event){
|
||||
var name = event.currentTarget.value;
|
||||
Proficiencies.update(this._id, {$set: {name: name}});
|
||||
},
|
||||
});
|
||||
|
||||
Template.nameDropdown.helpers({
|
||||
nameDropdownItems: function(){
|
||||
if (this.type === "skill") return skills;
|
||||
if (this.type === "save") return saves;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
<!--needs to be given charId, parentId and parentCollection-->
|
||||
<template name="proficiencyEditList">
|
||||
{{#if proficiencies.count}}
|
||||
<hr class="vertMargin">
|
||||
|
||||
<div id="proficiencies">
|
||||
<h2>Proficiencies</h2>
|
||||
{{#each proficiencies}}
|
||||
{{>proficiencyEdit}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<paper-button id="addProficiencyButton"
|
||||
class="red-button"
|
||||
raised>
|
||||
Add Proficiency
|
||||
</paper-button>
|
||||
</template>
|
||||
@@ -0,0 +1,31 @@
|
||||
Template.proficiencyEditList.helpers({
|
||||
proficiencies: function(){
|
||||
var selector = {
|
||||
"parent.id": this.parentId,
|
||||
"charId": this.charId,
|
||||
};
|
||||
if (this.parentGroup){
|
||||
selector["parent.group"] = this.parentGroup;
|
||||
}
|
||||
return Proficiencies.find(selector);
|
||||
}
|
||||
});
|
||||
|
||||
Template.proficiencyEditList.events({
|
||||
"tap #addProficiencyButton": function(){
|
||||
if (!_.isBoolean(this.enabled)) {
|
||||
this.enabled = true;
|
||||
}
|
||||
Proficiencies.insert({
|
||||
charId: this.charId,
|
||||
parent: {
|
||||
id: this.parentId,
|
||||
collection: this.parentCollection,
|
||||
group: this.parentGroup,
|
||||
},
|
||||
enabled: this.enabled,
|
||||
value: 1,
|
||||
type: "skill",
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
<template name="proficiencyListItem">
|
||||
<div class="item-slot">
|
||||
<div class="proficiency item small"
|
||||
hero-id="main" {{detailHero}}
|
||||
layout horizontal center>
|
||||
<core-icon icon="{{profIcon}}"
|
||||
style="margin-right: 16px;"></core-icon>
|
||||
<div flex>{{getName}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,20 @@
|
||||
Template.proficiencyListItem.helpers({
|
||||
profIcon: function(){
|
||||
var prof = this.value;
|
||||
if (prof > 0 && prof < 1) return "image:brightness-2";
|
||||
if (prof === 1) return "image:brightness-1";
|
||||
if (prof > 1) return "av:album";
|
||||
return "radio-button-off";
|
||||
},
|
||||
getName: function(){
|
||||
if (this.type === "skill") return skills[this.name];
|
||||
if (this.type === "save") return saves[this.name];
|
||||
return this.name;
|
||||
},
|
||||
});
|
||||
|
||||
Template.proficiencyListItem.events({
|
||||
"tap .proficiency": function(event, instance){
|
||||
openParentDialog(this.parent, this.charId, this._id);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
<template name="proficiencyView">
|
||||
<div class="proficiencyView item small"
|
||||
style="padding: 0;"
|
||||
layout horizontal center>
|
||||
<core-icon icon="{{profIcon}}" style="margin-right: 16px;"></core-icon>
|
||||
<div>{{getName}}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
var saves = {
|
||||
strengthSave: "Strength Save",
|
||||
dexteritySave: "Dexterity Save",
|
||||
constitutionSave: "Constitution Save",
|
||||
intelligenceSave: "Intelligence Save",
|
||||
wisdomSave: "Wisdom Save",
|
||||
charismaSave: "Charisma Save",
|
||||
};
|
||||
|
||||
var skills = {
|
||||
acrobatics: "Acrobatics",
|
||||
animalHandling: "Animal Handling",
|
||||
arcana: "Arcana",
|
||||
athletics: "Athletics",
|
||||
deception: "Deception",
|
||||
history: "History",
|
||||
insight: "Insight",
|
||||
intimidation: "Intimidation",
|
||||
investigation: "Investigation",
|
||||
medicine: "Medicine",
|
||||
nature: "Nature",
|
||||
perception: "Perception",
|
||||
performance: "Performance",
|
||||
persuasion: "Persuasion",
|
||||
religion: "Religion",
|
||||
sleightOfHand: "Sleight of Hand",
|
||||
stealth: "Stealth",
|
||||
survival: "Survival",
|
||||
initiative: "Initiative",
|
||||
};
|
||||
|
||||
Template.proficiencyView.helpers({
|
||||
profIcon: function(){
|
||||
var prof = this.value;
|
||||
if (prof > 0 && prof < 1) return "image:brightness-2";
|
||||
if (prof === 1) return "image:brightness-1";
|
||||
if (prof > 1) return "av:album";
|
||||
return "radio-button-off";
|
||||
},
|
||||
getName: function(){
|
||||
if (this.type === "skill") return skills[this.name];
|
||||
if (this.type === "save") return saves[this.name];
|
||||
return this.name;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
<template name="proficiencyViewList">
|
||||
{{#if proficiencies.count}}
|
||||
<hr class="vertMargin">
|
||||
<div class="proficiencies">
|
||||
<h2 style="margin-bottom: 8px;">Proficiencies</h2>
|
||||
{{#each proficiencies}}
|
||||
{{> proficiencyView}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
@@ -0,0 +1,12 @@
|
||||
Template.proficiencyViewList.helpers({
|
||||
proficiencies: function(){
|
||||
var selector = {
|
||||
"parent.id": this.parentId,
|
||||
"charId": this.charId,
|
||||
};
|
||||
if (this.parentGroup){
|
||||
selector["parent.group"] = this.parentGroup;
|
||||
}
|
||||
return Proficiencies.find(selector);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
.spellDialog paper-checkbox {
|
||||
margin: 8px 16px 8px 8px;
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<template name="spellDialog">
|
||||
{{#with spell}}
|
||||
{{#baseDialog title=name class=colorClass startEditing=../startEditing}}
|
||||
{{> spellDetails}}
|
||||
{{else}}
|
||||
{{> spellEdit}}
|
||||
{{/baseDialog}}
|
||||
{{/with}}
|
||||
</template>
|
||||
|
||||
<template name="spellDetails">
|
||||
<div class="body2">
|
||||
Level {{level}} {{school}} {{#if ritual}}ritual{{/if}}, {{preparedString}}
|
||||
</div>
|
||||
<div style="margin: 16px 0 16px 0;">
|
||||
{{#if castingTime}}
|
||||
<div>
|
||||
<span class="body2">Casting Time: </span><span>{{castingTime}}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if range}}
|
||||
<div>
|
||||
<span class="body2">Range: </span><span>{{range}}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if getComponents}}
|
||||
<div>
|
||||
<span class="body2">Components: </span><span>{{getComponents}}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if duration}}
|
||||
<div>
|
||||
<span class="body2">Duration: </span><span>{{duration}}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div>{{#markdown}}{{evaluateString charId description}}{{/markdown}}</div>
|
||||
{{> attacksViewList charId=charId parentId=_id}}
|
||||
</template>
|
||||
|
||||
<template name="spellEdit">
|
||||
<div horizontal layout>
|
||||
<paper-input id="spellNameInput" label="Name" floatinglabel value={{name}} flex></paper-input>
|
||||
</div>
|
||||
<div layout horizontal justified wrap>
|
||||
<paper-dropdown-menu id="schoolDropdown" label="School">
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu" selected={{school}}>
|
||||
{{#each magicSchools}}
|
||||
<paper-item name={{this}} class="containerMenuItem">{{this}}</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
<paper-dropdown-menu id="levelDropdown" label="Level">
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu" selected={{level}}>
|
||||
{{#each spellLevels}}
|
||||
<paper-item name={{level}} class="containerMenuItem">{{name}}</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
<paper-dropdown-menu id="listDropdown" label="Spell List">
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu" selected={{parent.id}}>
|
||||
{{#each spellLists}}
|
||||
<paper-item name={{_id}} class="containerMenuItem">{{name}}</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
<paper-dropdown-menu id="preparedDropdown" label="School">
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu" selected={{prepared}}>
|
||||
{{#each preparedOptions}}
|
||||
<paper-item name={{value}} class="containerMenuItem">{{name}}</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
|
||||
<hr class="vertMargin">
|
||||
|
||||
<div horizontal layout center justified wrap>
|
||||
<div layout horizontal center>
|
||||
<span>Verbal:</span>
|
||||
<paper-checkbox id="verbalCheckbox" class="sideMargin" checked={{components.verbal}}></paper-checkbox>
|
||||
</div>
|
||||
<div layout horizontal center>
|
||||
<span>Somatic:</span>
|
||||
<paper-checkbox id="somaticCheckbox" class="sideMargin" checked={{components.somatic}}></paper-checkbox>
|
||||
</div>
|
||||
<div layout horizontal center>
|
||||
<span>Concentration:</span>
|
||||
<paper-checkbox id="concentrationCheckbox" class="sideMargin" checked={{components.concentration}}></paper-checkbox>
|
||||
</div>
|
||||
<div layout horizontal center>
|
||||
<span>Ritual: </span>
|
||||
<paper-checkbox id="ritualCheckbox" class="sideMargin" checked={{ritual}}></paper-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
<div layout horizontal center>
|
||||
<div>Material: </div>
|
||||
<paper-input id="materialInput" class="sideMargin" label="Material Components" floatinglabel value={{components.material}} flex></paper-input>
|
||||
</div>
|
||||
|
||||
<hr class="vertMargin">
|
||||
|
||||
<div layout horizontal justified wrap>
|
||||
<paper-input id="castingTimeInput"
|
||||
label="Casting Time"
|
||||
value={{castingTime}}
|
||||
floatinglabel
|
||||
flex></paper-input>
|
||||
<paper-input id="rangeInput"
|
||||
class="sideMargin"
|
||||
label="Range"
|
||||
value={{range}}
|
||||
floatinglabel
|
||||
flex></paper-input>
|
||||
<paper-input id="durationInput"
|
||||
label="Duration"
|
||||
value={{duration}}
|
||||
floatinglabel
|
||||
flex></paper-input>
|
||||
</div>
|
||||
|
||||
<hr class="vertMargin">
|
||||
|
||||
<!--Description-->
|
||||
<paper-input-decorator label="Description" floatinglabel layout vertical>
|
||||
<paper-autogrow-textarea>
|
||||
<textarea id="descriptionInput" placeholder value={{description}}></textarea>
|
||||
</paper-autogrow-textarea>
|
||||
</paper-input-decorator>
|
||||
{{> attackEditList parentId=_id parentCollection="Spells" charId=charId enabled=true name=name}}
|
||||
</template>
|
||||
@@ -0,0 +1,142 @@
|
||||
var spellLevels = [
|
||||
{name: "Cantrip", level: 0},
|
||||
{name: "Level 1", level: 1},
|
||||
{name: "Level 2", level: 2},
|
||||
{name: "Level 3", level: 3},
|
||||
{name: "Level 4", level: 4},
|
||||
{name: "Level 5", level: 5},
|
||||
{name: "Level 6", level: 6},
|
||||
{name: "Level 7", level: 7},
|
||||
{name: "Level 8", level: 8},
|
||||
{name: "Level 9", level: 9},
|
||||
];
|
||||
|
||||
Template.spellDialog.helpers({
|
||||
spell: function(){
|
||||
return Spells.findOne(this.spellId);
|
||||
}
|
||||
});
|
||||
|
||||
Template.spellDialog.events({
|
||||
"color-change": function(event, instance){
|
||||
Spells.update(instance.data.spellId, {$set: {color: event.color}});
|
||||
},
|
||||
"tap #deleteButton": function(event, instance){
|
||||
Spells.softRemoveNode(instance.data.spellId);
|
||||
GlobalUI.deletedToast(instance.data.spellId, "Spells", "Spell");
|
||||
GlobalUI.closeDetail();
|
||||
},
|
||||
});
|
||||
|
||||
Template.spellDetails.helpers({
|
||||
getComponents: function(){
|
||||
var components = "";
|
||||
if (this.components.concentration) components += "C";
|
||||
if (this.components.verbal) components += components.length ? ", V" : "V";
|
||||
if (this.components.somatic) components += components.length ? ", S" : "S";
|
||||
if (this.components.material) {
|
||||
components += components.length ? ", M" : "M";
|
||||
components += " (" + this.components.material + ")";
|
||||
}
|
||||
return components;
|
||||
},
|
||||
preparedString: function(){
|
||||
if (this.prepared === "prepared") return "prepared";
|
||||
if (this.prepared === "unprepared") return "unprepared";
|
||||
if (this.prepared === "always") return "always prepared";
|
||||
},
|
||||
});
|
||||
|
||||
Template.spellEdit.onRendered(function(){
|
||||
updatePolymerInputs(this);
|
||||
});
|
||||
|
||||
Template.spellEdit.helpers({
|
||||
spellLists: function(){
|
||||
return SpellLists.find({charId: this.charId}, {fields: {name: 1}});
|
||||
},
|
||||
magicSchools: function(){
|
||||
return magicSchools;
|
||||
},
|
||||
spellLevels: function(){
|
||||
return spellLevels;
|
||||
},
|
||||
preparedOptions: function(){
|
||||
return [
|
||||
{name: "Prepared", value: "prepared"},
|
||||
{name: "Unprepared", value: "unprepared"},
|
||||
{name: "Always Prepared", value: "always"},
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
Template.spellEdit.events({
|
||||
"change #spellNameInput, input #spellNameInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Spells.update(this._id, {$set: {name: value}});
|
||||
},
|
||||
"change #castingTimeInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Spells.update(this._id, {$set: {castingTime: value}});
|
||||
},
|
||||
"change #rangeInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Spells.update(this._id, {$set: {range: value}});
|
||||
},
|
||||
"change #durationInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Spells.update(this._id, {$set: {duration: value}});
|
||||
},
|
||||
"change #materialInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Spells.update(this._id, {$set: {"components.material": value}});
|
||||
},
|
||||
"change #descriptionInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Spells.update(this._id, {$set: {"description": value}});
|
||||
},
|
||||
"core-select #listDropdown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var value = detail.item.getAttribute("name");
|
||||
if (value == this.parent.id) return;
|
||||
Spells.update(this._id, {$set: {"parent.id": value}});
|
||||
},
|
||||
"core-select #levelDropdown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var value = detail.item.getAttribute("name");
|
||||
if (value == this.level) return;
|
||||
Spells.update(this._id, {$set: {level: value}});
|
||||
},
|
||||
"core-select #schoolDropdown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var value = detail.item.getAttribute("name");
|
||||
if (value == this.school) return;
|
||||
Spells.update(this._id, {$set: {school: value}});
|
||||
},
|
||||
"core-select #preparedDropdown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if (!detail.isSelected) return;
|
||||
var value = detail.item.getAttribute("name");
|
||||
if (value == this.school) return;
|
||||
Spells.update(this._id, {$set: {prepared: value}});
|
||||
},
|
||||
"change #verbalCheckbox": function(event){
|
||||
var value = event.currentTarget.checked;
|
||||
Spells.update(this._id, {$set: {"components.verbal": value}});
|
||||
},
|
||||
"change #somaticCheckbox": function(event){
|
||||
var value = event.currentTarget.checked;
|
||||
Spells.update(this._id, {$set: {"components.somatic": value}});
|
||||
},
|
||||
"change #concentrationCheckbox": function(event){
|
||||
var value = event.currentTarget.checked;
|
||||
Spells.update(this._id, {$set: {"components.concentration": value}});
|
||||
},
|
||||
"change #ritualCheckbox": function(event){
|
||||
var value = event.currentTarget.checked;
|
||||
Spells.update(this._id, {$set: {"ritual": value}});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
.spellListDialog .colorDropdown {
|
||||
top: 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<template name="spellListDialog">
|
||||
{{#with spellList}}
|
||||
{{#baseDialog title=name class=colorClass startEditing=../startEditing}}
|
||||
<div>
|
||||
<div layout horizontal justified wrap class="subhead">
|
||||
{{#if attackBonus}}
|
||||
<div>
|
||||
Attack Bonus: {{evaluate charId attackBonus}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if saveDC}}
|
||||
<div>
|
||||
Save DC: {{evaluate charId saveDC}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if maxPrepared}}
|
||||
<div>
|
||||
Max Prepared: {{evaluateSigned charId maxPrepared}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<hr class="vertMargin">
|
||||
<div>{{#markdown}}{{evaluateString charId description}}{{/markdown}}</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<!--Name-->
|
||||
<paper-input id="spellListNameInput"
|
||||
class="fullwidth"
|
||||
label="Name"
|
||||
floatinglabel
|
||||
value={{name}}></paper-input>
|
||||
<!--Save DC-->
|
||||
<paper-input id="spellListSaveDCInput"
|
||||
label="Save DC"
|
||||
floatinglabel
|
||||
value={{saveDC}}
|
||||
style="width: 100%;"></paper-input><br>
|
||||
<!--Attack Bonus-->
|
||||
<paper-input id="spellListAttackBonusInput"
|
||||
label="Attack Bonus"
|
||||
floatinglabel
|
||||
value={{attackBonus}}
|
||||
style="width: 100%;"></paper-input><br>
|
||||
<!--Max Prepared-->
|
||||
<paper-input id="spellListMaxPreparedInput"
|
||||
label="Maximum Prepared Spells"
|
||||
floatinglabel
|
||||
value={{maxPrepared}}
|
||||
style="width: 100%;"></paper-input><br>
|
||||
<!--Description-->
|
||||
<paper-input-decorator label="Description" floatinglabel layout vertical>
|
||||
<paper-autogrow-textarea>
|
||||
<textarea id="spellListDescriptionInput" placeholder value={{description}}></textarea>
|
||||
</paper-autogrow-textarea>
|
||||
</paper-input-decorator>
|
||||
{{/baseDialog}}
|
||||
{{/with}}
|
||||
</template>
|
||||
@@ -0,0 +1,48 @@
|
||||
Template.spellListDialog.onRendered(function(){
|
||||
updatePolymerInputs(this);
|
||||
});
|
||||
|
||||
Template.spellListDialog.events({
|
||||
"color-change": function(event, instance){
|
||||
SpellLists.update(instance.data.spellListId, {$set: {color: event.color}});
|
||||
},
|
||||
"tap #deleteButton": function(event, instance){
|
||||
SpellLists.softRemoveNode(instance.data.spellListId);
|
||||
GlobalUI.deletedToast(
|
||||
instance.data.spellListId,
|
||||
"SpellLists",
|
||||
"Spell list and contents"
|
||||
);
|
||||
GlobalUI.closeDetail();
|
||||
},
|
||||
//TODO clean up String -> num here so they don't need casting by Schema.clean
|
||||
//TODO validate input (integer, non-negative, etc) for these inputs and give validation errors
|
||||
"change #spellListNameInput, input #spellListNameInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
SpellLists.update(this._id, {$set: {name: value}});
|
||||
},
|
||||
"change #spellListSaveDCInput, input #spellListSaveDCInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
SpellLists.update(this._id, {$set: {saveDC: value}});
|
||||
},
|
||||
"change #spellListAttackBonusInput, input #spellListAttackBonusInput":
|
||||
function(event){
|
||||
var value = event.currentTarget.value;
|
||||
SpellLists.update(this._id, {$set: {attackBonus: value}});
|
||||
},
|
||||
"change #spellListMaxPreparedInput, input #spellListMaxPreparedInput":
|
||||
function(event){
|
||||
var value = event.currentTarget.value;
|
||||
SpellLists.update(this._id, {$set: {maxPrepared: value}});
|
||||
},
|
||||
"change #spellListDescriptionInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
SpellLists.update(this._id, {$set: {description: value}});
|
||||
},
|
||||
});
|
||||
|
||||
Template.spellListDialog.helpers({
|
||||
spellList: function(){
|
||||
return SpellLists.findOne(this.spellListId);
|
||||
}
|
||||
});
|
||||
89
rpg-docs/client/views/private/character/spells/spells.css
Normal file
89
rpg-docs/client/views/private/character/spells/spells.css
Normal file
@@ -0,0 +1,89 @@
|
||||
#spells .containerMain {
|
||||
padding: 0 0 16px 0;
|
||||
}
|
||||
|
||||
#spells .inventoryItem {
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
#spells .inventoryItem core-icon{
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
#spells .inventoryItem[disabled] {
|
||||
color: #ccc !important;
|
||||
color: rgba(0,0,0,0.26) !important;
|
||||
pointer-events: initial !important;
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
#spells .inventoryItem[disabled] core-icon{
|
||||
color: #ccc !important;
|
||||
color: rgba(0,0,0,0.26) !important;
|
||||
}
|
||||
|
||||
#spells .inventoryItem paper-checkbox{
|
||||
pointer-events: initial !important;
|
||||
}
|
||||
|
||||
#spells paper-checkbox /deep/ #ink {
|
||||
color: #009688;
|
||||
}
|
||||
|
||||
#spells .inventoryItem.spellSlot {
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.slotName {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.slotBubble {
|
||||
pointer-events: initial !important;
|
||||
}
|
||||
|
||||
.slotBubble {
|
||||
color: #000;
|
||||
color: rgba(0,0,0,0.54);
|
||||
}
|
||||
|
||||
.slotBubble[disabled] {
|
||||
color: #cccccc;
|
||||
color: rgba(0,0,0,0.26);
|
||||
}
|
||||
|
||||
.spellsContainer{
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.card.spellList {
|
||||
min-width: 280px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
.card.spellSlotContainer {
|
||||
width: initial;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
.spellList .containerMain {
|
||||
-ms-column-width: 300px;
|
||||
-webkit-column-width: 300px;
|
||||
-moz-column-width: 300px;
|
||||
column-width: 300px;
|
||||
-ms-column-gap: 8px;
|
||||
-webkit-column-gap: 8px;
|
||||
-moz-column-gap: 8px;
|
||||
column-gap: 8px;
|
||||
-moz-column-fill: balance;
|
||||
column-fill: balance;
|
||||
}
|
||||
|
||||
.spellLevel {
|
||||
-webkit-backface-visibility: hidden;
|
||||
-webkit-transform: translateX(0);
|
||||
-webkit-column-break-inside: avoid;
|
||||
page-break-inside: avoid;
|
||||
break-inside: avoid;
|
||||
}
|
||||
147
rpg-docs/client/views/private/character/spells/spells.html
Normal file
147
rpg-docs/client/views/private/character/spells/spells.html
Normal file
@@ -0,0 +1,147 @@
|
||||
<template name="spells">
|
||||
<div fit>
|
||||
<div id="spells" class="scroll-y" fit>
|
||||
<div style="padding: 4px;"
|
||||
layout horizontal start wrap>
|
||||
{{#if hasSlots}}
|
||||
<paper-shadow class="card"
|
||||
style="margin: 4px;"
|
||||
hero-id="main" {{detailHero}}>
|
||||
<div class="white top subhead"
|
||||
layout horizontal center>
|
||||
Spell Slots
|
||||
</div>
|
||||
<div class="bottom list">
|
||||
{{#each levels}}{{#if showSlots ..}}
|
||||
<div class="item-slot">
|
||||
<div class="item spellSlot"
|
||||
hero-id="main" {{detailHero slotStatName ../_id}}
|
||||
layout horizontal center>
|
||||
<div style="margin-right: 16px">
|
||||
{{name}}
|
||||
</div>
|
||||
<div flex layout horizontal center>
|
||||
{{#each slotBubbles ..}}
|
||||
<paper-icon-button class="slotBubble"
|
||||
icon={{icon}}
|
||||
disabled={{disabled}}>
|
||||
</paper-icon-button>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
{{/if}}
|
||||
{{#each spellLists}}
|
||||
<paper-shadow class="card spellList" flex
|
||||
hero-id="main" {{detailHero}}
|
||||
style="margin: 4px;">
|
||||
<div class="top {{colorClass}}"
|
||||
hero-id="toolbar" {{detailHero}}
|
||||
layout horizontal center>
|
||||
<div flex>
|
||||
<div class="subhead">{{name}}</div>
|
||||
<div class="caption">
|
||||
{{#if saveDC}}
|
||||
<span style="margin-right: 16px;">
|
||||
Save DC: {{evaluate charId saveDC}}
|
||||
</span>
|
||||
{{/if}}
|
||||
{{#if attackBonus}}
|
||||
<span>
|
||||
Attack Bonus: {{evaluateSigned charId attackBonus}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{#if settings.showUnprepared}}
|
||||
{{#if maxPrepared}}
|
||||
<div class="subhead">
|
||||
{{numPrepared}} / {{evaluate charId maxPrepared}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<core-tooltip label="Done"
|
||||
position="left">
|
||||
<paper-icon-button class="finishPrep"
|
||||
icon="done">
|
||||
</paper-icon-button>
|
||||
</core-tooltip>
|
||||
{{else}}
|
||||
<core-tooltip label="Change prepared spells"
|
||||
position="left">
|
||||
<paper-icon-button class="prepSpells"
|
||||
disabled={{#unless canEditCharacter charId}}true{{/unless}}
|
||||
icon="book">
|
||||
</paper-icon-button>
|
||||
</core-tooltip>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="bottom list column-container">
|
||||
{{#each levels}}
|
||||
<div class="spellLevel">
|
||||
{{#if spellCount .. ../../_id}}
|
||||
<div class="subhead">
|
||||
{{name}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#each spells ../_id ../../_id}}
|
||||
{{#if showSpell ../../settings.showUnprepared}}
|
||||
<div class="item-slot">
|
||||
<div class="tall spell item"
|
||||
hero-id="main" {{detailHero}}
|
||||
layout horizontal center>
|
||||
<core-icon icon="social:whatshot"
|
||||
style="color: {{hexColor color}};
|
||||
margin-right: 16px;"
|
||||
></core-icon>
|
||||
<div flex layout vertical>
|
||||
<div>{{name}}</div>
|
||||
<div class="caption">
|
||||
{{school}}
|
||||
{{castingTime}}
|
||||
{{#if ritual}}
|
||||
(ritual)
|
||||
{{/if}}
|
||||
{{#if spellComponents}}
|
||||
- {{spellComponents}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{#if ../../settings.showUnprepared}}
|
||||
<paper-checkbox class="preparedCheckbox"
|
||||
checked={{isPrepared}}
|
||||
disabled={{cantUnprepare}}>
|
||||
</paper-checkbox>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="fab-buffer"></div>
|
||||
</div>
|
||||
</div>
|
||||
{{#if canEditCharacter _id}}
|
||||
{{#fabMenu}}
|
||||
<core-tooltip label="New spell list" position="left">
|
||||
<paper-fab icon="work"
|
||||
class="addSpellList"
|
||||
mini>
|
||||
</paper-fab>
|
||||
</core-tooltip>
|
||||
<core-tooltip label="New spell" position="left">
|
||||
<paper-fab icon="note-add"
|
||||
class="addSpell"
|
||||
mini>
|
||||
</paper-fab>
|
||||
</core-tooltip>
|
||||
{{/fabMenu}}
|
||||
{{/if}}
|
||||
</template>
|
||||
239
rpg-docs/client/views/private/character/spells/spells.js
Normal file
239
rpg-docs/client/views/private/character/spells/spells.js
Normal file
@@ -0,0 +1,239 @@
|
||||
var spellLevels = [
|
||||
{name: "Cantrips", level: 0},
|
||||
{name: "Level 1", level: 1},
|
||||
{name: "Level 2", level: 2},
|
||||
{name: "Level 3", level: 3},
|
||||
{name: "Level 4", level: 4},
|
||||
{name: "Level 5", level: 5},
|
||||
{name: "Level 6", level: 6},
|
||||
{name: "Level 7", level: 7},
|
||||
{name: "Level 8", level: 8},
|
||||
{name: "Level 9", level: 9},
|
||||
];
|
||||
|
||||
Template.spells.helpers({
|
||||
spellLists: function(){
|
||||
return SpellLists.find({charId: this._id}, {sort: {color: 1, name: 1}});
|
||||
},
|
||||
spellCount: function(list, charId){
|
||||
if (!list || !list.settings) return;
|
||||
if (list.settings.showUnprepared){
|
||||
return Spells.find(
|
||||
{charId: charId, "parent.id": list._id, level: this.level},
|
||||
{fields: {_id: 1, level: 1}}
|
||||
).count() > 0;
|
||||
} else {
|
||||
return Spells.find(
|
||||
{
|
||||
charId: charId,
|
||||
"parent.id": list._id,
|
||||
level: this.level,
|
||||
prepared: {$in: ["prepared", "always"]},
|
||||
},
|
||||
{fields: {_id: 1, level: 1}}
|
||||
).count() > 0;
|
||||
}
|
||||
},
|
||||
spells: function(listId, charId){
|
||||
return Spells.find(
|
||||
{charId: charId, "parent.id": listId, level: this.level},
|
||||
{sort: {color: 1, name: 1}}
|
||||
);
|
||||
},
|
||||
levels: function(){
|
||||
return spellLevels;
|
||||
},
|
||||
numPrepared: function(){
|
||||
return Spells.find({
|
||||
charId: Template.parentData()._id,
|
||||
"parent.id": this._id,
|
||||
prepared: "prepared",
|
||||
}).count();
|
||||
},
|
||||
order: function(){
|
||||
return _.indexOf(_.keys(colorOptions), this.color);
|
||||
},
|
||||
spellComponents: function(){
|
||||
var components = "";
|
||||
if (this.components.verbal){
|
||||
components += "V";
|
||||
}
|
||||
if (this.components.somatic){
|
||||
components += components ? ", S" : "S";
|
||||
}
|
||||
if (this.components.material){
|
||||
components += components ? ", M" : "M";
|
||||
}
|
||||
if (this.components.concentration){
|
||||
components += components ? ", C" : "C";
|
||||
}
|
||||
return components;
|
||||
},
|
||||
isPrepared: function(){
|
||||
return this.prepared === "prepared" || this.prepared === "always";
|
||||
},
|
||||
showSpell: function(listShowPrepped){
|
||||
if (listShowPrepped) {
|
||||
return true;
|
||||
} else {
|
||||
return this.prepared === "prepared" || this.prepared === "always";
|
||||
}
|
||||
},
|
||||
cantUnprepare: function(){
|
||||
return this.prepared === "always";
|
||||
},
|
||||
cantCast: function(level, char){
|
||||
for (var i = level; i <= 9; i++){
|
||||
if (Characters.calculate.attributeValue(char._id, "level" + i + "SpellSlots") > 0){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
showSlots: function(char){
|
||||
return this.level && Characters.calculate.attributeBase(
|
||||
char._id, "level" + this.level + "SpellSlots"
|
||||
);
|
||||
},
|
||||
hasSlots: function(){
|
||||
for (var i = 1; i <= 9; i += 1){
|
||||
if (Characters.calculate.attributeBase(this._id, "level" + i + "SpellSlots")){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
slotBubbles: function(char){
|
||||
var baseSlots = Characters.calculate.attributeBase(char._id, "level" + this.level + "SpellSlots");
|
||||
var currentSlots = Characters.calculate.attributeValue(char._id, "level" + this.level + "SpellSlots");
|
||||
var slotsUsed = baseSlots - currentSlots;
|
||||
var bubbles = [];
|
||||
var i;
|
||||
for (i = 0; i < currentSlots; i++){
|
||||
bubbles.push({
|
||||
icon: "radio-button-on",
|
||||
disabled: i !== currentSlots - 1 || !canEditCharacter(char._id), //last full slot not disabled
|
||||
attribute: "level" + this.level + "SpellSlots",
|
||||
charId: char._id,
|
||||
});
|
||||
}
|
||||
for (i = 0; i < slotsUsed; i++){
|
||||
bubbles.push({
|
||||
icon: "radio-button-off",
|
||||
disabled: i !== 0 || !canEditCharacter(char._id), //first empty slot not disabled
|
||||
attribute: "level" + this.level + "SpellSlots",
|
||||
charId: char._id,
|
||||
});
|
||||
}
|
||||
return bubbles;
|
||||
},
|
||||
slotStatName: function() {
|
||||
return "level" + this.level + "SpellSlots";
|
||||
},
|
||||
});
|
||||
|
||||
Template.spells.events({
|
||||
"tap .slotBubble": function(event){
|
||||
var modifier;
|
||||
if (!event.currentTarget.disabled){
|
||||
var char = Characters.findOne(this.charId);
|
||||
if (event.currentTarget.icon === "radio-button-off"){
|
||||
if (
|
||||
Characters.calculate.attributeValue(char._id, this.attribute) <
|
||||
Characters.calculate.attributeBase(char._id, this.attribute)
|
||||
){
|
||||
modifier = {$inc: {}};
|
||||
modifier.$inc[this.attribute + ".adjustment"] = 1;
|
||||
Characters.update(this.charId, modifier, {validate: false});
|
||||
}
|
||||
} else {
|
||||
if (Characters.calculate.attributeValue(char._id, this.attribute) > 0){
|
||||
modifier = {$inc: {}};
|
||||
modifier.$inc[this.attribute + ".adjustment"] = -1;
|
||||
Characters.update(this.charId, modifier, {validate: false});
|
||||
}
|
||||
}
|
||||
}
|
||||
event.stopPropagation();
|
||||
},
|
||||
"tap .spellSlot": function(event, instance) {
|
||||
var name = "Level " + this.level + " Spell Slots";
|
||||
var stat = "level" + this.level + "SpellSlots";
|
||||
var charId = instance.data._id;
|
||||
GlobalUI.setDetail({
|
||||
template: "attributeDialog",
|
||||
data: {name: name, statName: stat, charId: charId},
|
||||
heroId: charId + stat,
|
||||
});
|
||||
},
|
||||
"tap .spellList .top": function(event){
|
||||
GlobalUI.setDetail({
|
||||
template: "spellListDialog",
|
||||
data: {spellListId: this._id, charId: this.charId},
|
||||
heroId: this._id,
|
||||
});
|
||||
},
|
||||
"tap .spell": function(event){
|
||||
GlobalUI.setDetail({
|
||||
template: "spellDialog",
|
||||
data: {spellId: this._id, charId: this.charId},
|
||||
heroId: this._id,
|
||||
});
|
||||
},
|
||||
"tap .addSpellList": function(event){
|
||||
var charId = this.charId;
|
||||
SpellLists.insert({
|
||||
name: "New SpellList",
|
||||
charId: this._id,
|
||||
saveDC: "8 + intelligenceMod + proficiencyBonus",
|
||||
attackBonus: "intelligenceMod + proficiencyBonus",
|
||||
}, function(error, id){
|
||||
if (!error){
|
||||
GlobalUI.setDetail({
|
||||
template: "spellListDialog",
|
||||
data: {spellListId: id, charId: charId, startEditing: true},
|
||||
heroId: id,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
"tap .addSpell": function(event){
|
||||
var charId = this.charId;
|
||||
var listId = SpellLists.findOne({charId: this._id})._id;
|
||||
Spells.insert({
|
||||
name: "New Spell",
|
||||
charId: this._id,
|
||||
parent: {
|
||||
id: listId,
|
||||
collection: "SpellLists",
|
||||
},
|
||||
prepared: "prepared",
|
||||
}, function(error, id){
|
||||
if (!error){
|
||||
GlobalUI.setDetail({
|
||||
template: "spellDialog",
|
||||
data: {spellId: id, charId: charId, startEditing: true},
|
||||
heroId: id,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
"tap .preparedCheckbox": function(event){
|
||||
event.stopPropagation();
|
||||
},
|
||||
"change .preparedCheckbox": function(event){
|
||||
var value = event.currentTarget.checked;
|
||||
if (this.prepared === "unprepared" && value)
|
||||
Spells.update(this._id, {$set: {prepared: "prepared"}});
|
||||
else if (this.prepared === "prepared" && !value)
|
||||
Spells.update(this._id, {$set: {prepared: "unprepared"}});
|
||||
},
|
||||
"tap .prepSpells": function(event){
|
||||
SpellLists.update(this._id, {$set: {"settings.showUnprepared": true}});
|
||||
event.stopPropagation();
|
||||
},
|
||||
"tap .finishPrep": function(event){
|
||||
SpellLists.update(this._id, {$set: {"settings.showUnprepared": false}});
|
||||
event.stopPropagation();
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
<template name="abilityMiniCard">
|
||||
<div>
|
||||
<paper-shadow class="card abilityMiniCard clickable"
|
||||
hero-id="main" {{detailHero ability ../_id}}
|
||||
layout horizontal>
|
||||
<div class="left white-text {{color}}"
|
||||
hero-id="toolbar" {{detailHero ability ../_id}}>
|
||||
<div class="display1">{{characterCalculate "attributeValue" ../_id ability}}</div>
|
||||
<div class="title">{{abilityMod}}</div>
|
||||
</div>
|
||||
<div class="right subhead" layout horizontal center>
|
||||
{{title}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,9 @@
|
||||
Template.abilityMiniCard.helpers({
|
||||
abilityMod: function() {
|
||||
return signedString(
|
||||
Characters.calculate.abilityMod(
|
||||
Template.parentData()._id, this.ability
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
<!-- data just needs charId -->
|
||||
<template name="addTHPDialog">
|
||||
<div style="width: 200px; height: 150px;">
|
||||
<paper-input id="nameInput" label="Label"></paper-input>
|
||||
<paper-input-decorator label="Quantity" floatinglabel>
|
||||
<input autoFocus id="quantityInput" type="number" value="10">
|
||||
</paper-input-decorator>
|
||||
<div layout horizontal justify-center>
|
||||
Delete when zero <paper-checkbox id="deleteWhenZeroCheckbox" checked style="margin-left: 8px;"></paper-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
<paper-button id="cancelButton" affirmative> Cancel </paper-button>
|
||||
<paper-button id="addButton" affirmative> Add </paper-button>
|
||||
</template>
|
||||
@@ -0,0 +1,12 @@
|
||||
Template.addTHPDialog.events({
|
||||
"tap #addButton": function(event, instance){
|
||||
var max = +instance.find("#quantityInput").value;
|
||||
if (!max || max < 0) max = 0;
|
||||
TemporaryHitPoints.insert({
|
||||
charId: this.charId,
|
||||
name: instance.find("#nameInput").value,
|
||||
maximum: max,
|
||||
deleteOnZero: !!instance.find("#deleteWhenZeroCheckbox").checked,
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
<!-- needs name, char, and statName -->
|
||||
<template name="attributeDialog">
|
||||
{{#baseDialog title=name class=color hideEdit=true}}
|
||||
{{> attributeDialogView}}
|
||||
{{/baseDialog}}
|
||||
</template>
|
||||
|
||||
<template name="attributeDialogView">
|
||||
<div layout horizontal center-justified end>
|
||||
<div class="display2">
|
||||
{{attributeValue}}
|
||||
</div>
|
||||
{{#if adjustment}}
|
||||
<div class="display1">
|
||||
/{{attributeBase}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<hr class="vertMargin">
|
||||
|
||||
<table class="summaryTable">
|
||||
{{#each baseEffects}}
|
||||
<tr>
|
||||
<td>{{sourceName}}</td>
|
||||
<td>Base: {{statValue}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{#each addEffects}}
|
||||
<tr>
|
||||
<td>{{sourceName}}</td>
|
||||
<td>{{signedString statValue}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{#each mulEffects}}
|
||||
<tr>
|
||||
<td>{{sourceName}}</td>
|
||||
<td>× {{statValue}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{#each minEffects}}
|
||||
<tr>
|
||||
<td>{{sourceName}}</td>
|
||||
<td>Min: {{statValue}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{#each maxEffects}}
|
||||
<tr>
|
||||
<td>{{sourceName}}</td>
|
||||
<td>Max: {{statValue}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{#if adjustment}}
|
||||
<tr class="body2">
|
||||
<td>Base Value</td>
|
||||
<td>{{attributeBase}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adjustment</td>
|
||||
<td>{{signedString adjustment}}</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
<tr class="body2">
|
||||
<td>Total</td>
|
||||
<td>{{attributeValue}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</template>
|
||||
@@ -0,0 +1,160 @@
|
||||
//TODO add dexterity armor
|
||||
var stats = {
|
||||
"strength":{"name":"Strength"},
|
||||
"dexterity":{"name":"Dexterity"},
|
||||
"constitution":{"name":"Constitution"},
|
||||
"intelligence":{"name":"Intelligence"},
|
||||
"wisdom":{"name":"Wisdom"},
|
||||
"charisma":{"name":"Charisma"},
|
||||
"strengthSave":{"name":"Strength Save"},
|
||||
"dexteritySave":{"name":"Dexterity Save"},
|
||||
"constitutionSave":{"name":"Constitution Save"},
|
||||
"intelligenceSave":{"name":"Intelligence Save"},
|
||||
"wisdomSave":{"name":"Wisdom Save"},
|
||||
"charismaSave":{"name":"Charisma Save"},
|
||||
"acrobatics":{"name":"Acrobatics"},
|
||||
"animalHandling":{"name":"Animal Handling"},
|
||||
"arcana":{"name":"Arcana"},
|
||||
"athletics":{"name":"Athletics"},
|
||||
"deception":{"name":"Deception"},
|
||||
"history":{"name":"History"},
|
||||
"insight":{"name":"Insight"},
|
||||
"intimidation":{"name":"Intimidation"},
|
||||
"investigation":{"name":"Investigation"},
|
||||
"medicine":{"name":"Medicine"},
|
||||
"nature":{"name":"Nature"},
|
||||
"perception":{"name":"Perception"},
|
||||
"performance":{"name":"Performance"},
|
||||
"persuasion":{"name":"Persuasion"},
|
||||
"religion":{"name":"Religion"},
|
||||
"sleightOfHand":{"name":"Sleight of Hand"},
|
||||
"stealth":{"name":"Stealth"},
|
||||
"survival":{"name":"Survival"},
|
||||
"initiative":{"name":"Initiative"},
|
||||
"hitPoints":{"name":"Hit Points"},
|
||||
"armor":{"name":"Armor"},
|
||||
"dexterityArmor":{"name":"Dexterity Armor Bonus"},
|
||||
"speed":{"name":"Speed"},
|
||||
"proficiencyBonus":{"name":"Proficiency Bonus"},
|
||||
"ki":{"name":"Ki Points"},
|
||||
"sorceryPoints":{"name":"Sorcery Points"},
|
||||
"rages":{"name":"Rages"},
|
||||
"rageDamage":{"name":"Rage Damage"},
|
||||
"expertiseDice":{"name":"Expertise Dice"},
|
||||
"superiorityDice":{"name":"Superiority Dice"},
|
||||
"level1SpellSlots":{"name":"level 1 Spell Slots"},
|
||||
"level2SpellSlots":{"name":"level 2 Spell Slots"},
|
||||
"level3SpellSlots":{"name":"level 3 Spell Slots"},
|
||||
"level4SpellSlots":{"name":"level 4 Spell Slots"},
|
||||
"level5SpellSlots":{"name":"level 5 Spell Slots"},
|
||||
"level6SpellSlots":{"name":"level 6 Spell Slots"},
|
||||
"level7SpellSlots":{"name":"level 7 Spell Slots"},
|
||||
"level8SpellSlots":{"name":"level 8 Spell Slots"},
|
||||
"level9SpellSlots":{"name":"level 9 Spell Slots"},
|
||||
"d6HitDice":{"name":"d6 Hit Dice"},
|
||||
"d8HitDice":{"name":"d8 Hit Dice"},
|
||||
"d10HitDice":{"name":"d10 Hit Dice"},
|
||||
"d12HitDice":{"name":"d12 Hit Dice"},
|
||||
"acidMultiplier":{"name":"Acid", "group": "Weakness/Resistance"},
|
||||
"bludgeoningMultiplier":{"name":"Bludgeoning", "group": "Weakness/Resistance"},
|
||||
"coldMultiplier":{"name":"Cold", "group": "Weakness/Resistance"},
|
||||
"fireMultiplier":{"name":"Fire", "group": "Weakness/Resistance"},
|
||||
"forceMultiplier":{"name":"Force", "group": "Weakness/Resistance"},
|
||||
"lightningMultiplier":{"name":"Lightning", "group": "Weakness/Resistance"},
|
||||
"necroticMultiplier":{"name":"Necrotic", "group": "Weakness/Resistance"},
|
||||
"piercingMultiplier":{"name":"Piercing", "group": "Weakness/Resistance"},
|
||||
"poisonMultiplier":{"name":"Poison", "group": "Weakness/Resistance"},
|
||||
"psychicMultiplier":{"name":"Psychic", "group": "Weakness/Resistance"},
|
||||
"radiantMultiplier":{"name":"Radiant", "group": "Weakness/Resistance"},
|
||||
"slashingMultiplier":{"name":"Slashing", "group": "Weakness/Resistance"},
|
||||
"thunderMultiplier":{"name":"Thunder", "group": "Weakness/Resistance"},
|
||||
};
|
||||
|
||||
var operations = {
|
||||
base: {name: "Base Value"},
|
||||
proficiency: {name: "Proficiency"},
|
||||
add: {name: "+"},
|
||||
mul: {name: "×"},
|
||||
min: {name: "Min"},
|
||||
max: {name: "Max"},
|
||||
advantage: {name: "Advantage"},
|
||||
disadvantage: {name: "Disadvantage"},
|
||||
passiveAdd: {name: "Passive Bonus"},
|
||||
fail: {name: "Automatically Fail"},
|
||||
conditional: {name: "Conditional Benefit"},
|
||||
};
|
||||
|
||||
var abilities = {
|
||||
strength: {name: "Strength"},
|
||||
dexterity: {name: "Dexterity"},
|
||||
constitution: {name: "Constitution"},
|
||||
intelligence: {name: "Intelligence"},
|
||||
wisdom: {name: "Wisdom"},
|
||||
charisma: {name: "Charisma"},
|
||||
};
|
||||
|
||||
Template.attributeDialog.helpers({
|
||||
color: function(){
|
||||
if (this.color) return this.color + " white-text";
|
||||
var char = Characters.findOne(this.charId, {fields: {color: 1}});
|
||||
if (char) return getColorClass(char.color);
|
||||
},
|
||||
});
|
||||
|
||||
Template.attributeDialogView.helpers({
|
||||
or: function(a, b, c){
|
||||
return a || b || c;
|
||||
},
|
||||
adjustment: function(){
|
||||
var value = Characters.calculate.attributeValue(this.charId, this.statName);
|
||||
var base = Characters.calculate.attributeBase(this.charId, this.statName);
|
||||
return value - base;
|
||||
},
|
||||
baseEffects: function(){
|
||||
return Effects.find(
|
||||
{charId: this.charId, stat: this.statName, operation: "base", enabled: true}
|
||||
);
|
||||
},
|
||||
addEffects: function(){
|
||||
return Effects.find(
|
||||
{charId: this.charId, stat: this.statName, operation: "add", enabled: true}
|
||||
);
|
||||
},
|
||||
mulEffects: function(){
|
||||
return Effects.find(
|
||||
{charId: this.charId, stat: this.statName, operation: "mul", enabled: true}
|
||||
);
|
||||
},
|
||||
minEffects: function(){
|
||||
return Effects.find(
|
||||
{charId: this.charId, stat: this.statName, operation: "min", enabled: true}
|
||||
);
|
||||
},
|
||||
maxEffects: function(){
|
||||
return Effects.find(
|
||||
{charId: this.charId, stat: this.statName, operation: "max", enabled: true}
|
||||
);
|
||||
},
|
||||
attributeBase: function(){
|
||||
return Characters.calculate.attributeBase(this.charId, this.statName);
|
||||
},
|
||||
attributeValue: function() {
|
||||
return Characters.calculate.attributeValue(this.charId, this.statName);
|
||||
},
|
||||
sourceName: function(){
|
||||
if (this.parent.group === "racial"){
|
||||
return this.getParent().race;
|
||||
}
|
||||
if (this.parent.collection === "Characters"){
|
||||
return this.name;
|
||||
}
|
||||
return this.getParent().name;
|
||||
},
|
||||
operationName: function(){
|
||||
var op = operations[this.operation];
|
||||
return op && op.name || "No Operation";
|
||||
},
|
||||
statValue: function(){
|
||||
return evaluateEffect(this.charId, this);
|
||||
},
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user