From f5a32cb50ac242d334548e47ab3a818fd6fb7e7e Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Tue, 2 Oct 2018 15:43:10 +0200 Subject: [PATCH] Cobbled together some semblance of an item library UI --- app/Model/Library/Library.js | 38 +++- app/Model/Library/LibraryAttacks.js | 2 +- app/Model/Library/LibraryEffects.js | 1 - app/Model/Library/LibraryItems.js | 47 ++++ app/Model/Users/Users.js | 4 + app/Routes/Routes.js | 2 +- .../itemLibraryDialog/itemLibraryDialog.html | 19 ++ .../itemLibraryDialog/itemLibraryDialog.js | 37 +++- .../library/itemLibrary/itemLibrary.html | 28 ++- .../views/library/itemLibrary/itemLibrary.js | 95 +++++++- .../libraryItemDialog/libraryItemDialog.html | 88 ++++++++ .../libraryItemDialog/libraryItemDialog.js | 204 ++++++++++++++++++ app/client/views/library/library.css | 19 ++ app/client/views/library/library.html | 20 +- app/client/views/library/library.js | 29 +++ .../library/libraryDialog/libraryDialog.html | 58 +++++ .../library/libraryDialog/libraryDialog.js | 95 ++++++++ app/server/publications/library.js | 15 ++ app/server/publications/user.js | 1 + 19 files changed, 775 insertions(+), 27 deletions(-) create mode 100644 app/client/views/library/itemLibrary/libraryItemDialog/libraryItemDialog.html create mode 100644 app/client/views/library/itemLibrary/libraryItemDialog/libraryItemDialog.js create mode 100644 app/client/views/library/library.css create mode 100644 app/client/views/library/library.js create mode 100644 app/client/views/library/libraryDialog/libraryDialog.html create mode 100644 app/client/views/library/libraryDialog/libraryDialog.js diff --git a/app/Model/Library/Library.js b/app/Model/Library/Library.js index 6688d0e5..edcb8cc1 100644 --- a/app/Model/Library/Library.js +++ b/app/Model/Library/Library.js @@ -2,14 +2,38 @@ Libraries = new Mongo.Collection("library"); Schemas.Library = new SimpleSchema({ name: {type: String}, - owner: {type: String, regEx: SimpleSchema.RegEx.Id}, - readers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: []}, - writers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: []}, - public: {type: Boolean, defaultValue: false}, + owner: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, + readers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: [], index: 1}, + writers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: [], index: 1}, + public: {type: Boolean, defaultValue: false, index: 1}, }); Libraries.attachSchema(Schemas.Library); +Libraries.after.remove(function(userId, library) { + LibraryItems.remove({library: library._id}); + LibrarySpells.remove({library: library._id}); +}); + +Meteor.methods({ + removeLibrary: function(libraryId) { + let library = Libraries.findOne(libraryId); + let userId = Meteor.userId(); + + if (!library) return; + if (library.owner === userId){ + Libraries.remove(libraryId); + } else { + if (_.contains(library.readers, userId)){ + Libraries.update(libraryId, {$pull: {"readers": userId}}); + } + if (_.contains(library.writers, userId)){ + Libraries.update(libraryId, {$pull: {"writers": userId}}); + } + } + }, +}); + Libraries.allow({ insert(userId, doc) { return userId && doc.owner === userId; @@ -18,16 +42,14 @@ Libraries.allow({ return canEdit(userId, doc); }, remove(userId, doc) { - return canEdit(userId, doc); + return userId && doc.owner === userId; }, fetch: ["owner", "writers"], }); Libraries.deny({ - // For now, only admins can manage libraries insert(userId, doc){ - var user = Meteor.users.findOne(userId); - return !user || !_.contains(user.roles, "admin"); + return !Meteor.users.findOne(userId); }, update(userId, doc, fields, modifier) { // Can't change owners diff --git a/app/Model/Library/LibraryAttacks.js b/app/Model/Library/LibraryAttacks.js index d606acd5..9d111498 100644 --- a/app/Model/Library/LibraryAttacks.js +++ b/app/Model/Library/LibraryAttacks.js @@ -1,7 +1,7 @@ Schemas.LibraryAttacks = new SimpleSchema({ name: { type: String, - defaultValue: "New Attack", + optional: true, trim: false, }, details: { diff --git a/app/Model/Library/LibraryEffects.js b/app/Model/Library/LibraryEffects.js index 4abcb1ef..38389d53 100644 --- a/app/Model/Library/LibraryEffects.js +++ b/app/Model/Library/LibraryEffects.js @@ -9,7 +9,6 @@ Schemas.LibraryEffects = new SimpleSchema({ defaultValue: "add", allowedValues: [ "base", - "proficiency", "add", "mul", "min", diff --git a/app/Model/Library/LibraryItems.js b/app/Model/Library/LibraryItems.js index 569e1df9..f95cd95e 100644 --- a/app/Model/Library/LibraryItems.js +++ b/app/Model/Library/LibraryItems.js @@ -42,3 +42,50 @@ LibraryItems.allow({ }, fetch: ["library"], }); + +Meteor.methods({ + updateLibraryItemEffect: function({itemId, effectIndex, field, value, unsetField}){ + let libraryId = LibraryItems.findOne(itemId).library; + let userId = Meteor.userId(); + if (!Libraries.canEdit(userId, libraryId)) return; + let modifier = { + $set: { + [`effects.${effectIndex}.${field}`]: value, + } + }; + if (unsetField){ + modifier.$unset = { + [`effects.${effectIndex}.${unsetField}`]: 1, + } + } + LibraryItems.update(itemId, modifier); + }, + removeLibraryItemEffect: function({itemId, effectIndex}){ + let libraryId = LibraryItems.findOne(itemId).library; + let userId = Meteor.userId(); + if (!Libraries.canEdit(userId, libraryId)) return; + LibraryItems.update(itemId, {$unset : { + [`effects.${effectIndex}`] : 1, + }}); + LibraryItems.update(itemId, {$pull : {"effects" : null}}); + }, + updateLibraryItemAttack: function({itemId, attackIndex, field, value}){ + let libraryId = LibraryItems.findOne(itemId).library; + let userId = Meteor.userId(); + if (!Libraries.canEdit(userId, libraryId)) return; + LibraryItems.update(itemId, { + $set: { + [`attacks.${attackIndex}.${field}`]: value, + } + }); + }, + removeLibraryItemAttack: function({itemId, attackIndex}){ + let libraryId = LibraryItems.findOne(itemId).library; + let userId = Meteor.userId(); + if (!Libraries.canEdit(userId, libraryId)) return; + LibraryItems.update(itemId, {$unset : { + [`attacks.${attackIndex}`] : 1, + }}); + LibraryItems.update(itemId, {$pull : {"attacks" : null}}); + }, +}) diff --git a/app/Model/Users/Users.js b/app/Model/Users/Users.js index bdbbdda4..5f6b2a7e 100644 --- a/app/Model/Users/Users.js +++ b/app/Model/Users/Users.js @@ -3,6 +3,10 @@ Schemas.UserProfile = new SimpleSchema({ type: String, optional: true, }, + librarySubscriptions: { + type: [String], + defaultValue: [], + }, }); Schemas.User = new SimpleSchema({ diff --git a/app/Routes/Routes.js b/app/Routes/Routes.js index 5d67332a..49accc2a 100644 --- a/app/Routes/Routes.js +++ b/app/Routes/Routes.js @@ -121,7 +121,7 @@ Router.map(function() { this.route("library", { path: "/library", waitOn: function(){ - return subsManager.subscribe("standardLibraries"); + return subsManager.subscribe("customLibraries"); }, onAfterAction: function() { document.title = appName + " - Library"; diff --git a/app/client/views/character/inventory/itemLibraryDialog/itemLibraryDialog.html b/app/client/views/character/inventory/itemLibraryDialog/itemLibraryDialog.html index 1dcb352e..50d6189f 100644 --- a/app/client/views/character/inventory/itemLibraryDialog/itemLibraryDialog.html +++ b/app/client/views/character/inventory/itemLibraryDialog/itemLibraryDialog.html @@ -48,6 +48,25 @@ {{/unless}} {{/each}} + {{#each customLibraries}} +
+ + + {{name}} +
+ + + + {{#each item in (itemsInLibrary _id)}} + {{>libraryItem item=item selected=(isSelected item)}} + {{/each}} + +
+ {{#unless ready _id}} + + {{/unless}} +
+ {{/each}} {{/if}} diff --git a/app/client/views/character/inventory/itemLibraryDialog/itemLibraryDialog.js b/app/client/views/character/inventory/itemLibraryDialog/itemLibraryDialog.js index 7ca93920..c21a9aba 100644 --- a/app/client/views/character/inventory/itemLibraryDialog/itemLibraryDialog.js +++ b/app/client/views/character/inventory/itemLibraryDialog/itemLibraryDialog.js @@ -7,6 +7,13 @@ const categories = [ {name: "Tools", key: "tools"}, ]; +const categoryKeys = [ + "weapons", + "armor", + "adventuringGear", + "tools", +]; + Template.itemLibraryDialog.onCreated(function(){ this.selectedItem = new ReactiveVar(); this.searchTerm = new ReactiveVar(); @@ -14,10 +21,17 @@ Template.itemLibraryDialog.onCreated(function(){ this.readyDict = new ReactiveDict(); this.searchReady = new ReactiveVar(); librarySubs.subscribe("standardLibraries"); + librarySubs.subscribe("customLibraries"); + this.autorun(() => { // Subscribe to all open categories _.each(this.categoriesOpen.get(), (key) => { - var handle = librarySubs.subscribe("standardLibraryItems", key); + let handle; + if (_.contains(categoryKeys, key)){ + handle = librarySubs.subscribe("standardLibraryItems", key); + } else { + handle = librarySubs.subscribe("libraryItems", key); + } this.autorun(() => { this.readyDict.set(key, handle.ready()); }); @@ -70,12 +84,29 @@ Template.itemLibraryDialog.helpers({ const searchTerm = Template.instance().searchTerm.get(); if (!searchTerm) return; return LibraryItems.find({ - library: "SRDLibraryGA3XWsd", name: { $regex: new RegExp(".*" + searchTerm + ".*", "gi") }, }); }, + customLibraries(){ + let userId = Meteor.userId(); + return Libraries.find({ + $or: [ + {readers: userId}, + {writers: userId}, + {owner: userId}, + ], + }); + }, + itemsInLibrary(libraryId){ + return LibraryItems.find({ + library: libraryId, + }, { + sort: {name: 1}, + }); + }, + }); Template.itemLibraryDialog.events({ @@ -93,7 +124,7 @@ Template.itemLibraryDialog.events({ }, "click .category-header": function(event, template){ let cats = template.categoriesOpen.get(); - const key = this.key; + const key = this.key || this._id; // Toggle whether this key is in the array or not if (_.contains(cats, key)){ cats = _.without(cats, key); diff --git a/app/client/views/library/itemLibrary/itemLibrary.html b/app/client/views/library/itemLibrary/itemLibrary.html index 5fbf353b..87047681 100644 --- a/app/client/views/library/itemLibrary/itemLibrary.html +++ b/app/client/views/library/itemLibrary/itemLibrary.html @@ -1,5 +1,29 @@ diff --git a/app/client/views/library/itemLibrary/itemLibrary.js b/app/client/views/library/itemLibrary/itemLibrary.js index 480effcc..06c733db 100644 --- a/app/client/views/library/itemLibrary/itemLibrary.js +++ b/app/client/views/library/itemLibrary/itemLibrary.js @@ -1,7 +1,94 @@ +const librarySubs = new SubsManager(); + +Template.itemLibrary.onCreated(function(){ + this.selectedTab = new ReactiveVar("0"); + this.librariesOpen = new ReactiveVar([]); + this.readyDict = new ReactiveDict(); + this.autorun(() => { + // Subscribe to all open libraries + _.each(this.librariesOpen.get(), (libraryId) => { + var handle = librarySubs.subscribe("libraryItems", libraryId); + this.autorun(() => { + this.readyDict.set(libraryId, handle.ready()); + }); + }); + }); +}); + Template.itemLibrary.helpers({ - items(){ - return Items.find({charId: {$in: [ - "SRDLibrary", - ]}}); + selectedTab(){ + return Template.instance().selectedTab.get(); + }, + libraries(){ + let userId = Meteor.userId(); + return Libraries.find({ + $or: [ + {readers: userId}, + {writers: userId}, + {owner: userId}, + ], + }); + }, + libraryItems(){ + return LibraryItems.find({ + library: this._id + },{ + sort: {name: 1} + }); + }, + ready(libraryId){ + return Template.instance().readyDict.get(libraryId); + }, + isOpen(libraryId){ + const librariesOpen = Template.instance().librariesOpen.get(); + return _.contains(librariesOpen, libraryId); }, }); + +Template.itemLibrary.events({ + "click .library-header": function(event, template){ + let libs = template.librariesOpen.get(); + const libraryId = this._id; + // Toggle whether this key is in the array or not + if (_.contains(libs, libraryId)){ + libs = _.without(libs, libraryId); + } else { + libs.push(libraryId); + } + template.librariesOpen.set(libs); + }, + "click .editLibrary": function(event, instance){ + event.stopPropagation(); + var libraryId = this._id; + pushDialogStack({ + template: "libraryDialog", + data: {libraryId}, + element: event.currentTarget.parentElement.parentElement, + returnElement: () => instance.find(`.library-header[data-id='${libraryId}']`), + }); + }, + "click .addItem": function(event, instance){ + event.stopPropagation(); + var libraryId = this._id; + var itemId = LibraryItems.insert({ + name: "New Library Item", + library: libraryId, + }); + pushDialogStack({ + template: "libraryItemDialog", + data: {itemId}, + element: event.currentTarget, + returnElement: () => instance.find(`.item-name[data-id='${itemId}']`), + }); + }, + "click .item-name": function(event, instance){ + event.stopPropagation(); + var itemId = this._id; + pushDialogStack({ + template: "libraryItemDialog", + data: {itemId}, + element: event.currentTarget, + returnElement: () => instance.find(`.item-name[data-id='${itemId}']`), + }); + }, +}) diff --git a/app/client/views/library/itemLibrary/libraryItemDialog/libraryItemDialog.html b/app/client/views/library/itemLibrary/libraryItemDialog/libraryItemDialog.html new file mode 100644 index 00000000..8fcfce0d --- /dev/null +++ b/app/client/views/library/itemLibrary/libraryItemDialog/libraryItemDialog.html @@ -0,0 +1,88 @@ + diff --git a/app/client/views/library/itemLibrary/libraryItemDialog/libraryItemDialog.js b/app/client/views/library/itemLibrary/libraryItemDialog/libraryItemDialog.js new file mode 100644 index 00000000..c258705d --- /dev/null +++ b/app/client/views/library/itemLibrary/libraryItemDialog/libraryItemDialog.js @@ -0,0 +1,204 @@ +Template.libraryItemDialog.helpers({ + item(){ + return LibraryItems.findOne(this.itemId); + }, + calculationOrValue(){ + return this.calculation || this.value; + }, + indexedEffects(){ + let item = LibraryItems.findOne(this.itemId); + if (!item) return; + return _.map(item.effects, (effect, index) => { + if (!effect) return; + effect.index = index; + return effect; + }); + }, + indexedAttacks(){ + let item = LibraryItems.findOne(this.itemId); + if (!item) return; + return _.map(item.attacks, (attack, index) => { + if (!attack) return; + attack.index = index; + return attack; + }); + }, + operationIndex(operation){ + const ref = { + base: 0, + add: 1, + mul: 2, + min: 3, + max: 4, + advantage: 5, + disadvantage: 6, + passiveAdd: 7, + fail: 8, + conditional: 9, + }; + return ref[operation]; + }, + damageTypeIndex(damageType){ + const ref = { + bludgeoning: 0, + piercing: 1, + slashing: 2, + acid: 3, + cold: 4, + fire: 5, + force: 6, + lightning: 7, + necrotic: 8, + poison: 9, + psychic: 10, + radiant: 11, + thunder: 12, + }; + return ref[damageType]; + } +}); + +const bind = function(field){ + return _.debounce(function(event){ + const input = event.currentTarget; + var value = input.value; + LibraryItems.update(this.itemId, { + $set: {[field]: value} + }, { + removeEmptyStrings: false, + trimStrings: false, + }); + }, 300); +}; + +Template.libraryItemDialog.events({ + "click #backButton": function(){ + popDialogStack(); + }, + "click #deleteButton": function(){ + LibraryItems.remove(this.itemId); + popDialogStack(); + }, + "input #libraryItemLibraryNameInput": bind("libraryName"), + "input #libraryItemNameInput": bind("name"), + "input #libraryItemPluralInput": bind("plural"), + "input #libraryItemQuantityInput": bind("quantity"), + "input #libraryItemValueInput": bind("value"), + "input #libraryItemWeightInput": bind("weight"), + "change #attunementCheckbox": function(event){ + LibraryItems.update(this.itemId, { + $set: {requiresAttunement: event.currentTarget.checked} + }); + }, + "change #incrementCheckbox": function(event){ + LibraryItems.update(this.itemId, { + $set: {"settings.showIncrement": event.currentTarget.checked} + }); + }, + "input #libraryItemDescriptionInput": bind("description"), + + // Effects + "click #addEffect": function(event, template){ + LibraryItems.update(template.data.itemId, { + $push: { + effects: {operation: "add"} + } + }); + }, + "iron-select .operationMenu": function(event, template){ + var detail = event.originalEvent.detail; + var opName = detail.item.getAttribute("name"); + if (opName == this.operation) return; + Meteor.call("updateLibraryItemEffect", { + itemId: template.data.itemId, + effectIndex: this.index, + field: "operation", + value: opName, + }); + }, + "input .LibraryItemEffectStat": _.debounce(function(event, template){ + Meteor.call("updateLibraryItemEffect", { + itemId: template.data.itemId, + effectIndex: this.index, + field: "stat", + value: event.currentTarget.value, + }); + }, 300), + "input .LibraryItemEffectValue": _.debounce(function(event, template){ + let value = event.currentTarget.value; + if (value && _.isFinite(+value)){ + Meteor.call("updateLibraryItemEffect", { + itemId: template.data.itemId, + effectIndex: this.index, + field: "value", + unsetField: "calculation", + value, + }); + } else { + Meteor.call("updateLibraryItemEffect", { + itemId: template.data.itemId, + effectIndex: this.index, + field: "calculation", + unsetField: "value", + value, + }); + } + }, 300), + "click .deleteEffect": function (event, template) { + Meteor.call("removeLibraryItemEffect", { + itemId: template.data.itemId, + effectIndex: this.index, + }); + }, + + // Attacks + "click #addAttack": function(event, template){ + LibraryItems.update(template.data.itemId, { + $push: { + attacks: {damageType: "slashing"} + } + }); + }, + "iron-select .damageTypeMenu": function(event, template){ + var detail = event.originalEvent.detail; + var damageType = detail.item.getAttribute("name"); + if (damageType == this.damageType) return; + Meteor.call("updateLibraryItemAttack", { + itemId: template.data.itemId, + attackIndex: this.index, + field: "damageType", + value: damageType, + }); + }, + "input .LibraryItemAttackBonusInput": _.debounce(function(event, template){ + Meteor.call("updateLibraryItemAttack", { + itemId: template.data.itemId, + attackIndex: this.index, + field: "attackBonus", + value: event.currentTarget.value, + }); + }, 300), + "input .LibraryItemAttackDamageInput": _.debounce(function(event, template){ + Meteor.call("updateLibraryItemAttack", { + itemId: template.data.itemId, + attackIndex: this.index, + field: "damage", + value: event.currentTarget.value, + }); + }, 300), + "input .LibraryItemAttackDetailsInput": _.debounce(function(event, template){ + Meteor.call("updateLibraryItemAttack", { + itemId: template.data.itemId, + attackIndex: this.index, + field: "details", + value: event.currentTarget.value, + }); + }, 300), + + "click .deleteAttack": function (event, template) { + Meteor.call("removeLibraryItemAttack", { + itemId: template.data.itemId, + attackIndex: this.index, + }); + }, +}); diff --git a/app/client/views/library/library.css b/app/client/views/library/library.css new file mode 100644 index 00000000..731d8036 --- /dev/null +++ b/app/client/views/library/library.css @@ -0,0 +1,19 @@ +.library .item-name { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + cursor: pointer; +} + +.library .library-header { + font-weight: 500; + cursor: pointer; +} + +.library .library-header iron-icon { + transition: transform 0.3s ease; +} + +.library .library-header iron-icon.open { + transform: rotate(90deg); +} diff --git a/app/client/views/library/library.html b/app/client/views/library/library.html index e22c9a84..b01f46ff 100644 --- a/app/client/views/library/library.html +++ b/app/client/views/library/library.html @@ -1,26 +1,32 @@ diff --git a/app/client/views/library/library.js b/app/client/views/library/library.js new file mode 100644 index 00000000..70d0e89d --- /dev/null +++ b/app/client/views/library/library.js @@ -0,0 +1,29 @@ +const librarySubs = new SubsManager(); + +Template.library.onCreated(function(){ + this.selectedTab = new ReactiveVar("0"); +}); + +Template.library.helpers({ + selectedTab(){ + return Template.instance().selectedTab.get(); + }, +}); + +Template.library.events({ + "iron-select #libraryTabs": function(event, instance){ + instance.selectedTab.set(event.target.selected); + }, + "click #addLibrary": function(event, instance){ + var libraryId = Libraries.insert({ + name: "New Library", + owner: Meteor.userId(), + }); + pushDialogStack({ + template: "libraryDialog", + data: {libraryId}, + element: event.currentTarget, + returnElement: () => instance.find(`.library-header[data-id='${libraryId}']`), + }); + }, +}) diff --git a/app/client/views/library/libraryDialog/libraryDialog.html b/app/client/views/library/libraryDialog/libraryDialog.html new file mode 100644 index 00000000..3fc83637 --- /dev/null +++ b/app/client/views/library/libraryDialog/libraryDialog.html @@ -0,0 +1,58 @@ + diff --git a/app/client/views/library/libraryDialog/libraryDialog.js b/app/client/views/library/libraryDialog/libraryDialog.js new file mode 100644 index 00000000..6c22b871 --- /dev/null +++ b/app/client/views/library/libraryDialog/libraryDialog.js @@ -0,0 +1,95 @@ +Template.libraryDialog.onCreated(function(){ + this.userId = new ReactiveVar(); + this.autorun(() => { + var library = Libraries.findOne(Template.currentData().libraryId, { + fields: {readers: 1, writers: 1, owner: 1} + }); + if (!library) return; + this.subscribe("userNames", _.union(library.readers, library.writers, [library.owner])); + }); +}); + +Template.libraryDialog.helpers({ + library(){ + return Libraries.findOne(this.libraryId); + }, + readers: function(){ + var library = Libraries.findOne(this.libraryId, {fields: {readers: 1}}); + return library && library.readers; + }, + writers: function(){ + var library = Libraries.findOne(this.libraryId, {fields: {writers: 1}}); + return library && library.writers + }, + username: function(id){ + const user = Meteor.users.findOne(id); + return user && user.username || "user: " + id; + }, + shareButtonDisabled: function(){ + return !Template.instance().userId.get(); + }, + userFindError: function(){ + if (!Template.instance().userId.get()){ + return "User not found"; + } + }, +}); + +Template.libraryDialog.events({ + "input #libraryNameInput": _.debounce(function(event){ + const input = event.currentTarget; + var name = input.value; + if (!name){ + input.invalid = true; + input.errorMessage = "Name is required"; + } else { + input.invalid = false; + Libraries.update(this.libraryId, { + $set: {name} + }, { + removeEmptyStrings: false, + trimStrings: false, + }); + } + }, 300), + "click #deleteButton": function(){ + Meteor.call("removeLibrary", this.libraryId); + popDialogStack(); + }, + "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); + } + }); + }, + "click #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"){ + Libraries.update(self.libraryId, { + $addToSet: {writers: userId}, + $pull: {readers: userId}, + }); + } else { + Libraries.update(self.libraryId, { + $addToSet: {readers: userId}, + $pull: {writers: userId}, + }); + } + }, + "click .deleteShare": function(event, instance) { + Libraries.update(instance.data.libraryId, { + $pull: {writers: this.id, readers: this.id} + }); + }, +}); diff --git a/app/server/publications/library.js b/app/server/publications/library.js index 1e6a6441..3ab18ce3 100644 --- a/app/server/publications/library.js +++ b/app/server/publications/library.js @@ -23,3 +23,18 @@ Meteor.publish("standardLibrarySpells", function(level){ sort: {name: 1}, }); }); + +Meteor.publish("customLibraries", function(){ + userId = this.userId; + return Libraries.find({ + $or: [ + {readers: userId}, + {writers: userId}, + {owner: userId}, + ], + }); +}); + +Meteor.publish("libraryItems", function(libraryId){ + return LibraryItems.find({library: libraryId}); +}); diff --git a/app/server/publications/user.js b/app/server/publications/user.js index ceb648ff..799539fd 100644 --- a/app/server/publications/user.js +++ b/app/server/publications/user.js @@ -4,5 +4,6 @@ Meteor.publish("user", function(){ username: 1, profile: 1, apiKey: 1, + librarySubscriptions: 1, }}); });