// This collection stores all the documents. // Note: not Documents, but this.Documents, because of the editing package (?) this.Documents = new Mongo.Collection("documents"); // This collection stores sets of users that are editing documents. EditingUsers = new Mongo.Collection("editingUsers"); if (Meteor.isClient) { Meteor.subscribe("documents"); Meteor.subscribe("editingUsers"); Template.editor.helpers({ // Return the id of the first document you can find. docid: function () { setupCurrentDocument(); return Session.get("docid"); }, // Configure the CodeMirror editor. config: function () { return function (editor) { editor.setOption("lineNumbers", true); editor.setOption("theme", "cobalt"); editor.setOption("mode", "html"); // Set a callback that gets triggered whenever the user // makes a change in the code editing window. editor.on("change", function (cmEditor /* , info */) { let $preview = $("#viewer_iframe"); // Send the current code over to the iframe for rendering. $preview.contents().find("html").html(cmEditor.getValue()); Meteor.call("addEditingUser"); }); }; } }); Template.editingUsers.helpers({ // Retrieve a set of users that are editing this document. users: function () { let doc = Documents.findOne(); if (!doc) { // Give up. return null; } let eUsers = EditingUsers.findOne({ docId: doc._id }); if (!eUsers) { // Give up. return null; } let users = new Array(); let i = 0; for (let userId in eUsers.users) { users[i] = fixObjectsKeys(eUsers.users[userId]); users[i]._id = userId; i++; } return users; } }); Template.navbar.helpers({ documents: function () { return Documents.find(); } }); Template.docMeta.helpers({ document: function () { return Documents.findOne({ _id: Session.get("docid") }); }, canEdit: function () { let doc = Documents.findOne({ _id: Session.get("docid") }); return doc && doc.owner === Meteor.userId(); }, isPrivate: function () { let doc = Documents.findOne({ _id: Session.get("docid") }); return !!(doc.isPrivate); } }); Template.editableText.helpers({ userCanEdit: function (doc, collection) { Meteor._debug("userCanEdit", doc, collection); // Can edit if the document is owned by me. doc = Documents.findOne({ _id: Session.get("docid"), owner: Meteor.userId() }); return !!doc; } }); Template.navbar.events({ "click .js-add-doc": function (event) { event.preventDefault(); // User not available. if (!Meteor.user()) { alert("You need to login first."); } else { Meteor.call("addDoc", function (err, res) { if (!err) { console.log("addDoc res", res); Session.set("docid", res); } }); } }, "click .js-load-doc": function (event) { // This contains a complete document. Session.set("docid", this._id); } }); Template.docMeta.events({ "click .js-tog-private": function (event) { const docid = Session.get("docid"); if (docid) { const doc = { _id: docid, isPrivate: event.target.checked }; Meteor.call("updateDocPrivacy", doc); } } }); } // end isClient... if (Meteor.isServer) { Meteor.publish("documents", function () { Meteor._debug("Publishing documents"); return Documents.find({ $or: [ { isPrivate: false }, { owner: this.userId } ] }); }); Meteor.publish("editingUsers", function () { Meteor._debug("Publishing all editingUsers"); return EditingUsers.find(); }); Meteor.startup(function () { // Insert a document if there isn't one already. if (!Documents.findOne()) { Documents.insert({ title: "my new document" }); } }); } // Methods that provide write access to the data. Meteor.methods({ addDoc: function () { Meteor._debug("addDoc, this", this); // Not logged-in. if (!this.userId) { return; } else { let doc = { owner: this.userId, createdOn: new Date(), title: "my new doc" }; const docid = Documents.insert(doc); return docid; } }, updateDocPrivacy: function (doc) { Meteor._debug("updatedocPrivacy", this.userId, doc) if (!this.userId) { return; } let res = Documents.update({ _id: doc._id, owner: this.userId }, { $set: { isPrivate: doc.isPrivate } }); Meteor._debug("update", res); }, addEditingUser: function () { let doc = Documents.findOne(); if (!doc) { // No doc: give up. return; } if (!this.userId) { // No logged-in user: give up. return; } // Now I have a doc and possibly a user. let user = Meteor.user().profile; let eUsers = EditingUsers.findOne({ docId: doc._id }); // No editing users have been stored yet. if (!eUsers) { eUsers = { docId: doc._id, users: {} }; } user.lastEdit = new Date(); eUsers.users[this.userId] = user; // Upsert: insert or update if filter matches. EditingUsers.upsert({ _id: eUsers._id }, eUsers); } }); function setupCurrentDocument() { let doc; // No docid set yet. if (!Session.get("docid")) { doc = Documents.findOne(); if (doc) { Session.set("docid", doc._id); } } } // This renames object keys by removing hyphens to make them compatible // with spacebars. function fixObjectsKeys(obj) { let newObj = {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { const key2 = key.replace("-", ""); newObj[key2] = obj[key]; } } return newObj; }