diff --git a/app/imports/api/creature/creatureFolders/CreatureFolders.js b/app/imports/api/creature/creatureFolders/CreatureFolders.js
index dc411ec6..e0e784cc 100644
--- a/app/imports/api/creature/creatureFolders/CreatureFolders.js
+++ b/app/imports/api/creature/creatureFolders/CreatureFolders.js
@@ -4,33 +4,33 @@ import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
let CreatureFolders = new Mongo.Collection('creatureFolders');
let creatureFolderSchema = new SimpleSchema({
- name: {
- type: String,
- trim: false,
- optional: true,
- max: STORAGE_LIMITS.name,
- },
- creatures: {
- type: Array,
- defaultValue: [],
- },
- 'creatures.$': {
- type: String,
- regEx: SimpleSchema.RegEx.Id,
- },
- owner: {
- type: String,
- regEx: SimpleSchema.RegEx.Id,
- index: 1,
- },
- archived: {
- type: Boolean,
- optional: true,
- },
- order: {
- type: Number,
- defaultValue: 0,
- },
+ name: {
+ type: String,
+ trim: false,
+ optional: true,
+ max: STORAGE_LIMITS.name,
+ },
+ creatures: {
+ type: Array,
+ defaultValue: [],
+ },
+ 'creatures.$': {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id,
+ },
+ owner: {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id,
+ index: 1,
+ },
+ archived: {
+ type: Boolean,
+ optional: true,
+ },
+ order: {
+ type: Number,
+ defaultValue: 0,
+ },
});
CreatureFolders.attachSchema(creatureFolderSchema);
diff --git a/app/imports/api/creature/journal/JournalEntry.js b/app/imports/api/creature/journal/JournalEntry.js
index 5e65cb2b..74b885ea 100644
--- a/app/imports/api/creature/journal/JournalEntry.js
+++ b/app/imports/api/creature/journal/JournalEntry.js
@@ -2,49 +2,49 @@ import SimpleSchema from 'simpl-schema';
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
let ExperienceSchema = new SimpleSchema({
- title: {
- type: String,
- optional: true,
- max: STORAGE_LIMITS.name,
- },
- // Potentially long description of the event
- description: {
- type: String,
- optional: true,
- max: STORAGE_LIMITS.description,
- },
- // The real-world date that it occured
- date: {
- type: Date,
- autoValue: function () {
- // If the date isn't set, set it to now
- if (!this.isSet) {
- return new Date();
- }
- },
- },
- // The date in-world of this event
- worldDate: {
- type: String,
- optional: true,
- max: STORAGE_LIMITS.name,
- },
- // Tags to better find this entry later
- tags: {
- type: Array,
- defaultValue: [],
- maxCount: STORAGE_LIMITS.tagCount,
- },
- 'tags.$': {
- type: String,
- max: STORAGE_LIMITS.tagLength,
- },
- // ID of the journal this entry belongs to
- journalId: {
- type: String,
- regEx: SimpleSchema.RegEx.Id,
- index: 1,
- }
+ title: {
+ type: String,
+ optional: true,
+ max: STORAGE_LIMITS.name,
+ },
+ // Potentially long description of the event
+ description: {
+ type: String,
+ optional: true,
+ max: STORAGE_LIMITS.description,
+ },
+ // The real-world date that it occured
+ date: {
+ type: Date,
+ autoValue: function () {
+ // If the date isn't set, set it to now
+ if (!this.isSet) {
+ return new Date();
+ }
+ },
+ },
+ // The date in-world of this event
+ worldDate: {
+ type: String,
+ optional: true,
+ max: STORAGE_LIMITS.name,
+ },
+ // Tags to better find this entry later
+ tags: {
+ type: Array,
+ defaultValue: [],
+ maxCount: STORAGE_LIMITS.tagCount,
+ },
+ 'tags.$': {
+ type: String,
+ max: STORAGE_LIMITS.tagLength,
+ },
+ // ID of the journal this entry belongs to
+ journalId: {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id,
+ index: 1,
+ }
});
export { ExperienceSchema };
diff --git a/app/imports/api/library/Libraries.js b/app/imports/api/library/Libraries.js
index 1e46c672..696f0001 100644
--- a/app/imports/api/library/Libraries.js
+++ b/app/imports/api/library/Libraries.js
@@ -20,15 +20,15 @@ import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
let Libraries = new Mongo.Collection('libraries');
let LibrarySchema = new SimpleSchema({
- name: {
- type: String,
- max: STORAGE_LIMITS.name,
- },
- description: {
- type: String,
- optional: true,
- max: STORAGE_LIMITS.summary,
- },
+ name: {
+ type: String,
+ max: STORAGE_LIMITS.name,
+ },
+ description: {
+ type: String,
+ optional: true,
+ max: STORAGE_LIMITS.summary,
+ },
});
LibrarySchema.extend(SharingSchema);
@@ -38,96 +38,96 @@ Libraries.attachSchema(LibrarySchema);
export default Libraries;
const insertLibrary = new ValidatedMethod({
- name: 'libraries.insert',
- mixins: [
- simpleSchemaMixin,
- ],
- schema: LibrarySchema.omit('owner'),
- run(library) {
- if (!this.userId) {
- throw new Meteor.Error('Libraries.methods.insert.denied',
- 'You need to be logged in to insert a library');
- }
- let tier = getUserTier(this.userId);
- if (!tier.paidBenefits) {
- throw new Meteor.Error('Libraries.methods.insert.denied',
- `The ${tier.name} tier does not allow you to insert a library`);
- }
- library.owner = this.userId;
- return Libraries.insert(library);
- },
+ name: 'libraries.insert',
+ mixins: [
+ simpleSchemaMixin,
+ ],
+ schema: LibrarySchema.omit('owner'),
+ run(library) {
+ if (!this.userId) {
+ throw new Meteor.Error('Libraries.methods.insert.denied',
+ 'You need to be logged in to insert a library');
+ }
+ let tier = getUserTier(this.userId);
+ if (!tier.paidBenefits) {
+ throw new Meteor.Error('Libraries.methods.insert.denied',
+ `The ${tier.name} tier does not allow you to insert a library`);
+ }
+ library.owner = this.userId;
+ return Libraries.insert(library);
+ },
});
const updateLibraryName = new ValidatedMethod({
- name: 'libraries.updateName',
- validate: new SimpleSchema({
- _id: {
- type: String,
- regEx: SimpleSchema.RegEx.id
- },
- name: {
- type: String,
- },
- }).validator(),
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run({ _id, name }) {
- let library = Libraries.findOne(_id);
- assertEditPermission(library, this.userId);
- Libraries.update(_id, { $set: { name } });
- },
+ name: 'libraries.updateName',
+ validate: new SimpleSchema({
+ _id: {
+ type: String,
+ regEx: SimpleSchema.RegEx.id
+ },
+ name: {
+ type: String,
+ },
+ }).validator(),
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run({ _id, name }) {
+ let library = Libraries.findOne(_id);
+ assertEditPermission(library, this.userId);
+ Libraries.update(_id, { $set: { name } });
+ },
});
const updateLibraryDescription = new ValidatedMethod({
- name: 'libraries.updateDescription',
- validate: new SimpleSchema({
- _id: {
- type: String,
- regEx: SimpleSchema.RegEx.id
- },
- description: {
- type: String,
- },
- }).validator(),
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run({ _id, description }) {
- let library = Libraries.findOne(_id);
- assertEditPermission(library, this.userId);
- Libraries.update(_id, { $set: { description } });
- },
+ name: 'libraries.updateDescription',
+ validate: new SimpleSchema({
+ _id: {
+ type: String,
+ regEx: SimpleSchema.RegEx.id
+ },
+ description: {
+ type: String,
+ },
+ }).validator(),
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run({ _id, description }) {
+ let library = Libraries.findOne(_id);
+ assertEditPermission(library, this.userId);
+ Libraries.update(_id, { $set: { description } });
+ },
});
const removeLibrary = new ValidatedMethod({
- name: 'libraries.remove',
- validate: new SimpleSchema({
- _id: {
- type: String,
- regEx: SimpleSchema.RegEx.id
- },
- }).validator(),
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run({ _id }) {
- let library = Libraries.findOne(_id);
- assertOwnership(library, this.userId);
- this.unblock();
- removeLibaryWork(_id)
- }
+ name: 'libraries.remove',
+ validate: new SimpleSchema({
+ _id: {
+ type: String,
+ regEx: SimpleSchema.RegEx.id
+ },
+ }).validator(),
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run({ _id }) {
+ let library = Libraries.findOne(_id);
+ assertOwnership(library, this.userId);
+ this.unblock();
+ removeLibaryWork(_id)
+ }
});
export function removeLibaryWork(libraryId) {
- Libraries.remove(libraryId);
- LibraryNodes.remove({ 'ancestors.id': libraryId });
+ Libraries.remove(libraryId);
+ LibraryNodes.remove({ 'ancestors.id': libraryId });
}
export { LibrarySchema, insertLibrary, updateLibraryName, updateLibraryDescription, removeLibrary };
diff --git a/app/imports/api/properties/Buffs.js b/app/imports/api/properties/Buffs.js
index 86584694..386c402b 100644
--- a/app/imports/api/properties/Buffs.js
+++ b/app/imports/api/properties/Buffs.js
@@ -3,79 +3,79 @@ import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
import createPropertySchema from '/imports/api/properties/subSchemas/createPropertySchema.js';
let BuffSchema = createPropertySchema({
- name: {
- type: String,
- optional: true,
- max: STORAGE_LIMITS.name,
- },
- description: {
- type: 'inlineCalculationFieldToCompute',
- optional: true,
- },
- hideRemoveButton: {
- type: Boolean,
- optional: true,
- },
- // How many rounds this buff lasts
- duration: {
- type: 'fieldToCompute',
- optional: true,
- },
- target: {
- type: String,
- allowedValues: [
- 'self',
- 'target',
- ],
- defaultValue: 'target',
- },
- // Prevent the property from showing up in the log
- silent: {
- type: Boolean,
- optional: true,
- },
- // Prevent the children from being crystalized
- skipCrystalization: {
- type: Boolean,
- optional: true,
- },
+ name: {
+ type: String,
+ optional: true,
+ max: STORAGE_LIMITS.name,
+ },
+ description: {
+ type: 'inlineCalculationFieldToCompute',
+ optional: true,
+ },
+ hideRemoveButton: {
+ type: Boolean,
+ optional: true,
+ },
+ // How many rounds this buff lasts
+ duration: {
+ type: 'fieldToCompute',
+ optional: true,
+ },
+ target: {
+ type: String,
+ allowedValues: [
+ 'self',
+ 'target',
+ ],
+ defaultValue: 'target',
+ },
+ // Prevent the property from showing up in the log
+ silent: {
+ type: Boolean,
+ optional: true,
+ },
+ // Prevent the children from being crystalized
+ skipCrystalization: {
+ type: Boolean,
+ optional: true,
+ },
});
let ComputedOnlyBuffSchema = createPropertySchema({
- description: {
- type: 'computedOnlyInlineCalculationField',
- optional: true,
- max: STORAGE_LIMITS.description,
- },
- duration: {
- type: 'computedOnlyField',
- optional: true,
- },
- durationSpent: {
- type: Number,
- optional: true,
- min: 0,
- },
- appliedBy: {
- type: Object,
- optional: true,
- },
- 'appliedBy.name': {
- type: String,
- max: STORAGE_LIMITS.name,
- },
- 'appliedBy.id': {
- type: String,
- regEx: SimpleSchema.RegEx.Id,
- },
- 'appliedBy.collection': {
- type: String,
- max: STORAGE_LIMITS.collectionName,
- },
+ description: {
+ type: 'computedOnlyInlineCalculationField',
+ optional: true,
+ max: STORAGE_LIMITS.description,
+ },
+ duration: {
+ type: 'computedOnlyField',
+ optional: true,
+ },
+ durationSpent: {
+ type: Number,
+ optional: true,
+ min: 0,
+ },
+ appliedBy: {
+ type: Object,
+ optional: true,
+ },
+ 'appliedBy.name': {
+ type: String,
+ max: STORAGE_LIMITS.name,
+ },
+ 'appliedBy.id': {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id,
+ },
+ 'appliedBy.collection': {
+ type: String,
+ max: STORAGE_LIMITS.collectionName,
+ },
});
const ComputedBuffSchema = new SimpleSchema()
- .extend(BuffSchema)
- .extend(ComputedOnlyBuffSchema);
+ .extend(BuffSchema)
+ .extend(ComputedOnlyBuffSchema);
export { BuffSchema, ComputedOnlyBuffSchema, ComputedBuffSchema };
diff --git a/app/imports/api/properties/Containers.js b/app/imports/api/properties/Containers.js
index 565e0be6..6936bd15 100644
--- a/app/imports/api/properties/Containers.js
+++ b/app/imports/api/properties/Containers.js
@@ -3,69 +3,69 @@ import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
import createPropertySchema from '/imports/api/properties/subSchemas/createPropertySchema.js';
let ContainerSchema = createPropertySchema({
- name: {
- type: String,
- optional: true,
- trim: false,
- max: STORAGE_LIMITS.name,
- },
- carried: {
- type: Boolean,
- defaultValue: true,
- optional: true,
- },
- contentsWeightless: {
- type: Boolean,
- optional: true,
- },
- weight: {
- type: Number,
- min: 0,
- optional: true,
- },
- value: {
- type: Number,
- min: 0,
- optional: true,
- },
- description: {
- type: 'inlineCalculationFieldToCompute',
- optional: true,
- },
+ name: {
+ type: String,
+ optional: true,
+ trim: false,
+ max: STORAGE_LIMITS.name,
+ },
+ carried: {
+ type: Boolean,
+ defaultValue: true,
+ optional: true,
+ },
+ contentsWeightless: {
+ type: Boolean,
+ optional: true,
+ },
+ weight: {
+ type: Number,
+ min: 0,
+ optional: true,
+ },
+ value: {
+ type: Number,
+ min: 0,
+ optional: true,
+ },
+ description: {
+ type: 'inlineCalculationFieldToCompute',
+ optional: true,
+ },
});
const ComputedOnlyContainerSchema = createPropertySchema({
- description: {
- type: 'computedOnlyInlineCalculationField',
- optional: true,
- },
- // Weight of all the contents, zero if `contentsWeightless` is true
- contentsWeight: {
- type: Number,
- optional: true,
- removeBeforeCompute: true,
- },
- // Weight of all the carried contents (some sub-containers might not be carried)
- // zero if `contentsWeightless` is true
- carriedWeight: {
- type: Number,
- optional: true,
- removeBeforeCompute: true,
- },
- contentsValue: {
- type: Number,
- optional: true,
- removeBeforeCompute: true,
- },
- carriedValue: {
- type: Number,
- optional: true,
- removeBeforeCompute: true,
- },
+ description: {
+ type: 'computedOnlyInlineCalculationField',
+ optional: true,
+ },
+ // Weight of all the contents, zero if `contentsWeightless` is true
+ contentsWeight: {
+ type: Number,
+ optional: true,
+ removeBeforeCompute: true,
+ },
+ // Weight of all the carried contents (some sub-containers might not be carried)
+ // zero if `contentsWeightless` is true
+ carriedWeight: {
+ type: Number,
+ optional: true,
+ removeBeforeCompute: true,
+ },
+ contentsValue: {
+ type: Number,
+ optional: true,
+ removeBeforeCompute: true,
+ },
+ carriedValue: {
+ type: Number,
+ optional: true,
+ removeBeforeCompute: true,
+ },
});
const ComputedContainerSchema = new SimpleSchema()
- .extend(ComputedOnlyContainerSchema)
- .extend(ContainerSchema);
+ .extend(ComputedOnlyContainerSchema)
+ .extend(ContainerSchema);
export { ContainerSchema, ComputedOnlyContainerSchema, ComputedContainerSchema };
diff --git a/app/imports/api/properties/Items.js b/app/imports/api/properties/Items.js
index 2183d567..a328cfcf 100644
--- a/app/imports/api/properties/Items.js
+++ b/app/imports/api/properties/Items.js
@@ -3,69 +3,69 @@ import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
import createPropertySchema from '/imports/api/properties/subSchemas/createPropertySchema.js';
const ItemSchema = createPropertySchema({
- name: {
- type: String,
- optional: true,
- max: STORAGE_LIMITS.name,
- },
- // Plural name of the item, if there is more than one
- plural: {
- type: String,
- optional: true,
- max: STORAGE_LIMITS.name,
- },
- description: {
- type: 'inlineCalculationFieldToCompute',
- optional: true,
- },
- // Number currently held
- quantity: {
- type: SimpleSchema.Integer,
- min: 0,
- defaultValue: 1
- },
- // Weight per item in the stack
- weight: {
- type: Number,
- min: 0,
- optional: true,
- },
- // Value per item in the stack, in gold pieces
- value: {
- type: Number,
- min: 0,
- optional: true,
- },
- // If this item is equipped, it requires attunement
- requiresAttunement: {
- type: Boolean,
- optional: true,
- },
- attuned: {
- type: Boolean,
- optional: true,
- },
- // Show increment/decrement buttons in item lists
- showIncrement: {
- type: Boolean,
- optional: true,
- },
- // Unequipped items shouldn't affect creature stats
- equipped: {
- type: Boolean,
- defaultValue: false,
- },
+ name: {
+ type: String,
+ optional: true,
+ max: STORAGE_LIMITS.name,
+ },
+ // Plural name of the item, if there is more than one
+ plural: {
+ type: String,
+ optional: true,
+ max: STORAGE_LIMITS.name,
+ },
+ description: {
+ type: 'inlineCalculationFieldToCompute',
+ optional: true,
+ },
+ // Number currently held
+ quantity: {
+ type: SimpleSchema.Integer,
+ min: 0,
+ defaultValue: 1
+ },
+ // Weight per item in the stack
+ weight: {
+ type: Number,
+ min: 0,
+ optional: true,
+ },
+ // Value per item in the stack, in gold pieces
+ value: {
+ type: Number,
+ min: 0,
+ optional: true,
+ },
+ // If this item is equipped, it requires attunement
+ requiresAttunement: {
+ type: Boolean,
+ optional: true,
+ },
+ attuned: {
+ type: Boolean,
+ optional: true,
+ },
+ // Show increment/decrement buttons in item lists
+ showIncrement: {
+ type: Boolean,
+ optional: true,
+ },
+ // Unequipped items shouldn't affect creature stats
+ equipped: {
+ type: Boolean,
+ defaultValue: false,
+ },
});
let ComputedOnlyItemSchema = createPropertySchema({
- description: {
- type: 'computedOnlyInlineCalculationField',
- optional: true,
- },
+ description: {
+ type: 'computedOnlyInlineCalculationField',
+ optional: true,
+ },
});
const ComputedItemSchema = new SimpleSchema()
- .extend(ItemSchema)
- .extend(ComputedOnlyItemSchema);
+ .extend(ItemSchema)
+ .extend(ComputedOnlyItemSchema);
export { ItemSchema, ComputedItemSchema, ComputedOnlyItemSchema };
diff --git a/app/imports/api/properties/Spells.js b/app/imports/api/properties/Spells.js
index bcb4ee3b..575c9b5e 100644
--- a/app/imports/api/properties/Spells.js
+++ b/app/imports/api/properties/Spells.js
@@ -3,99 +3,99 @@ import SimpleSchema from 'simpl-schema';
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
const magicSchools = [
- 'abjuration',
- 'conjuration',
- 'divination',
- 'enchantment',
- 'evocation',
- 'illusion',
- 'necromancy',
- 'transmutation',
+ 'abjuration',
+ 'conjuration',
+ 'divination',
+ 'enchantment',
+ 'evocation',
+ 'illusion',
+ 'necromancy',
+ 'transmutation',
];
let SpellSchema = new SimpleSchema({})
- .extend(ActionSchema)
- .extend({
- name: {
- type: String,
- optional: true,
- max: STORAGE_LIMITS.name,
- },
- // If it's always prepared, it doesn't count against the number of spells
- // prepared in a spell list, and enabled should be true
- alwaysPrepared: {
- type: Boolean,
- optional: true,
- },
- prepared: {
- type: Boolean,
- optional: true,
- },
- // This spell ignores spell slot rules
- castWithoutSpellSlots: {
- type: Boolean,
- optional: true,
- },
- hasAttackRoll: {
- type: Boolean,
- optional: true,
- },
- castingTime: {
- type: String,
- optional: true,
- defaultValue: 'action',
- max: STORAGE_LIMITS.spellDetail,
- },
- range: {
- type: String,
- optional: true,
- max: STORAGE_LIMITS.spellDetail,
- },
- duration: {
- type: String,
- optional: true,
- defaultValue: 'Instantaneous',
- max: STORAGE_LIMITS.spellDetail,
- },
- verbal: {
- type: Boolean,
- optional: true,
- },
- somatic: {
- type: Boolean,
- optional: true,
- },
- concentration: {
- type: Boolean,
- optional: true,
- },
- material: {
- type: String,
- optional: true,
- max: STORAGE_LIMITS.spellDetail,
- },
- ritual: {
- type: Boolean,
- optional: true,
- },
- level: {
- type: SimpleSchema.Integer,
- defaultValue: 1,
- max: 9,
- min: 0,
- },
- school: {
- type: String,
- defaultValue: 'abjuration',
- allowedValues: magicSchools,
- },
- });
+ .extend(ActionSchema)
+ .extend({
+ name: {
+ type: String,
+ optional: true,
+ max: STORAGE_LIMITS.name,
+ },
+ // If it's always prepared, it doesn't count against the number of spells
+ // prepared in a spell list, and enabled should be true
+ alwaysPrepared: {
+ type: Boolean,
+ optional: true,
+ },
+ prepared: {
+ type: Boolean,
+ optional: true,
+ },
+ // This spell ignores spell slot rules
+ castWithoutSpellSlots: {
+ type: Boolean,
+ optional: true,
+ },
+ hasAttackRoll: {
+ type: Boolean,
+ optional: true,
+ },
+ castingTime: {
+ type: String,
+ optional: true,
+ defaultValue: 'action',
+ max: STORAGE_LIMITS.spellDetail,
+ },
+ range: {
+ type: String,
+ optional: true,
+ max: STORAGE_LIMITS.spellDetail,
+ },
+ duration: {
+ type: String,
+ optional: true,
+ defaultValue: 'Instantaneous',
+ max: STORAGE_LIMITS.spellDetail,
+ },
+ verbal: {
+ type: Boolean,
+ optional: true,
+ },
+ somatic: {
+ type: Boolean,
+ optional: true,
+ },
+ concentration: {
+ type: Boolean,
+ optional: true,
+ },
+ material: {
+ type: String,
+ optional: true,
+ max: STORAGE_LIMITS.spellDetail,
+ },
+ ritual: {
+ type: Boolean,
+ optional: true,
+ },
+ level: {
+ type: SimpleSchema.Integer,
+ defaultValue: 1,
+ max: 9,
+ min: 0,
+ },
+ school: {
+ type: String,
+ defaultValue: 'abjuration',
+ allowedValues: magicSchools,
+ },
+ });
const ComputedOnlySpellSchema = new SimpleSchema()
- .extend(ComputedOnlyActionSchema);
+ .extend(ComputedOnlyActionSchema);
const ComputedSpellSchema = new SimpleSchema()
- .extend(SpellSchema)
- .extend(ComputedOnlySpellSchema);
+ .extend(SpellSchema)
+ .extend(ComputedOnlySpellSchema);
export { SpellSchema, ComputedOnlySpellSchema, ComputedSpellSchema };
diff --git a/app/imports/api/properties/subSchemas/ColorSchema.js b/app/imports/api/properties/subSchemas/ColorSchema.js
index f258c269..0597b336 100644
--- a/app/imports/api/properties/subSchemas/ColorSchema.js
+++ b/app/imports/api/properties/subSchemas/ColorSchema.js
@@ -1,12 +1,12 @@
import SimpleSchema from 'simpl-schema';
const ColorSchema = new SimpleSchema({
- color: {
- type: String,
- // match hex colors of the form #A23 or #A23f56
- regEx: /^#([a-f0-9]{3}){1,2}\b$/i,
- optional: true,
- },
+ color: {
+ type: String,
+ // match hex colors of the form #A23 or #A23f56
+ regEx: /^#([a-f0-9]{3}){1,2}\b$/i,
+ optional: true,
+ },
});
export default ColorSchema;
diff --git a/app/imports/api/properties/subSchemas/DeathSavesSchema.js b/app/imports/api/properties/subSchemas/DeathSavesSchema.js
index ea7f2933..b6238544 100644
--- a/app/imports/api/properties/subSchemas/DeathSavesSchema.js
+++ b/app/imports/api/properties/subSchemas/DeathSavesSchema.js
@@ -1,26 +1,26 @@
import SimpleSchema from 'simpl-schema';
const DeathSavesSchema = new SimpleSchema({
- pass: {
- type: SimpleSchema.Integer,
- min: 0,
- max: 3,
- defaultValue: 0,
- },
- fail: {
- type: SimpleSchema.Integer,
- min: 0,
- max: 3,
- defaultValue: 0,
- },
- canDeathSave: {
- type: Boolean,
- defaultValue: true,
- },
- stable: {
- type: Boolean,
- defaultValue: false,
- },
+ pass: {
+ type: SimpleSchema.Integer,
+ min: 0,
+ max: 3,
+ defaultValue: 0,
+ },
+ fail: {
+ type: SimpleSchema.Integer,
+ min: 0,
+ max: 3,
+ defaultValue: 0,
+ },
+ canDeathSave: {
+ type: Boolean,
+ defaultValue: true,
+ },
+ stable: {
+ type: Boolean,
+ defaultValue: false,
+ },
});
export default DeathSavesSchema;
diff --git a/app/imports/api/sharing/SharingSchema.js b/app/imports/api/sharing/SharingSchema.js
index a22da7cd..2a4f87c3 100644
--- a/app/imports/api/sharing/SharingSchema.js
+++ b/app/imports/api/sharing/SharingSchema.js
@@ -3,36 +3,36 @@ import '/imports/api/sharing/sharing.js';
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
let SharingSchema = new SimpleSchema({
- owner: {
- type: String,
- regEx: SimpleSchema.RegEx.Id,
- index: 1
- },
- readers: {
- type: Array,
- defaultValue: [],
- index: 1,
- maxCount: STORAGE_LIMITS.readersCount,
- },
- 'readers.$': {
- type: String,
- regEx: SimpleSchema.RegEx.Id
- },
- writers: {
- type: Array,
- defaultValue: [],
- index: 1,
- maxCount: STORAGE_LIMITS.writersCount,
- },
- 'writers.$': {
- type: String,
- regEx: SimpleSchema.RegEx.Id
- },
- public: {
- type: Boolean,
- defaultValue: false,
- index: 1,
- },
+ owner: {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id,
+ index: 1
+ },
+ readers: {
+ type: Array,
+ defaultValue: [],
+ index: 1,
+ maxCount: STORAGE_LIMITS.readersCount,
+ },
+ 'readers.$': {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id
+ },
+ writers: {
+ type: Array,
+ defaultValue: [],
+ index: 1,
+ maxCount: STORAGE_LIMITS.writersCount,
+ },
+ 'writers.$': {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id
+ },
+ public: {
+ type: Boolean,
+ defaultValue: false,
+ index: 1,
+ },
});
export default SharingSchema;
diff --git a/app/imports/api/users/Users.js b/app/imports/api/users/Users.js
index 40e50311..54328914 100644
--- a/app/imports/api/users/Users.js
+++ b/app/imports/api/users/Users.js
@@ -11,321 +11,321 @@ const defaultLibraries = process.env.DEFAULT_LIBRARIES && process.env.DEFAULT_LI
const defaultLibraryCollections = process.env.DEFAULT_LIBRARY_COLLECTIONS && process.env.DEFAULT_LIBRARY_COLLECTIONS.split(',') || [];
const userSchema = new SimpleSchema({
- username: {
- type: String,
- optional: true,
- max: 30,
- min: 4,
- },
- emails: {
- type: Array,
- optional: true,
- },
- 'emails.$': {
- type: Object,
- },
- 'emails.$.address': {
- type: String,
- regEx: SimpleSchema.RegEx.Email,
- },
- 'emails.$.verified': {
- type: Boolean,
- },
- registered_emails: {
- type: Array,
- optional: true,
- },
- 'registered_emails.$': {
- type: Object,
- blackbox: true,
- },
- createdAt: {
- type: Date
- },
- services: {
- type: Object,
- optional: true,
- blackbox: true,
- },
- roles: {
- type: Array,
- optional: true,
- },
- 'roles.$': {
- type: String
- },
- // In order to avoid an 'Exception in setInterval callback' from Meteor
- heartbeat: {
- type: Date,
- optional: true,
- },
- apiKey: {
- type: String,
- index: 1,
- optional: true,
- },
- darkMode: {
- type: Boolean,
- optional: true,
- },
- subscribedLibraries: {
- type: Array,
- defaultValue: defaultLibraries,
- maxCount: 100,
- },
- 'subscribedLibraries.$': {
- type: String,
- regEx: SimpleSchema.RegEx.Id,
- },
- subscribedLibraryCollections: {
- type: Array,
- defaultValue: defaultLibraryCollections,
- maxCount: 100,
- },
- 'subscribedLibraryCollections.$': {
- type: String,
- regEx: SimpleSchema.RegEx.Id,
- },
- subscribedCharacters: {
- type: Array,
- defaultValue: [],
- max: 100,
- },
- 'subscribedCharacters.$': {
- type: String,
- regEx: SimpleSchema.RegEx.Id,
- },
- fileStorageUsed: {
- type: Number,
- optional: true,
- },
- profile: {
- type: Object,
- blackbox: true,
- optional: true,
- },
- preferences: {
- type: Object,
- optional: true,
- defaultValue: {},
- },
- 'preferences.swapAbilityScoresAndModifiers': {
- type: Boolean,
- optional: true,
- },
- 'preferences.hidePropertySelectDialogHelp': {
- type: Boolean,
- optional: true,
- },
+ username: {
+ type: String,
+ optional: true,
+ max: 30,
+ min: 4,
+ },
+ emails: {
+ type: Array,
+ optional: true,
+ },
+ 'emails.$': {
+ type: Object,
+ },
+ 'emails.$.address': {
+ type: String,
+ regEx: SimpleSchema.RegEx.Email,
+ },
+ 'emails.$.verified': {
+ type: Boolean,
+ },
+ registered_emails: {
+ type: Array,
+ optional: true,
+ },
+ 'registered_emails.$': {
+ type: Object,
+ blackbox: true,
+ },
+ createdAt: {
+ type: Date
+ },
+ services: {
+ type: Object,
+ optional: true,
+ blackbox: true,
+ },
+ roles: {
+ type: Array,
+ optional: true,
+ },
+ 'roles.$': {
+ type: String
+ },
+ // In order to avoid an 'Exception in setInterval callback' from Meteor
+ heartbeat: {
+ type: Date,
+ optional: true,
+ },
+ apiKey: {
+ type: String,
+ index: 1,
+ optional: true,
+ },
+ darkMode: {
+ type: Boolean,
+ optional: true,
+ },
+ subscribedLibraries: {
+ type: Array,
+ defaultValue: defaultLibraries,
+ maxCount: 100,
+ },
+ 'subscribedLibraries.$': {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id,
+ },
+ subscribedLibraryCollections: {
+ type: Array,
+ defaultValue: defaultLibraryCollections,
+ maxCount: 100,
+ },
+ 'subscribedLibraryCollections.$': {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id,
+ },
+ subscribedCharacters: {
+ type: Array,
+ defaultValue: [],
+ max: 100,
+ },
+ 'subscribedCharacters.$': {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id,
+ },
+ fileStorageUsed: {
+ type: Number,
+ optional: true,
+ },
+ profile: {
+ type: Object,
+ blackbox: true,
+ optional: true,
+ },
+ preferences: {
+ type: Object,
+ optional: true,
+ defaultValue: {},
+ },
+ 'preferences.swapAbilityScoresAndModifiers': {
+ type: Boolean,
+ optional: true,
+ },
+ 'preferences.hidePropertySelectDialogHelp': {
+ type: Boolean,
+ optional: true,
+ },
});
Meteor.users.attachSchema(userSchema);
Meteor.users.generateApiKey = new ValidatedMethod({
- name: 'users.generateApiKey',
- validate: null,
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run() {
- if (Meteor.isClient) return;
- var user = Meteor.users.findOne(this.userId);
- if (!user) return;
- if (user && user.apiKey) return;
- var apiKey = Random.id(30);
- Meteor.users.update(this.userId, { $set: { apiKey } });
- },
+ name: 'users.generateApiKey',
+ validate: null,
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run() {
+ if (Meteor.isClient) return;
+ var user = Meteor.users.findOne(this.userId);
+ if (!user) return;
+ if (user && user.apiKey) return;
+ var apiKey = Random.id(30);
+ Meteor.users.update(this.userId, { $set: { apiKey } });
+ },
});
Meteor.users.setDarkMode = new ValidatedMethod({
- name: 'users.setDarkMode',
- validate: new SimpleSchema({
- darkMode: { type: Boolean },
- }).validator(),
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run({ darkMode }) {
- if (!this.userId) return;
- Meteor.users.update(this.userId, { $set: { darkMode } });
- },
+ name: 'users.setDarkMode',
+ validate: new SimpleSchema({
+ darkMode: { type: Boolean },
+ }).validator(),
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run({ darkMode }) {
+ if (!this.userId) return;
+ Meteor.users.update(this.userId, { $set: { darkMode } });
+ },
});
Meteor.users.sendVerificationEmail = new ValidatedMethod({
- name: 'users.sendVerificationEmail',
- validate: new SimpleSchema({
- userId: {
- type: String,
- optional: true,
- },
- address: {
- type: String,
- },
- }).validator(),
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run({ userId, address }) {
- userId = this.userId || userId;
- let user = Meteor.users.findOne(userId);
- if (!user) {
- throw new Meteor.Error('User not found',
- 'Can\'t send a validation email to a user that does not exist');
- }
- if (!some(user.emails, email => email.address === address)) {
- throw new Meteor.Error('Email address not found',
- 'The specified email address wasn\'t found on this user account');
- }
- Accounts.sendVerificationEmail(userId, address);
- }
+ name: 'users.sendVerificationEmail',
+ validate: new SimpleSchema({
+ userId: {
+ type: String,
+ optional: true,
+ },
+ address: {
+ type: String,
+ },
+ }).validator(),
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run({ userId, address }) {
+ userId = this.userId || userId;
+ let user = Meteor.users.findOne(userId);
+ if (!user) {
+ throw new Meteor.Error('User not found',
+ 'Can\'t send a validation email to a user that does not exist');
+ }
+ if (!some(user.emails, email => email.address === address)) {
+ throw new Meteor.Error('Email address not found',
+ 'The specified email address wasn\'t found on this user account');
+ }
+ Accounts.sendVerificationEmail(userId, address);
+ }
});
Meteor.users.canPickUsername = new ValidatedMethod({
- name: 'users.canPickUsername',
- validate: userSchema.pick('username').validator(),
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run({ username }) {
- if (Meteor.isClient) return;
- let user = Accounts.findUserByUsername(username);
- // You can pick your own username
- if (user && user._id === this.userId) {
- return false;
- }
- return !!user;
- }
+ name: 'users.canPickUsername',
+ validate: userSchema.pick('username').validator(),
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run({ username }) {
+ if (Meteor.isClient) return;
+ let user = Accounts.findUserByUsername(username);
+ // You can pick your own username
+ if (user && user._id === this.userId) {
+ return false;
+ }
+ return !!user;
+ }
});
Meteor.users.setUsername = new ValidatedMethod({
- name: 'users.setUsername',
- validate: userSchema.pick('username').validator(),
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run({ username }) {
- if (!this.userId) throw 'Can only set your username if logged in';
- if (Meteor.isClient) return;
- return Accounts.setUsername(this.userId, username)
- }
+ name: 'users.setUsername',
+ validate: userSchema.pick('username').validator(),
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run({ username }) {
+ if (!this.userId) throw 'Can only set your username if logged in';
+ if (Meteor.isClient) return;
+ return Accounts.setUsername(this.userId, username)
+ }
});
Meteor.users.setPreference = new ValidatedMethod({
- name: 'users.setPreference',
- validate: new SimpleSchema({
- preference: {
- type: String,
- },
- value: {
- type: SimpleSchema.oneOf(Boolean),
- },
- }).validator(),
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run({ preference, value }) {
- if (!this.userId) throw 'You can only set preferences once logged in';
- let prefPath = `preferences.${preference}`
- if (value == true) {
- return Meteor.users.update(this.userId, {
- $set: { [prefPath]: true },
- });
- } else {
- return Meteor.users.update(this.userId, {
- $unset: { [prefPath]: 1 },
- });
- }
- },
+ name: 'users.setPreference',
+ validate: new SimpleSchema({
+ preference: {
+ type: String,
+ },
+ value: {
+ type: SimpleSchema.oneOf(Boolean),
+ },
+ }).validator(),
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run({ preference, value }) {
+ if (!this.userId) throw 'You can only set preferences once logged in';
+ let prefPath = `preferences.${preference}`
+ if (value == true) {
+ return Meteor.users.update(this.userId, {
+ $set: { [prefPath]: true },
+ });
+ } else {
+ return Meteor.users.update(this.userId, {
+ $unset: { [prefPath]: 1 },
+ });
+ }
+ },
});
Meteor.users.subscribeToLibrary = new ValidatedMethod({
- name: 'users.subscribeToLibrary',
- validate: new SimpleSchema({
- libraryId: {
- type: String,
- regEx: SimpleSchema.RegEx.Id,
- },
- subscribe: {
- type: Boolean,
- },
- }).validator(),
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run({ libraryId, subscribe }) {
- if (!this.userId) throw 'Can only subscribe if logged in';
- if (subscribe) {
- return Meteor.users.update(this.userId, {
- $addToSet: { subscribedLibraries: libraryId },
- });
- } else {
- return Meteor.users.update(this.userId, {
- $pullAll: { subscribedLibraries: libraryId },
- });
- }
- }
+ name: 'users.subscribeToLibrary',
+ validate: new SimpleSchema({
+ libraryId: {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id,
+ },
+ subscribe: {
+ type: Boolean,
+ },
+ }).validator(),
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run({ libraryId, subscribe }) {
+ if (!this.userId) throw 'Can only subscribe if logged in';
+ if (subscribe) {
+ return Meteor.users.update(this.userId, {
+ $addToSet: { subscribedLibraries: libraryId },
+ });
+ } else {
+ return Meteor.users.update(this.userId, {
+ $pullAll: { subscribedLibraries: libraryId },
+ });
+ }
+ }
});
Meteor.users.subscribeToLibraryCollection = new ValidatedMethod({
- name: 'users.subscribeToLibraryCollection',
- validate: new SimpleSchema({
- libraryCollectionId: {
- type: String,
- regEx: SimpleSchema.RegEx.Id,
- },
- subscribe: {
- type: Boolean,
- },
- }).validator(),
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run({ libraryCollectionId, subscribe }) {
- if (!this.userId) throw 'Can only subscribe if logged in';
- if (subscribe) {
- return Meteor.users.update(this.userId, {
- $addToSet: { subscribedLibraryCollections: libraryCollectionId },
- });
- } else {
- return Meteor.users.update(this.userId, {
- $pullAll: { subscribedLibraryCollections: libraryCollectionId },
- });
- }
- }
+ name: 'users.subscribeToLibraryCollection',
+ validate: new SimpleSchema({
+ libraryCollectionId: {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id,
+ },
+ subscribe: {
+ type: Boolean,
+ },
+ }).validator(),
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run({ libraryCollectionId, subscribe }) {
+ if (!this.userId) throw 'Can only subscribe if logged in';
+ if (subscribe) {
+ return Meteor.users.update(this.userId, {
+ $addToSet: { subscribedLibraryCollections: libraryCollectionId },
+ });
+ } else {
+ return Meteor.users.update(this.userId, {
+ $pullAll: { subscribedLibraryCollections: libraryCollectionId },
+ });
+ }
+ }
});
Meteor.users.findUserByUsernameOrEmail = new ValidatedMethod({
- name: 'users.findUserByUsernameOrEmail',
- validate: new SimpleSchema({
- usernameOrEmail: {
- type: String,
- },
- }).validator(),
- mixins: [RateLimiterMixin],
- rateLimit: {
- numRequests: 5,
- timeInterval: 5000,
- },
- run({ usernameOrEmail }) {
- if (Meteor.isClient) return;
- let user = Accounts.findUserByUsername(usernameOrEmail) ||
- Accounts.findUserByEmail(usernameOrEmail);
- return user && user._id;
- }
+ name: 'users.findUserByUsernameOrEmail',
+ validate: new SimpleSchema({
+ usernameOrEmail: {
+ type: String,
+ },
+ }).validator(),
+ mixins: [RateLimiterMixin],
+ rateLimit: {
+ numRequests: 5,
+ timeInterval: 5000,
+ },
+ run({ usernameOrEmail }) {
+ if (Meteor.isClient) return;
+ let user = Accounts.findUserByUsername(usernameOrEmail) ||
+ Accounts.findUserByEmail(usernameOrEmail);
+ return user && user._id;
+ }
});
diff --git a/app/imports/parser/grammar.js b/app/imports/parser/grammar.js
index d8a449f8..ec217527 100644
--- a/app/imports/parser/grammar.js
+++ b/app/imports/parser/grammar.js
@@ -4,7 +4,7 @@ function id(x) { return x[0]; }
import node from './parseTree/_index.js';
- import moo from 'moo';
+ import moo from 'moo';
const lexer = moo.compile({
number: /[0-9]+(?:\.[0-9]+)?/,
diff --git a/app/imports/server/cron/deleteSoftRemovedDocuments.js b/app/imports/server/cron/deleteSoftRemovedDocuments.js
index 22a1d5ad..b22d0293 100644
--- a/app/imports/server/cron/deleteSoftRemovedDocuments.js
+++ b/app/imports/server/cron/deleteSoftRemovedDocuments.js
@@ -4,47 +4,47 @@ import { assertAdmin } from '/imports/api/sharing/sharingPermissions.js';
import { SyncedCron } from 'meteor/littledata:synced-cron';
Meteor.startup(() => {
- const collections = [
- CreatureProperties,
- LibraryNodes,
- ];
+ const collections = [
+ CreatureProperties,
+ LibraryNodes,
+ ];
- /**
- * Deletes all soft removed documents that were removed more than 1 day ago
- * and were not restored
- * @return {Number} Number of documents removed
- */
- const deleteOldSoftRemovedDocs = function () {
- const now = new Date();
- const yesterday = new Date(now.getTime() - (24 * 60 * 60 * 1000));
- collections.forEach(collection => {
- collection.remove({
- removed: true,
- removedAt: { $lt: yesterday } // dates *before* yesterday
- }, function (error) {
- if (error) {
- console.error(JSON.stringify(error, null, 2));
- }
- });
- });
- };
+ /**
+ * Deletes all soft removed documents that were removed more than 1 day ago
+ * and were not restored
+ * @return {Number} Number of documents removed
+ */
+ const deleteOldSoftRemovedDocs = function () {
+ const now = new Date();
+ const yesterday = new Date(now.getTime() - (24 * 60 * 60 * 1000));
+ collections.forEach(collection => {
+ collection.remove({
+ removed: true,
+ removedAt: { $lt: yesterday } // dates *before* yesterday
+ }, function (error) {
+ if (error) {
+ console.error(JSON.stringify(error, null, 2));
+ }
+ });
+ });
+ };
- SyncedCron.add({
- name: 'deleteSoftRemovedDocs',
- schedule: function (parser) {
- return parser.text('every 10 minutes');
- },
- job: deleteOldSoftRemovedDocs,
- });
+ SyncedCron.add({
+ name: 'deleteSoftRemovedDocs',
+ schedule: function (parser) {
+ return parser.text('every 10 minutes');
+ },
+ job: deleteOldSoftRemovedDocs,
+ });
- SyncedCron.start();
+ SyncedCron.start();
- // Add a method to manually trigger removal
- Meteor.methods({
- deleteOldSoftRemovedDocs() {
- assertAdmin(this.userId);
- this.unblock();
- deleteOldSoftRemovedDocs();
- },
- });
+ // Add a method to manually trigger removal
+ Meteor.methods({
+ deleteOldSoftRemovedDocs() {
+ assertAdmin(this.userId);
+ this.unblock();
+ deleteOldSoftRemovedDocs();
+ },
+ });
});
diff --git a/app/imports/ui/components/ColumnLayout.vue b/app/imports/ui/components/ColumnLayout.vue
index 3b53c998..8d3fc918 100644
--- a/app/imports/ui/components/ColumnLayout.vue
+++ b/app/imports/ui/components/ColumnLayout.vue
@@ -12,46 +12,46 @@
diff --git a/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue b/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue
index 6acf3c2e..8cc185f2 100644
--- a/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue
+++ b/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue
@@ -19,72 +19,72 @@ import TreeNodeList from '/imports/ui/components/tree/TreeNodeList.vue';
import { organizeDoc, reorderDoc } from '/imports/api/parenting/organizeMethods.js';
export default {
- components: {
- TreeNodeList,
- },
- props: {
- root: {
- type: Object,
- default: undefined,
- },
- organize: Boolean,
- selectedNode: {
- type: Object,
- default: undefined,
- },
- filter: {
- type: Object,
- default: undefined,
- },
- group: {
- type: String,
- default: 'creatureProperties'
- },
- expanded: Boolean,
- },
- meteor: {
- children() {
- const children = nodesToTree({
- collection: CreatureProperties,
- ancestorId: this.root.id,
- filter: this.filter,
- includeFilteredDocAncestors: true,
- includeFilteredDocDescendants: true,
- });
- this.$emit('length', children.length);
- return children;
- },
- },
- methods: {
- reordered({ doc, newIndex }) {
- reorderDoc.call({
- docRef: {
- id: doc._id,
- collection: 'creatureProperties',
- },
- order: newIndex,
- });
- },
- reorganized({ doc, parent, newIndex }) {
- let parentRef;
- if (parent) {
- parentRef = {
- id: parent._id,
- collection: 'creatureProperties',
- };
- } else {
- parentRef = this.root;
- }
- organizeDoc.call({
- docRef: {
- id: doc._id,
- collection: 'creatureProperties',
- },
- parentRef,
- order: newIndex,
- });
- },
- },
+ components: {
+ TreeNodeList,
+ },
+ props: {
+ root: {
+ type: Object,
+ default: undefined,
+ },
+ organize: Boolean,
+ selectedNode: {
+ type: Object,
+ default: undefined,
+ },
+ filter: {
+ type: Object,
+ default: undefined,
+ },
+ group: {
+ type: String,
+ default: 'creatureProperties'
+ },
+ expanded: Boolean,
+ },
+ meteor: {
+ children() {
+ const children = nodesToTree({
+ collection: CreatureProperties,
+ ancestorId: this.root.id,
+ filter: this.filter,
+ includeFilteredDocAncestors: true,
+ includeFilteredDocDescendants: true,
+ });
+ this.$emit('length', children.length);
+ return children;
+ },
+ },
+ methods: {
+ reordered({ doc, newIndex }) {
+ reorderDoc.call({
+ docRef: {
+ id: doc._id,
+ collection: 'creatureProperties',
+ },
+ order: newIndex,
+ });
+ },
+ reorganized({ doc, parent, newIndex }) {
+ let parentRef;
+ if (parent) {
+ parentRef = {
+ id: parent._id,
+ collection: 'creatureProperties',
+ };
+ } else {
+ parentRef = this.root;
+ }
+ organizeDoc.call({
+ docRef: {
+ id: doc._id,
+ collection: 'creatureProperties',
+ },
+ parentRef,
+ order: newIndex,
+ });
+ },
+ },
};
diff --git a/app/imports/ui/dialogStack/mockElement.js b/app/imports/ui/dialogStack/mockElement.js
index e3f19654..6f179af5 100644
--- a/app/imports/ui/dialogStack/mockElement.js
+++ b/app/imports/ui/dialogStack/mockElement.js
@@ -2,65 +2,65 @@ import { parse, stringify } from 'css-box-shadow';
// Only supports border radius defined like "20px" or "100%"
const transformedRadius = (radiusString, deltaWidth, deltaHeight) => {
- if (/^\d+\.?\d*px$/.test(radiusString)) {
- //The radius is defined in pixel units, so get the radius as a number
- const rad = +radiusString.match(/\d+\.?\d*/)[0];
- // Set the x and y radius of the "to" element, compensating for scale
- return `${rad / deltaWidth}px / ${rad / deltaHeight}px`;
- } else if (/^\d+\.?\d*%$/.test(radiusString)) {
- //The radius is defined as a percentage, so just use it as is
- return radiusString;
- }
+ if (/^\d+\.?\d*px$/.test(radiusString)) {
+ //The radius is defined in pixel units, so get the radius as a number
+ const rad = +radiusString.match(/\d+\.?\d*/)[0];
+ // Set the x and y radius of the "to" element, compensating for scale
+ return `${rad / deltaWidth}px / ${rad / deltaHeight}px`;
+ } else if (/^\d+\.?\d*%$/.test(radiusString)) {
+ //The radius is defined as a percentage, so just use it as is
+ return radiusString;
+ }
};
const transformedBoxShadow = (shadowString, deltaWidth, deltaHeight) => {
- if (shadowString === 'none') return shadowString;
- if (shadowString[0] === 'r') {
- let strings = shadowString.match(/rgba\([^)]+\)[^,]+/g);
- strings = strings.map(string => {
- // Move color to end
- let m = string.match(/(rgba\([^)]+\))([^,]+)/);
- return `${m[2].trim()} ${m[1]}`;
- });
- shadowString = strings.join(', ');
- }
- let scaleAverage = (deltaWidth + deltaHeight) / 2;
- let shadows = parse(shadowString);
- shadows.forEach(shadow => {
- shadow.offsetX /= deltaWidth;
- shadow.offsetY /= deltaHeight;
- shadow.blurRadius /= scaleAverage;
- shadow.spreadRadius /= scaleAverage;
- })
- return stringify(shadows);
+ if (shadowString === 'none') return shadowString;
+ if (shadowString[0] === 'r') {
+ let strings = shadowString.match(/rgba\([^)]+\)[^,]+/g);
+ strings = strings.map(string => {
+ // Move color to end
+ let m = string.match(/(rgba\([^)]+\))([^,]+)/);
+ return `${m[2].trim()} ${m[1]}`;
+ });
+ shadowString = strings.join(', ');
+ }
+ let scaleAverage = (deltaWidth + deltaHeight) / 2;
+ let shadows = parse(shadowString);
+ shadows.forEach(shadow => {
+ shadow.offsetX /= deltaWidth;
+ shadow.offsetY /= deltaHeight;
+ shadow.blurRadius /= scaleAverage;
+ shadow.spreadRadius /= scaleAverage;
+ })
+ return stringify(shadows);
}
export default function mockElement({ source, target, offset = { x: 0, y: 0 } }) {
- if (!source || !target) throw `Can't mock without ${source ? 'target' : 'source'}`;
- let sourceRect = source.getBoundingClientRect();
- let targetRect = target.getBoundingClientRect();
+ if (!source || !target) throw `Can't mock without ${source ? 'target' : 'source'}`;
+ let sourceRect = source.getBoundingClientRect();
+ let targetRect = target.getBoundingClientRect();
- // Get how must the target change to become the source
- const deltaWidth = sourceRect.width / targetRect.width;
- const deltaHeight = sourceRect.height / targetRect.height;
- const deltaLeft = sourceRect.left - targetRect.left + offset.x;
- const deltaTop = sourceRect.top - targetRect.top + offset.y;
- // Mock the source
- target.style.transform = `translate(${deltaLeft}px, ${deltaTop}px) ` +
- `scale(${deltaWidth}, ${deltaHeight})`;
- // Mock the background color unless it's completely transparent
- let backgroundColor = getComputedStyle(source).backgroundColor
- if (backgroundColor !== 'rgba(0, 0, 0, 0)') {
- target.style.backgroundColor = backgroundColor;
- }
- // Edge might not combine all border radii into a single value,
- // So we just sample the top left one if we need to
- let oldRadius = getComputedStyle(source).borderRadius ||
- getComputedStyle(source).borderTopLeftRadius;
- let borderRadius = transformedRadius(oldRadius, deltaWidth, deltaHeight);
- target.style.borderRadius = borderRadius;
- let boxShadow = transformedBoxShadow(
- getComputedStyle(source).boxShadow, deltaWidth, deltaHeight
- );
- target.style.setProperty('box-shadow', boxShadow, 'important');
+ // Get how must the target change to become the source
+ const deltaWidth = sourceRect.width / targetRect.width;
+ const deltaHeight = sourceRect.height / targetRect.height;
+ const deltaLeft = sourceRect.left - targetRect.left + offset.x;
+ const deltaTop = sourceRect.top - targetRect.top + offset.y;
+ // Mock the source
+ target.style.transform = `translate(${deltaLeft}px, ${deltaTop}px) ` +
+ `scale(${deltaWidth}, ${deltaHeight})`;
+ // Mock the background color unless it's completely transparent
+ let backgroundColor = getComputedStyle(source).backgroundColor
+ if (backgroundColor !== 'rgba(0, 0, 0, 0)') {
+ target.style.backgroundColor = backgroundColor;
+ }
+ // Edge might not combine all border radii into a single value,
+ // So we just sample the top left one if we need to
+ let oldRadius = getComputedStyle(source).borderRadius ||
+ getComputedStyle(source).borderTopLeftRadius;
+ let borderRadius = transformedRadius(oldRadius, deltaWidth, deltaHeight);
+ target.style.borderRadius = borderRadius;
+ let boxShadow = transformedBoxShadow(
+ getComputedStyle(source).boxShadow, deltaWidth, deltaHeight
+ );
+ target.style.setProperty('box-shadow', boxShadow, 'important');
}
diff --git a/app/imports/ui/properties/viewers/BuffViewer.vue b/app/imports/ui/properties/viewers/BuffViewer.vue
index 231b60ae..214f33f2 100644
--- a/app/imports/ui/properties/viewers/BuffViewer.vue
+++ b/app/imports/ui/properties/viewers/BuffViewer.vue
@@ -25,41 +25,41 @@ import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyV
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
export default {
- mixins: [propertyViewerMixin],
- computed: {
- reset() {
- let reset = this.model.reset
- if (reset === 'shortRest') {
- return `Reset${this.model.resetMultiplier && ' x' + this.model.resetMultiplier
- } on a short rest`;
- } else if (reset === 'longRest') {
- return `Reset${this.model.resetMultiplier && ' x' + this.model.resetMultiplier
- } on a long rest`;
- } else {
- return undefined;
- }
- }
- },
- methods: {
- numberToSignedString,
- }
+ mixins: [propertyViewerMixin],
+ computed: {
+ reset() {
+ let reset = this.model.reset
+ if (reset === 'shortRest') {
+ return `Reset${this.model.resetMultiplier && ' x' + this.model.resetMultiplier
+ } on a short rest`;
+ } else if (reset === 'longRest') {
+ return `Reset${this.model.resetMultiplier && ' x' + this.model.resetMultiplier
+ } on a long rest`;
+ } else {
+ return undefined;
+ }
+ }
+ },
+ methods: {
+ numberToSignedString,
+ }
}
diff --git a/app/jsconfig.json b/app/jsconfig.json
new file mode 100644
index 00000000..d113b9c5
--- /dev/null
+++ b/app/jsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "module": "ESNext",
+ "moduleResolution": "Node",
+ "target": "ES2020",
+ "jsx": "react",
+ "strictNullChecks": true,
+ "strictFunctionTypes": true,
+ "baseUrl": ".",
+ "paths": {
+ "/*": [
+ "./*"
+ ]
+ }
+ },
+ "exclude": [
+ "node_modules",
+ "**/node_modules/*"
+ ]
+}
\ No newline at end of file
diff --git a/app/public/manifest.json b/app/public/manifest.json
index 70392a3f..4d831406 100644
--- a/app/public/manifest.json
+++ b/app/public/manifest.json
@@ -1,43 +1,43 @@
{
- "name": "DiceCloud",
- "icons": [
- {
- "src": "\/android-chrome-36x36.png?v=lk6WXp6Pmj",
- "sizes": "36x36",
- "type": "image\/png",
- "density": "0.75"
- },
- {
- "src": "\/android-chrome-48x48.png?v=lk6WXp6Pmj",
- "sizes": "48x48",
- "type": "image\/png",
- "density": "1.0"
- },
- {
- "src": "\/android-chrome-72x72.png?v=lk6WXp6Pmj",
- "sizes": "72x72",
- "type": "image\/png",
- "density": "1.5"
- },
- {
- "src": "\/android-chrome-96x96.png?v=lk6WXp6Pmj",
- "sizes": "96x96",
- "type": "image\/png",
- "density": "2.0"
- },
- {
- "src": "\/android-chrome-144x144.png?v=lk6WXp6Pmj",
- "sizes": "144x144",
- "type": "image\/png",
- "density": "3.0"
- },
- {
- "src": "\/android-chrome-192x192.png?v=lk6WXp6Pmj",
- "sizes": "192x192",
- "type": "image\/png",
- "density": "4.0"
- }
- ],
- "start_url": "\/",
- "display": "standalone"
+ "name": "DiceCloud",
+ "icons": [
+ {
+ "src": "\/android-chrome-36x36.png?v=lk6WXp6Pmj",
+ "sizes": "36x36",
+ "type": "image\/png",
+ "density": "0.75"
+ },
+ {
+ "src": "\/android-chrome-48x48.png?v=lk6WXp6Pmj",
+ "sizes": "48x48",
+ "type": "image\/png",
+ "density": "1.0"
+ },
+ {
+ "src": "\/android-chrome-72x72.png?v=lk6WXp6Pmj",
+ "sizes": "72x72",
+ "type": "image\/png",
+ "density": "1.5"
+ },
+ {
+ "src": "\/android-chrome-96x96.png?v=lk6WXp6Pmj",
+ "sizes": "96x96",
+ "type": "image\/png",
+ "density": "2.0"
+ },
+ {
+ "src": "\/android-chrome-144x144.png?v=lk6WXp6Pmj",
+ "sizes": "144x144",
+ "type": "image\/png",
+ "density": "3.0"
+ },
+ {
+ "src": "\/android-chrome-192x192.png?v=lk6WXp6Pmj",
+ "sizes": "192x192",
+ "type": "image\/png",
+ "density": "4.0"
+ }
+ ],
+ "start_url": "\/",
+ "display": "standalone"
}
\ No newline at end of file