diff --git a/app/assets/javascripts/app/collections/comments.js b/app/assets/javascripts/app/collections/comments.js index efd825988..0b53b8cf0 100644 --- a/app/assets/javascripts/app/collections/comments.js +++ b/app/assets/javascripts/app/collections/comments.js @@ -7,5 +7,18 @@ app.collections.Comments = Backbone.Collection.extend({ initialize : function(models, options) { this.post = options.post + }, + + make : function(text){ + var self = this + + var comment = new app.models.Comment({text: text }) + , deferred = comment.save({}, {url : self.url()}) + + comment.set({author: app.currentUser.toJSON(), parent: self.post }) + + this.add(comment) + + return deferred } }); diff --git a/app/assets/javascripts/app/collections/reshares.js b/app/assets/javascripts/app/collections/reshares.js new file mode 100644 index 000000000..d2c74c8e5 --- /dev/null +++ b/app/assets/javascripts/app/collections/reshares.js @@ -0,0 +1,4 @@ +app.collections.Reshares = Backbone.Collection.extend({ + model: app.models.Reshare, + url : "/reshares" +}); diff --git a/app/assets/javascripts/app/models/participation.js b/app/assets/javascripts/app/models/participation.js deleted file mode 100644 index 01c53d9e2..000000000 --- a/app/assets/javascripts/app/models/participation.js +++ /dev/null @@ -1 +0,0 @@ -app.models.Participation = Backbone.Model.extend({ }); diff --git a/app/assets/javascripts/app/models/post.js b/app/assets/javascripts/app/models/post.js index e6f01de60..7ed5c69cd 100644 --- a/app/assets/javascripts/app/models/post.js +++ b/app/assets/javascripts/app/models/post.js @@ -2,27 +2,27 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin, urlRoot : "/posts", initialize : function() { - this.setupCollections(); - this.bind("change", this.setupCollections, this) + this.interactions = new app.models.Post.Interactions(_.extend({post : this}, this.get("interactions"))) + this.delegateToInteractions() }, - setupCollections: function() { - this.comments = new app.collections.Comments(this.get("comments") || this.get("last_three_comments"), {post : this}); - this.likes = this.likes || new app.collections.Likes([], {post : this}); // load in the user like initially - this.participations = this.participations || new app.collections.Participations([], {post : this}); // load in the user like initially + delegateToInteractions : function(){ + this.comments = this.interactions.comments + this.likes = this.interactions.likes + + this.comment = function(){ + this.interactions.comment.apply(this.interactions, arguments) + } }, setFrameName : function(){ - var templatePicker = new app.models.Post.TemplatePicker(this) - this.set({frame_name : templatePicker.getFrameName()}) + this.set({frame_name : new app.models.Post.TemplatePicker(this).getFrameName()}) }, interactedAt : function() { return this.timeOf("interacted_at"); }, - createReshareUrl : "/reshares", - reshare : function(){ return this._reshare = this._reshare || new app.models.Reshare({root_guid : this.get("guid")}); }, @@ -31,15 +31,6 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin, return this.get("author") }, - toggleLike : function() { - var userLike = this.get("user_like") - if(userLike) { - this.unlike() - } else { - this.like() - } - }, - toggleFavorite : function(options){ this.set({favorite : !this.get("favorite")}) @@ -47,40 +38,6 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin, if(options.save){ this.save() } }, - like : function() { - var self = this; - this.likes.create({}, {success : function(resp){ - self.set(resp) - self.trigger('interacted', self) - }}); - - }, - - unlike : function() { - var self = this; - var likeModel = new app.models.Like(this.get("user_like")); - likeModel.url = this.likes.url + "/" + likeModel.id; - - likeModel.destroy({success : function(model, resp) { - self.set(resp); - self.trigger('interacted', this) - }}); - }, - - comment : function (text) { - - var self = this - , postComments = this.comments; - - postComments.create({"text": text}, { - url : postComments.url(), - wait:true, // added a wait for the time being. 0.5.3 was not optimistic, but 0.9.2 is. - error:function () { - alert(Diaspora.I18n.t("failed_to_post_message")); - } - }); - }, - headline : function() { var headline = this.get("text").trim() , newlineIdx = headline.indexOf("\n") diff --git a/app/assets/javascripts/app/models/post/interactions.js b/app/assets/javascripts/app/models/post/interactions.js new file mode 100644 index 000000000..0cd51de81 --- /dev/null +++ b/app/assets/javascripts/app/models/post/interactions.js @@ -0,0 +1,116 @@ +//require ../post + +app.models.Post.Interactions = Backbone.Model.extend({ + url : function(){ + return this.post.url() + "/interactions" + }, + + initialize : function(options){ + this.post = options.post + this.comments = new app.collections.Comments(this.get("comments"), {post : this.post}) + this.likes = new app.collections.Likes(this.get("likes"), {post : this.post}); + this.reshares = new app.collections.Reshares(this.get("reshares"), {post : this.post}); + }, + + parse : function(resp){ + this.comments.reset(resp.comments) + this.likes.reset(resp.likes) + this.reshares.reset(resp.reshares) + + var comments = this.comments + , likes = this.likes + , reshares = this.reshares + + return { + comments : comments, + likes : likes, + reshares : reshares, + fetched : true + } + }, + + likesCount : function(){ + return (this.get("fetched") ? this.likes.models.length : this.get("likes_count") ) + }, + + resharesCount : function(){ + return this.get("fetched") ? this.reshares.models.length : this.get("reshares_count") + }, + + commentsCount : function(){ + return this.get("fetched") ? this.comments.models.length : this.get("comments_count") + }, + + userLike : function(){ + return this.likes.select(function(like){ return like.get("author").guid == app.currentUser.get("guid")})[0] + }, + + userReshare : function(){ + return this.reshares.select(function(reshare){ return reshare.get("author").guid == app.currentUser.get("guid")})[0] + }, + + toggleLike : function() { + if(this.userLike()) { + this.unlike() + } else { + this.like() + } + }, + + like : function() { + var self = this; + this.likes.create({}, {success : function(){ + self.trigger("change") + self.set({"likes_count" : self.get("likes_count") + 1}) + }}) + }, + + unlike : function() { + var self = this; + this.userLike().destroy({success : function(model, resp) { + self.trigger('change') + self.set({"likes_count" : self.get("likes_count") - 1}) + }}); + }, + + comment : function (text) { + var self = this; + + this.comments.make(text).fail(function () { + alert(Diaspora.I18n.t("failed_to_post_message")); + }).done(function() { + self.trigger('change') //updates after sync + }); + + this.trigger("change") //updates count in an eager manner + }, + + reshare : function(){ + var interactions = this + , reshare = this.post.reshare() + + reshare.save({}, { + success : function(resp){ + var flash = new Diaspora.Widgets.FlashMessages; + flash.render({ + success: true, + notice: Diaspora.I18n.t("reshares.successful") + }); + } + }).done(function(){ + interactions.reshares.add(reshare) + }).done(function(){ + interactions.trigger("change") + }); + }, + + userCanReshare : function(){ + var isReshare = this.post.get("post_type") == "Reshare" + , rootExists = (isReshare ? this.post.get("root") : true) + , publicPost = this.post.get("public") + , userIsNotAuthor = this.post.get("author").diaspora_id != app.currentUser.get("diaspora_id") + , userIsNotRootAuthor = rootExists && (isReshare ? this.post.get("root").author.diaspora_id != app.currentUser.get("diaspora_id") : true) + + return publicPost && app.currentUser.authenticated() && userIsNotAuthor && userIsNotRootAuthor; + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/app/models/reshare.js b/app/assets/javascripts/app/models/reshare.js index 68320eb80..7a4b83ff7 100644 --- a/app/assets/javascripts/app/models/reshare.js +++ b/app/assets/javascripts/app/models/reshare.js @@ -1,4 +1,6 @@ app.models.Reshare = app.models.Post.extend({ + urlRoot : "/reshares", + rootPost : function(){ this._rootPost = this._rootPost || new app.models.Post(this.get("root")); return this._rootPost diff --git a/app/assets/javascripts/app/pages/post-viewer.js b/app/assets/javascripts/app/pages/post-viewer.js index 17b0c19f8..71f1d663d 100644 --- a/app/assets/javascripts/app/pages/post-viewer.js +++ b/app/assets/javascripts/app/pages/post-viewer.js @@ -9,8 +9,10 @@ app.pages.PostViewer = app.views.Base.extend({ }, initialize : function(options) { - this.model = new app.models.Post({ id : options.id }); + var post = this.model = new app.models.Post({ id : options.id }); this.model.preloadOrFetch().done(_.bind(this.initViews, this)); + this.model.interactions.fetch() //async, yo, might want to throttle this later. + this.bindEvents() }, diff --git a/app/assets/javascripts/app/views/comment_stream_view.js b/app/assets/javascripts/app/views/comment_stream_view.js index c97374fef..fbdda24d5 100644 --- a/app/assets/javascripts/app/views/comment_stream_view.js +++ b/app/assets/javascripts/app/views/comment_stream_view.js @@ -31,8 +31,9 @@ app.views.CommentStream = app.views.Base.extend({ presenter: function(){ return _.extend(this.defaultPresenter(), { - moreCommentsCount : (this.model.get("comments_count") - 3), - showExpandCommentsLink : (this.model.get("comments_count") > 3) + moreCommentsCount : (this.model.interactions.commentsCount() - 3), + showExpandCommentsLink : (this.model.interactions.commentsCount() > 3), + commentsCount : this.model.interactions.commentsCount() }) }, diff --git a/app/assets/javascripts/app/views/comment_view.js b/app/assets/javascripts/app/views/comment_view.js index cbed276a5..4a826a33d 100644 --- a/app/assets/javascripts/app/views/comment_view.js +++ b/app/assets/javascripts/app/views/comment_view.js @@ -4,11 +4,15 @@ app.views.Comment = app.views.Content.extend({ className : "comment media", events : function() { - return _.extend(app.views.Content.prototype.events, { + return _.extend({}, app.views.Content.prototype.events, { "click .comment_delete": "destroyModel" }); }, + initialize : function(){ + this.model.on("change", this.render, this) + }, + presenter : function() { return _.extend(this.defaultPresenter(), { canRemove: this.canRemove(), diff --git a/app/assets/javascripts/app/views/feedback_view.js b/app/assets/javascripts/app/views/feedback_view.js index 86f83bb7f..57e3a8ac8 100644 --- a/app/assets/javascripts/app/views/feedback_view.js +++ b/app/assets/javascripts/app/views/feedback_view.js @@ -1,5 +1,4 @@ app.views.Feedback = app.views.Base.extend({ - templateName: "feedback", className : "info", @@ -10,47 +9,30 @@ app.views.Feedback = app.views.Base.extend({ }, initialize : function() { - this.model.bind('interacted', this.render, this); + this.model.interactions.on('change', this.render, this); }, presenter : function() { - return _.extend(this.defaultPresenter(), { - userCanReshare : this.userCanReshare() + var interactions = this.model.interactions + + return _.extend(this.defaultPresenter(),{ + commentsCount : interactions.commentsCount(), + likesCount : interactions.likesCount(), + resharesCount : interactions.resharesCount(), + userCanReshare : interactions.userCanReshare(), + userLike : interactions.userLike(), + userReshare : interactions.userReshare(), }) }, toggleLike: function(evt) { if(evt) { evt.preventDefault(); } - this.model.toggleLike(); + this.model.interactions.toggleLike(); }, resharePost : function(evt) { if(evt) { evt.preventDefault(); } if(!window.confirm(Diaspora.I18n.t("reshares.post", {name: this.model.reshareAuthor().name}))) { return } - var reshare = this.model.reshare() - var model = this.model - - reshare.save({}, { - url: this.model.createReshareUrl, - success : function(resp){ - var flash = new Diaspora.Widgets.FlashMessages; - flash.render({ - success: true, - notice: Diaspora.I18n.t("reshares.successful") - }); - model.trigger("interacted") - } - }); - }, - - userCanReshare : function() { - var isReshare = this.model.get("post_type") == "Reshare" - var rootExists = (isReshare ? this.model.get("root") : true) - - var publicPost = this.model.get("public"); - var userIsNotAuthor = this.model.get("author").diaspora_id != app.currentUser.get("diaspora_id"); - var userIsNotRootAuthor = rootExists && (isReshare ? this.model.get("root").author.diaspora_id != app.currentUser.get("diaspora_id") : true) - - return publicPost && app.currentUser.authenticated() && userIsNotAuthor && userIsNotRootAuthor; + this.model.interactions.reshare(); } }); diff --git a/app/assets/javascripts/app/views/likes_info_view.js b/app/assets/javascripts/app/views/likes_info_view.js index 5069f8946..f4f3071bb 100644 --- a/app/assets/javascripts/app/views/likes_info_view.js +++ b/app/assets/javascripts/app/views/likes_info_view.js @@ -10,23 +10,19 @@ app.views.LikesInfo = app.views.StreamObject.extend({ tooltipSelector : ".avatar", initialize : function() { - this.model.bind('expandedLikes', this.render, this) + this.model.interactions.bind('change', this.render, this) }, presenter : function() { return _.extend(this.defaultPresenter(), { - likes : this.model.likes.models + likes : this.model.interactions.likes.toJSON(), + likesCount : this.model.interactions.likesCount(), + likes_fetched : this.model.interactions.get("fetched"), }) }, showAvatars : function(evt){ if(evt) { evt.preventDefault() } - var self = this; - this.model.likes.fetch() - .done(function(resp){ - // set like attribute and like collection - self.model.set({likes : self.model.likes.reset(resp)}) - self.model.trigger("expandedLikes") - }) + this.model.interactions.fetch() } }); diff --git a/app/assets/javascripts/app/views/post-viewer/feedback.js b/app/assets/javascripts/app/views/post-viewer/feedback.js index 7f8584ba4..de63cbbb1 100644 --- a/app/assets/javascripts/app/views/post-viewer/feedback.js +++ b/app/assets/javascripts/app/views/post-viewer/feedback.js @@ -18,6 +18,11 @@ app.views.PostViewerFeedback = app.views.Feedback.extend({ tooltipSelector : ".label, .home-button", + initialize : function(){ + this.model.interactions.on("change", this.render, this) + }, + + postRenderTemplate : function() { this.sneakyVisiblity() }, @@ -36,5 +41,4 @@ app.views.PostViewerFeedback = app.views.Feedback.extend({ alert("you must be logged in to do that!") return false; } - }); \ No newline at end of file diff --git a/app/assets/javascripts/app/views/post-viewer/interactions.js b/app/assets/javascripts/app/views/post-viewer/interactions.js index a0b17600b..7d78f7264 100644 --- a/app/assets/javascripts/app/views/post-viewer/interactions.js +++ b/app/assets/javascripts/app/views/post-viewer/interactions.js @@ -5,7 +5,8 @@ app.views.PostViewerInteractions = app.views.Base.extend({ subviews : { "#post-feedback" : "feedbackView", "#post-reactions" : "reactionsView", - "#new-post-comment" : "newCommentView" + "#new-post-comment" : "newCommentView", + ".interaction_counts" : "interactionCountsView" }, templateName: "post-viewer/interactions", @@ -18,7 +19,7 @@ app.views.PostViewerInteractions = app.views.Base.extend({ }, initViews : function() { - this.reactionsView = new app.views.PostViewerReactions({ model : this.model }) + this.reactionsView = new app.views.PostViewerReactions({ model : this.model.interactions }) /* subviews that require user */ this.feedbackView = new app.views.PostViewerFeedback({ model : this.model }) diff --git a/app/assets/javascripts/app/views/post-viewer/new_comment.js b/app/assets/javascripts/app/views/post-viewer/new_comment.js index 16775a80c..f31da66ca 100644 --- a/app/assets/javascripts/app/views/post-viewer/new_comment.js +++ b/app/assets/javascripts/app/views/post-viewer/new_comment.js @@ -10,7 +10,7 @@ app.views.PostViewerNewComment = app.views.Base.extend({ scrollableArea : "#post-reactions", initialize : function(){ - this.model.comments.bind("sync", this.clearAndReactivateForm, this) + this.model.interactions.comments.bind("sync", this.clearAndReactivateForm, this) }, postRenderTemplate : function() { @@ -25,7 +25,6 @@ app.views.PostViewerNewComment = app.views.Base.extend({ }, clearAndReactivateForm : function() { - this.model.trigger("interacted") this.toggleFormState() this.$("textarea").val("") .css('height', '18px') diff --git a/app/assets/javascripts/app/views/post-viewer/reactions.js b/app/assets/javascripts/app/views/post-viewer/reactions.js index 145ed1b02..1447bde22 100644 --- a/app/assets/javascripts/app/views/post-viewer/reactions.js +++ b/app/assets/javascripts/app/views/post-viewer/reactions.js @@ -7,7 +7,16 @@ app.views.PostViewerReactions = app.views.Base.extend({ tooltipSelector : ".avatar", initialize : function() { - this.model.bind('interacted', this.render, this); + this.model.on('change', this.render, this); + this.model.comments.bind("add", this.appendComment, this) + }, + + presenter : function(){ + return { + likes : this.model.likes.toJSON(), + comments : this.model.comments.toJSON(), + reshares : this.model.reshares.toJSON() + } }, postRenderTemplate : function() { @@ -21,14 +30,15 @@ app.views.PostViewerReactions = app.views.Base.extend({ /* copy pasta from commentStream */ appendComment: function(comment) { - // Set the post as the comment's parent, so we can check - // on post ownership in the Comment view. - comment.set({parent : this.model.toJSON()}) + // Set the post as the comment's parent, so we can check on post ownership in the Comment view. + // model was post on old view, is interactions on new view + + var parent = this.model.get("post_type") ? this.model.toJSON : this.model.post.toJSON() + comment.set({parent : parent}) this.$("#post-comments").append(new app.views.Comment({ model: comment, className : "post-comment media" }).render().el); } - }); \ No newline at end of file diff --git a/app/assets/templates/comment-stream.jst.hbs b/app/assets/templates/comment-stream.jst.hbs index 200235fda..a41b612d9 100644 --- a/app/assets/templates/comment-stream.jst.hbs +++ b/app/assets/templates/comment-stream.jst.hbs @@ -11,7 +11,7 @@
{{#if loggedIn}} -