diff --git a/rpg-docs/client/compatibility/jquery.quickfit.js b/rpg-docs/client/compatibility/jquery.quickfit.js new file mode 100644 index 00000000..f8d6ebe6 --- /dev/null +++ b/rpg-docs/client/compatibility/jquery.quickfit.js @@ -0,0 +1,174 @@ +// jscs:disable +// https://github.com/chunksnbits/jquery-quickfit +(function ($) { + var Quickfit, QuickfitHelper, defaults, pluginName; + + pluginName = 'quickfit'; + + defaults = { + min: 8, + max: 12, + tolerance: 0.02, + truncate: false, + width: null, + sampleNumberOfLetters: 10, + sampleFontSize: 12 + }; + QuickfitHelper = (function () { + + var sharedInstance = null; + + QuickfitHelper.instance = function (options) { + if (!sharedInstance) { + sharedInstance = new QuickfitHelper(options); + } + return sharedInstance; + }; + + function QuickfitHelper(options) { + this.options = options; + + this.item = $(''); + this.item.css({ + position: 'absolute', + left: '-1000px', + top: '-1000px', + 'font-size': "" + this.options.sampleFontSize + "px" + }); + $('body').append(this.item); + + this.meassures = {}; + } + + QuickfitHelper.prototype.getMeassure = function (letter) { + var currentMeassure; + currentMeassure = this.meassures[letter]; + if (!currentMeassure) { + currentMeassure = this.setMeassure(letter); + } + return currentMeassure; + }; + + QuickfitHelper.prototype.setMeassure = function (letter) { + var currentMeassure, index, sampleLetter, text, _ref; + + text = ''; + sampleLetter = letter === ' ' ? ' ' : letter; + + for (index = 0, _ref = this.options.sampleNumberOfLetters - 1; 0 <= _ref ? index <= _ref : index >= _ref; 0 <= _ref ? index++ : index--) { + text += sampleLetter; + } + + this.item.html(text); + currentMeassure = this.item.width() / this.options.sampleNumberOfLetters / this.options.sampleFontSize; + this.meassures[letter] = currentMeassure; + + return currentMeassure; + }; + + return QuickfitHelper; + + })(); + + Quickfit = (function () { + + function Quickfit(element, options) { + this.$element = element; + this.options = $.extend({}, defaults, options); + this.$element = $(this.$element); + this._defaults = defaults; + this._name = pluginName; + this.quickfitHelper = QuickfitHelper.instance(this.options); + } + + Quickfit.prototype.fit = function () { + var elementWidth; + if (!this.options.width) { + elementWidth = this.$element.width(); + this.options.width = elementWidth - this.options.tolerance * elementWidth; + } + if (this.text = this.$element.attr('data-quickfit')) { + this.previouslyTruncated = true; + } else { + this.text = this.$element.text(); + } + this.calculateFontSize(); + + if (this.options.truncate) this.truncate(); + + return { + $element: this.$element, + size: this.fontSize + }; + }; + + Quickfit.prototype.calculateFontSize = function () { + var letter, textWidth, i; + + textWidth = 0; + for (i = 0; i < this.text.length; ++i) { + letter = this.text.charAt(i); + textWidth += this.quickfitHelper.getMeassure(letter); + } + + this.targetFontSize = parseInt(this.options.width / textWidth); + return this.fontSize = Math.max(this.options.min, Math.min(this.options.max, this.targetFontSize)); + }; + + Quickfit.prototype.truncate = function () { + var index, lastLetter, letter, textToAdd, textWidth; + + if (this.fontSize > this.targetFontSize) { + textToAdd = ''; + textWidth = 3 * this.quickfitHelper.getMeassure('.') * this.fontSize; + + index = 0; + while (textWidth < this.options.width && index < this.text.length) { + letter = this.text[index++]; + if (lastLetter) textToAdd += lastLetter; + textWidth += this.fontSize * this.quickfitHelper.getMeassure(letter); + lastLetter = letter; + } + + if (textToAdd.length + 1 === this.text.length) { + textToAdd = this.text; + } else { + textToAdd += '...'; + } + this.textWasTruncated = true; + + return this.$element.attr('data-quickfit', this.text).html(textToAdd); + + } else { + if (this.previouslyTruncated) { + return this.$element.html(this.text); + } + } + }; + + return Quickfit; + + })(); + + return $.fn.quickfit = function (options) { + var measurements = []; + + // Separate measurements from repaints + // First calculate all measurements... + var $elements = this.each(function () { + var measurement = new Quickfit(this, options).fit(); + measurements.push(measurement); + return measurement.$element; + }); + + // ... then apply the measurements. + for (var i = 0; i < measurements.length; i++) { + var measurement = measurements[i]; + + measurement.$element.css({ fontSize: measurement.size + 'px' }); + } + + return $elements; + }; + +})(jQuery, window); diff --git a/rpg-docs/client/lib/printing.js b/rpg-docs/client/lib/printing.js new file mode 100644 index 00000000..1eb0357a --- /dev/null +++ b/rpg-docs/client/lib/printing.js @@ -0,0 +1,12 @@ +Session.setDefault("isPrinting", false); +if (window.matchMedia) { + var mediaQueryList = window.matchMedia("print"); + mediaQueryList.addListener(function(mql) { + if (mql.matches) { + Session.set("isPrinting", true); + Tracker.flush(); + } else { + Session.set("isPrinting", false); + } + }); +} diff --git a/rpg-docs/client/views/character/characterSheet.html b/rpg-docs/client/views/character/characterSheet.html index 9fd7a65f..5573ee4b 100644 --- a/rpg-docs/client/views/character/characterSheet.html +++ b/rpg-docs/client/views/character/characterSheet.html @@ -1,4 +1,7 @@ + {{#if printing}} + {{> printedCharacterSheet}} + {{/if}} diff --git a/rpg-docs/client/views/character/characterSheet.js b/rpg-docs/client/views/character/characterSheet.js index 528cf42d..655863df 100644 --- a/rpg-docs/client/views/character/characterSheet.js +++ b/rpg-docs/client/views/character/characterSheet.js @@ -165,6 +165,9 @@ var getTab = function(charId){ }; Template.characterSheet.helpers({ + printing: function(){ + return Session.get("isPrinting"); + }, selectedTab: function(){ return getTab(this._id); }, diff --git a/rpg-docs/client/views/character/printedCharacterSheet/printedAbility/printedAbility.html b/rpg-docs/client/views/character/printedCharacterSheet/printedAbility/printedAbility.html new file mode 100644 index 00000000..2f938d57 --- /dev/null +++ b/rpg-docs/client/views/character/printedCharacterSheet/printedAbility/printedAbility.html @@ -0,0 +1,13 @@ + + + + {{title}} + + + {{characterCalculate "attributeValue" ../_id ability}} + + + {{abilityMod}} + + + diff --git a/rpg-docs/client/views/character/printedCharacterSheet/printedAbility/printedAbility.js b/rpg-docs/client/views/character/printedCharacterSheet/printedAbility/printedAbility.js new file mode 100644 index 00000000..62e74b7d --- /dev/null +++ b/rpg-docs/client/views/character/printedCharacterSheet/printedAbility/printedAbility.js @@ -0,0 +1,9 @@ +Template.printedAbility.helpers({ + abilityMod: function() { + return signedString( + Characters.calculate.abilityMod( + Template.parentData()._id, this.ability + ) + ); + } +}); diff --git a/rpg-docs/client/views/character/printedCharacterSheet/printedCharacterSheet.css b/rpg-docs/client/views/character/printedCharacterSheet/printedCharacterSheet.css new file mode 100644 index 00000000..41e60aab --- /dev/null +++ b/rpg-docs/client/views/character/printedCharacterSheet/printedCharacterSheet.css @@ -0,0 +1,37 @@ +.printed { + background: #fff; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 99; +} + +.printed > .page { + width: 100%; + padding: 1cm; + page-break-inside: avoid; + page-break-after: always; +} + +.printed .shrink-to-fit { + white-space: nowrap; + overflow: hidden; +} + +@media screen { + .printed { + display: none; + } +} + +@media print { + .character-sheet { + display: none; + } + app-drawer { + display: none; + } + +} diff --git a/rpg-docs/client/views/character/printedCharacterSheet/printedCharacterSheet.html b/rpg-docs/client/views/character/printedCharacterSheet/printedCharacterSheet.html new file mode 100644 index 00000000..44cddd5f --- /dev/null +++ b/rpg-docs/client/views/character/printedCharacterSheet/printedCharacterSheet.html @@ -0,0 +1,116 @@ + + + + + + + {{name}} + + + + {{#each classes}} + + {{name}} {{level}} + + {{/each}} + + + {{alignment}} {{gender}} {{race}} + + + + + + + + {{> printedAbility ability="strength" title="Strength" color="red"}} + {{> printedAbility ability="dexterity" title="Dexterity" color="indigo"}} + {{> printedAbility ability="constitution" title="Constitution" color="green"}} + {{> printedAbility ability="intelligence" title="Intelligence" color="deep-orange"}} + {{> printedAbility ability="wisdom" title="Wisdom" color="purple"}} + {{> printedAbility ability="charisma" title="Charisma" color="pink"}} + + + + {{> printedLongStat stat="proficiencyBonus" name="Proficiency Bonus" prefix="+"}} + + + + Saving Throws + + + {{> printedSkillRow name="Strength" skill="strengthSave"}} + {{> printedSkillRow name="Dexterity" skill="dexteritySave"}} + {{> printedSkillRow name="Constitution" skill="constitutionSave"}} + {{> printedSkillRow name="Intelligence" skill="intelligenceSave"}} + {{> printedSkillRow name="Wisdom" skill="wisdomSave"}} + {{> printedSkillRow name="Charisma" skill="charismaSave"}} + + + + + Skills + + + {{> printedSkillRow name="Acrobatics" skill="acrobatics"}} + {{> printedSkillRow name="Animal Handling" skill="animalHandling"}} + {{> printedSkillRow name="Arcana" skill="arcana"}} + {{> printedSkillRow name="Athletics" skill="athletics"}} + {{> printedSkillRow name="Deception" skill="deception"}} + {{> printedSkillRow name="History" skill="history"}} + {{> printedSkillRow name="Insight" skill="insight"}} + {{> printedSkillRow name="Intimidation" skill="intimidation"}} + {{> printedSkillRow name="Investigation" skill="investigation"}} + {{> printedSkillRow name="Medicine" skill="medicine"}} + {{> printedSkillRow name="Nature" skill="nature"}} + {{> printedSkillRow name="Perception" skill="perception" showPassive="true"}} + {{> printedSkillRow name="Performance" skill="performance"}} + {{> printedSkillRow name="Persuasion" skill="persuasion"}} + {{> printedSkillRow name="Religion" skill="religion"}} + {{> printedSkillRow name="Sleight of Hand" skill="sleightOfHand"}} + {{> printedSkillRow name="Stealth" skill="stealth"}} + {{> printedSkillRow name="Survival" skill="survival"}} + + + + + + + + + + + + + {{> printedSquareStat stat="armor" name="Armor Class" color="teal"}} + + + {{> printedSquareStat stat="initiative" name="Initiative" color="teal"}} + + + {{> printedSquareStat stat="speed" name="Speed" color="teal"}} + + + + Hit Points + + + + + /{{characterCalculate "attributeValue" _id "hitPoints"}} + + + + + + + + + + + + + + + + diff --git a/rpg-docs/client/views/character/printedCharacterSheet/printedCharacterSheet.js b/rpg-docs/client/views/character/printedCharacterSheet/printedCharacterSheet.js new file mode 100644 index 00000000..1a2b9da4 --- /dev/null +++ b/rpg-docs/client/views/character/printedCharacterSheet/printedCharacterSheet.js @@ -0,0 +1,17 @@ +Template.printedCharacterSheet.onRendered(function(){ + // Quickfit is only called once on rendering, text will not resize reactively + this.$(".shrink-to-fit").quickfit({ + min: 7, + max: 36, + truncate: true, + }); +}); + +Template.printedCharacterSheet.helpers({ + character(){ + return Characters.findOne(this._id); + }, + classes: function(){ + return Classes.find({charId: this._id}, {sort: {createdAt: 1}}); + }, +}); diff --git a/rpg-docs/client/views/character/printedCharacterSheet/printedLongStat/printedLongStat.html b/rpg-docs/client/views/character/printedCharacterSheet/printedLongStat/printedLongStat.html new file mode 100644 index 00000000..04e82209 --- /dev/null +++ b/rpg-docs/client/views/character/printedCharacterSheet/printedLongStat/printedLongStat.html @@ -0,0 +1,14 @@ + + + + {{#if isSkill}} + {{prefix}}{{skillMod}} + {{else}} + {{prefix}}{{characterCalculate "attributeValue" ../_id stat}} + {{/if}} + + + {{name}} + + + diff --git a/rpg-docs/client/views/character/printedCharacterSheet/printedLongStat/printedLongStat.js b/rpg-docs/client/views/character/printedCharacterSheet/printedLongStat/printedLongStat.js new file mode 100644 index 00000000..ea1cb92d --- /dev/null +++ b/rpg-docs/client/views/character/printedCharacterSheet/printedLongStat/printedLongStat.js @@ -0,0 +1,9 @@ +Template.printedLongStat.helpers({ + skillMod: function() { + return signedString( + Characters.calculate.skillMod( + Template.parentData()._id, this.stat + ) + ); + }, +}); diff --git a/rpg-docs/client/views/character/printedCharacterSheet/printedSkillRow/printedSkillRow.html b/rpg-docs/client/views/character/printedCharacterSheet/printedSkillRow/printedSkillRow.html new file mode 100644 index 00000000..cee2c576 --- /dev/null +++ b/rpg-docs/client/views/character/printedCharacterSheet/printedSkillRow/printedSkillRow.html @@ -0,0 +1,21 @@ + + + + {{#if failSkill}} + fail + {{else}} + + {{skillMod}} + + {{/if}} + + {{name}} + {{#if conditionalCount}} + * + {{/if}} + {{#if showPassive}} + ({{characterCalculate "passiveSkill" ../_id skill}}) + {{/if}} + + + diff --git a/rpg-docs/client/views/character/printedCharacterSheet/printedSkillRow/printedSkillRow.js b/rpg-docs/client/views/character/printedCharacterSheet/printedSkillRow/printedSkillRow.js new file mode 100644 index 00000000..66ff3757 --- /dev/null +++ b/rpg-docs/client/views/character/printedCharacterSheet/printedSkillRow/printedSkillRow.js @@ -0,0 +1,41 @@ +Template.printedSkillRow.helpers({ + skillMod: function() { + return signedString( + Characters.calculate.skillMod( + Template.parentData()._id, this.skill + ) + ); + }, + profIcon: function(){ + var charId = Template.parentData()._id; + var prof = Characters.calculate.proficiency(charId, this.skill); + 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-unchecked"; + }, + failSkill: function(){ + var charId = Template.parentData()._id; + return Effects.find({ + charId: charId, + stat: this.skill, + enabled: true, + operation: "fail", + }).count(); + }, + advantage: function(){ + var charId = Template.parentData()._id; + var advantage = Characters.calculate.advantage(charId, this.skill); + if (advantage > 0) return "advantage"; + if (advantage < 0) return "disadvantage"; + }, + conditionalCount: function(){ + var charId = Template.parentData()._id; + return Effects.find({ + charId: charId, + stat: this.skill, + enabled: true, + operation: "conditional", + }).count(); + }, +}); diff --git a/rpg-docs/client/views/character/printedCharacterSheet/printedSquareStat/printedSquareStat.html b/rpg-docs/client/views/character/printedCharacterSheet/printedSquareStat/printedSquareStat.html new file mode 100644 index 00000000..2aff9a03 --- /dev/null +++ b/rpg-docs/client/views/character/printedCharacterSheet/printedSquareStat/printedSquareStat.html @@ -0,0 +1,14 @@ + + + + {{name}} + + + {{#if isSkill}} + {{prefix}}{{skillMod}} + {{else}} + {{prefix}}{{characterCalculate "attributeValue" ../_id stat}} + {{/if}} + + + diff --git a/rpg-docs/client/views/character/printedCharacterSheet/printedSquareStat/printedSquareStat.js b/rpg-docs/client/views/character/printedCharacterSheet/printedSquareStat/printedSquareStat.js new file mode 100644 index 00000000..680f5f16 --- /dev/null +++ b/rpg-docs/client/views/character/printedCharacterSheet/printedSquareStat/printedSquareStat.js @@ -0,0 +1,9 @@ +Template.printedSquareStat.helpers({ + skillMod: function() { + return signedString( + Characters.calculate.skillMod( + Template.parentData()._id, this.stat + ) + ); + }, +}); diff --git a/rpg-docs/client/views/layout/head.html b/rpg-docs/client/views/layout/head.html index 7be8468a..583fdf40 100644 --- a/rpg-docs/client/views/layout/head.html +++ b/rpg-docs/client/views/layout/head.html @@ -23,4 +23,17 @@ + +