diff --git a/public/javascripts/app/pages/framer.js b/public/javascripts/app/pages/framer.js index 1aee8f31841c84437d6059cc7ae0e9181ada465e..3939f832fefa89404e4db0910610dbb5f146c85f 100644 --- a/public/javascripts/app/pages/framer.js +++ b/public/javascripts/app/pages/framer.js @@ -33,7 +33,7 @@ app.pages.Framer = app.views.Base.extend({ this._postView.feedbackView = new Backbone.View - this.model.authorIsNotCurrentUser = function(){ return false } + this.model.authorIsCurrentUser = function(){ return true } return this._postView }, diff --git a/public/javascripts/app/templates/stream-element.handlebars b/public/javascripts/app/templates/stream-element.handlebars index 2e0fe9a838745db28abceddf2bbcf39860afaa9c..024c51a0b6fe8fb1b74d1047a0df04dafb636057 100644 --- a/public/javascripts/app/templates/stream-element.handlebars +++ b/public/javascripts/app/templates/stream-element.handlebars @@ -2,7 +2,7 @@ {{#if current_user}} <div class="controls"> - {{#if authorIsNotCurrentUser}} + {{#unless authorIsCurrentUser}} <a href="#" rel=nofollow> <img src="{{imageUrl "/images/icons/ignoreuser.png"}}"" alt="Ignoreuser" class="block_user control_icon" title="{{t "ignore"}}" /> </a> @@ -13,7 +13,7 @@ <a href="#" rel=nofollow> <img src="{{imageUrl "/images/deletelabel.png"}}" class="delete control_icon remove_post" title="{{t "delete"}}" /> </a> - {{/if}} + {{/unless}} </div> {{/if}} diff --git a/public/javascripts/app/views/post_view.js b/public/javascripts/app/views/post_view.js index 5900bf75c39c2669e258d2d2d371ef9f6c65da41..bc6345e5056abcd64f7b2725d4974db0348b5fe0 100644 --- a/public/javascripts/app/views/post_view.js +++ b/public/javascripts/app/views/post_view.js @@ -1,133 +1,21 @@ app.views.Post = app.views.StreamObject.extend({ - - templateName: "stream-element", - - className : "stream_element loaded", - - events: { - "click .focus_comment_textarea": "focusCommentTextarea", - "click .show_nsfw_post": "removeNsfwShield", - "click .toggle_nsfw_state": "toggleNsfwState", - - "click .remove_post": "destroyModel", - "click .hide_post": "hidePost", - "click .block_user": "blockUser" - }, - - subviews : { - ".feedback" : "feedbackView", - ".likes" : "likesInfoView", - ".comments" : "commentStreamView", - ".post-content" : "postContentView" - }, - - tooltipSelector : ".delete, .block_user, .post_scope", - initialize : function(options) { - // allow for a custom template name to be passed in via the options hash - this.templateName = options.templateName || this.templateName - - this.model.bind('remove', this.remove, this); - this.model.bind('destroy', this.destroy, this); - - //subviews - this.commentStreamView = new app.views.CommentStream({ model : this.model}); - - return this; - }, - - likesInfoView : function(){ - return new app.views.LikesInfo({ model : this.model}); - }, - - feedbackView : function(){ - if(!app.currentUser.authenticated()) { return null } - return new app.views.Feedback({model : this.model}); - }, - - postContentView: function(){ - var normalizedClass = this.model.get("post_type").replace(/::/, "__"); - var postClass = app.views[normalizedClass] || app.views.StatusMessage; - return new postClass({ model : this.model }); + this.templateName = options.templateName }, presenter : function() { return _.extend(this.defaultPresenter(), { - authorIsNotCurrentUser : this.authorIsNotCurrentUser(), + authorIsCurrentUser : this.authorIsCurrentUser(), showPost : this.showPost(), text : app.helpers.textFormatter(this.model) }) }, - showPost : function() { - return (app.currentUser.get("showNsfw")) || !this.model.get("nsfw") - }, - - removeNsfwShield: function(evt){ - if(evt){ evt.preventDefault(); } - this.model.set({nsfw : false}) - this.render(); - }, - - toggleNsfwState: function(evt){ - if(evt){ evt.preventDefault(); } - app.currentUser.toggleNsfwState(); - }, - - blockUser: function(evt){ - if(evt) { evt.preventDefault(); } - if(!confirm("Ignore this user?")) { return } - - var personId = this.model.get("author").id; - var block = new app.models.Block(); - - block.save({block : {person_id : personId}}, { - success : function(){ - if(!app.stream) { return } - - _.each(app.stream.posts.models, function(model){ - if(model.get("author").id == personId) { - app.stream.posts.remove(model); - } - }) - } - }) - }, - - hidePost : function(evt) { - if(evt) { evt.preventDefault(); } - if(!confirm(Diaspora.I18n.t('confirm_dialog'))) { return } - - $.ajax({ - url : "/share_visibilities/42", - type : "PUT", - data : { - post_id : this.model.id - } - }) - - this.slideAndRemove(); - }, - - focusCommentTextarea: function(evt){ - evt.preventDefault(); - this.$(".new_comment_form_wrapper").removeClass("hidden"); - this.$(".comment_box").focus(); - - return this; + authorIsCurrentUser : function() { + return app.currentUser.authenticated() && this.model.get("author").id == app.user().id }, - authorIsNotCurrentUser : function() { - return this.model.get("author").id != app.user().id - }, - - isOnShowPage : function() { - return (!this.model.collection) && (this.model.url() == document.location.pathname); - }, - - destroy : function() { - if (this.isOnShowPage()) { - document.location.replace(Backbone.history.options.root); - } + showPost : function() { + return (app.currentUser.get("showNsfw")) || !this.model.get("nsfw") } }); diff --git a/public/javascripts/app/views/stream_object_view.js b/public/javascripts/app/views/stream_object_view.js index 1f46e732b50641b891d7fb3e5a4e2f0154085ee2..42d7bc6d4195dd420307386c9f59e350aae041c4 100644 --- a/public/javascripts/app/views/stream_object_view.js +++ b/public/javascripts/app/views/stream_object_view.js @@ -1,6 +1,5 @@ app.views.StreamObject = app.views.Base.extend({ - - destroyModel: function(evt) { + destroyModel: function(evt) { if (evt) { evt.preventDefault(); } diff --git a/public/javascripts/app/views/stream_post_views.js b/public/javascripts/app/views/stream_post_views.js new file mode 100644 index 0000000000000000000000000000000000000000..5d955c54de447c7b39dc4db5b1bf3c96188a0cf6 --- /dev/null +++ b/public/javascripts/app/views/stream_post_views.js @@ -0,0 +1,102 @@ +app.views.StreamPost = app.views.Post.extend({ + templateName: "stream-element", + className : "stream_element loaded", + + subviews : { + ".feedback" : "feedbackView", + ".likes" : "likesInfoView", + ".comments" : "commentStreamView", + ".post-content" : "postContentView" + }, + + events: { + "click .focus_comment_textarea": "focusCommentTextarea", + "click .show_nsfw_post": "removeNsfwShield", + "click .toggle_nsfw_state": "toggleNsfwState", + + "click .remove_post": "destroyModel", + "click .hide_post": "hidePost", + "click .block_user": "blockUser" + }, + + tooltipSelector : ".delete, .block_user, .post_scope", + + initialize : function(){ + this.model.bind('remove', this.remove, this); + + //subviews + this.commentStreamView = new app.views.CommentStream({ model : this.model}); + }, + + + likesInfoView : function(){ + return new app.views.LikesInfo({ model : this.model}); + }, + + feedbackView : function(){ + if(!app.currentUser.authenticated()) { return null } + return new app.views.Feedback({model : this.model}); + }, + + postContentView: function(){ + var normalizedClass = this.model.get("post_type").replace(/::/, "__"); + var postClass = app.views[normalizedClass] || app.views.StatusMessage; + return new postClass({ model : this.model }); + }, + + removeNsfwShield: function(evt){ + if(evt){ evt.preventDefault(); } + this.model.set({nsfw : false}) + this.render(); + }, + + toggleNsfwState: function(evt){ + if(evt){ evt.preventDefault(); } + app.currentUser.toggleNsfwState(); + }, + + + blockUser: function(evt){ + if(evt) { evt.preventDefault(); } + if(!confirm("Ignore this user?")) { return } + + var personId = this.model.get("author").id; + var block = new app.models.Block(); + + block.save({block : {person_id : personId}}, { + success : function(){ + if(!app.stream) { return } + + _.each(app.stream.posts.models, function(model){ + if(model.get("author").id == personId) { + app.stream.posts.remove(model); + } + }) + } + }) + }, + + hidePost : function(evt) { + if(evt) { evt.preventDefault(); } + if(!confirm(Diaspora.I18n.t('confirm_dialog'))) { return } + + $.ajax({ + url : "/share_visibilities/42", + type : "PUT", + data : { + post_id : this.model.id + } + }) + + this.slideAndRemove(); + }, + + focusCommentTextarea: function(evt){ + evt.preventDefault(); + this.$(".new_comment_form_wrapper").removeClass("hidden"); + this.$(".comment_box").focus(); + + return this; + } + +}) \ No newline at end of file diff --git a/public/javascripts/app/views/stream_view.js b/public/javascripts/app/views/stream_view.js index a39892dd96961407fc543edf39b5c25e64f76ea5..b17ae4c60a6efa083d849a2f328c01593b50b828 100644 --- a/public/javascripts/app/views/stream_view.js +++ b/public/javascripts/app/views/stream_view.js @@ -27,7 +27,7 @@ app.views.Stream = Backbone.View.extend({ }, addPost : function(post) { - var postView = new app.views.Post({ model: post }); + var postView = new app.views.StreamPost({ model: post }); $(this.el)[ (this.collection.at(0).id == post.id) diff --git a/spec/javascripts/app/views/post_view_spec.js b/spec/javascripts/app/views/post_view_spec.js index d1ef0e2b35da511db74c884b5ca36ccecfb7ad4f..58225d1afbfffc37e6f19188bd3ac9dcd64c533b 100644 --- a/spec/javascripts/app/views/post_view_spec.js +++ b/spec/javascripts/app/views/post_view_spec.js @@ -1,188 +1,3 @@ describe("app.views.Post", function(){ - - describe("#render", function(){ - beforeEach(function(){ - loginAs({name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}}); - - Diaspora.I18n.loadLocale({stream : { - reshares : { - one : "<%= count %> reshare", - other : "<%= count %> reshares" - }, - likes : { - zero : "<%= count %> Likes", - one : "<%= count %> Like", - other : "<%= count %> Likes" - } - }}) - - var posts = $.parseJSON(spec.readFixture("stream_json"))["posts"]; - - this.collection = new app.collections.Posts(posts); - this.statusMessage = this.collection.models[0]; - this.reshare = this.collection.models[1]; - }) - - context("reshare", function(){ - it("displays a reshare count", function(){ - this.statusMessage.set({reshares_count : 2}) - var view = new app.views.Post({model : this.statusMessage}).render(); - - expect($(view.el).html()).toContain(Diaspora.I18n.t('stream.reshares', {count: 2})) - }) - - it("does not display a reshare count for 'zero'", function(){ - this.statusMessage.set({reshares_count : 0}) - var view = new app.views.Post({model : this.statusMessage}).render(); - - expect($(view.el).html()).not.toContain("0 Reshares") - }) - }) - - context("likes", function(){ - it("displays a like count", function(){ - this.statusMessage.set({likes_count : 1}) - var view = new app.views.Post({model : this.statusMessage}).render(); - - expect($(view.el).html()).toContain(Diaspora.I18n.t('stream.likes', {count: 1})) - }) - it("does not display a like count for 'zero'", function(){ - this.statusMessage.set({likes_count : 0}) - var view = new app.views.Post({model : this.statusMessage}).render(); - - expect($(view.el).html()).not.toContain("0 Likes") - }) - }) - - context("embed_html", function(){ - it("provides oembed html from the model response", function(){ - this.statusMessage.set({"o_embed_cache" : { - "data" : { - "html" : "some html" - } - }}) - - var view = new app.views.Content({model : this.statusMessage}); - expect(view.presenter().o_embed_html).toContain("some html") - }) - - it("does not provide oembed html from the model response if none is present", function(){ - this.statusMessage.set({"o_embed_cache" : null}) - - var view = new app.views.Content({model : this.statusMessage}); - expect(view.presenter().o_embed_html).toBe(""); - }) - }) - - context("user not signed in", function(){ - it("does not provide a Feedback view", function(){ - logout() - var view = new app.views.Post({model : this.statusMessage}).render(); - expect(view.feedbackView()).toBeFalsy(); - }) - }) - - context("NSFW", function(){ - beforeEach(function(){ - this.statusMessage.set({nsfw: true}); - this.view = new app.views.Post({model : this.statusMessage}).render(); - - this.hiddenPosts = function(){ - return this.view.$(".nsfw-shield") - } - }); - - it("contains a shield element", function(){ - expect(this.hiddenPosts().length).toBe(1) - }); - - it("does not contain a shield element when nsfw is false", function(){ - this.statusMessage.set({nsfw: false}); - this.view.render(); - expect(this.hiddenPosts()).not.toExist(); - }) - - context("showing a single post", function(){ - it("removes the shields when the post is clicked", function(){ - expect(this.hiddenPosts()).toExist(); - this.view.$(".nsfw-shield .show_nsfw_post").click(); - expect(this.hiddenPosts()).not.toExist(); - }); - }); - - context("clicking the toggle nsfw link toggles it on the user", function(){ - it("calls toggleNsfw on the user", function(){ - spyOn(app.user(), "toggleNsfwState") - this.view.$(".toggle_nsfw_state").first().click(); - expect(app.user().toggleNsfwState).toHaveBeenCalled(); - }); - }) - }) - - context("user views their own post", function(){ - beforeEach(function(){ - this.statusMessage.set({ author: { - id : app.user().id - }}); - this.view = new app.views.Post({model : this.statusMessage}).render(); - }) - - it("contains remove post", function(){ - expect(this.view.$(".remove_post")).toExist(); - }) - - it("destroys the view when they delete a their post from the show page", function(){ - spyOn(window, "confirm").andReturn(true); - - this.view.$(".remove_post").click(); - - expect(window.confirm).toHaveBeenCalled(); - expect(this.view).not.toExist(); - }) - }) - - context("markdown rendering", function() { - beforeEach(function() { - // example from issue #2665 - this.evilUrl = "http://www.bürgerentscheid-krankenhäuser.de"; - this.asciiUrl = "http://www.xn--brgerentscheid-krankenhuser-xkc78d.de"; - }); - - it("correctly handles non-ascii characters in urls", function() { - this.statusMessage.set({text: "<"+this.evilUrl+">"}); - var view = new app.views.Post({model : this.statusMessage}).render(); - - expect($(view.el).html()).toContain(this.asciiUrl); - expect($(view.el).html()).toContain(this.evilUrl); - }); - - it("doesn't break link texts for non-ascii urls", function() { - var linkText = "check out this awesome link!"; - this.statusMessage.set({text: "["+linkText+"]("+this.evilUrl+")"}); - var view = new app.views.Post({model: this.statusMessage}).render(); - - expect($(view.el).html()).toContain(this.asciiUrl); - expect($(view.el).html()).toContain(linkText); - }); - - it("doesn't break reference style links for non-ascii urls", function() { - var postContent = "blabla blab [my special link][1] bla blabla\n\n[1]: "+this.evilUrl+" and an optional title)"; - this.statusMessage.set({text: postContent}); - var view = new app.views.Post({model: this.statusMessage}).render(); - - expect($(view.el).html()).not.toContain(this.evilUrl); - expect($(view.el).html()).toContain(this.asciiUrl); - }); - - it("correctly handles images with non-ascii urls", function() { - var postContent = ""; - var niceImg = '"http://xn--bndnis-fr-krankenhuser-i5b27cha.de/wp-content/uploads/2011/11/cropped-logohp.jpg"'; - this.statusMessage.set({text: postContent}); - var view = new app.views.Post({model: this.statusMessage}).render(); - - expect($(view.el).html()).toContain(niceImg); - }); - - }); - }) -}); + //check out StreamPost +}) diff --git a/spec/javascripts/app/views/stream_post_spec.js b/spec/javascripts/app/views/stream_post_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..7b0f545f67e86393292ef71127ea2684ca99f6fe --- /dev/null +++ b/spec/javascripts/app/views/stream_post_spec.js @@ -0,0 +1,148 @@ +describe("app.views.StreamPost", function(){ + beforeEach(function(){ + this.PostViewClass = app.views.StreamPost + }) + + describe("#render", function(){ + beforeEach(function(){ + loginAs({name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}}); + + Diaspora.I18n.loadLocale({stream : { + reshares : { + one : "<%= count %> reshare", + other : "<%= count %> reshares" + }, + likes : { + zero : "<%= count %> Likes", + one : "<%= count %> Like", + other : "<%= count %> Likes" + } + }}) + + var posts = $.parseJSON(spec.readFixture("stream_json"))["posts"]; + + this.collection = new app.collections.Posts(posts); + this.statusMessage = this.collection.models[0]; + this.reshare = this.collection.models[1]; + }) + + context("reshare", function(){ + it("displays a reshare count", function(){ + this.statusMessage.set({reshares_count : 2}) + var view = new this.PostViewClass({model : this.statusMessage}).render(); + + expect($(view.el).html()).toContain(Diaspora.I18n.t('stream.reshares', {count: 2})) + }) + + it("does not display a reshare count for 'zero'", function(){ + this.statusMessage.set({reshares_count : 0}) + var view = new this.PostViewClass({model : this.statusMessage}).render(); + + expect($(view.el).html()).not.toContain("0 Reshares") + }) + }) + + context("likes", function(){ + it("displays a like count", function(){ + this.statusMessage.set({likes_count : 1}) + var view = new this.PostViewClass({model : this.statusMessage}).render(); + + expect($(view.el).html()).toContain(Diaspora.I18n.t('stream.likes', {count: 1})) + }) + it("does not display a like count for 'zero'", function(){ + this.statusMessage.set({likes_count : 0}) + var view = new this.PostViewClass({model : this.statusMessage}).render(); + + expect($(view.el).html()).not.toContain("0 Likes") + }) + }) + + context("embed_html", function(){ + it("provides oembed html from the model response", function(){ + this.statusMessage.set({"o_embed_cache" : { + "data" : { + "html" : "some html" + } + }}) + + var view = new app.views.Content({model : this.statusMessage}); + expect(view.presenter().o_embed_html).toContain("some html") + }) + + it("does not provide oembed html from the model response if none is present", function(){ + this.statusMessage.set({"o_embed_cache" : null}) + + var view = new app.views.Content({model : this.statusMessage}); + expect(view.presenter().o_embed_html).toBe(""); + }) + }) + + context("user not signed in", function(){ + it("does not provide a Feedback view", function(){ + logout() + var view = new this.PostViewClass({model : this.statusMessage}).render(); + expect(view.feedbackView()).toBeFalsy(); + }) + }) + + context("NSFW", function(){ + beforeEach(function(){ + this.statusMessage.set({nsfw: true}); + this.view = new this.PostViewClass({model : this.statusMessage}).render(); + + this.hiddenPosts = function(){ + return this.view.$(".nsfw-shield") + } + }); + + it("contains a shield element", function(){ + expect(this.hiddenPosts().length).toBe(1) + }); + + it("does not contain a shield element when nsfw is false", function(){ + this.statusMessage.set({nsfw: false}); + this.view.render(); + expect(this.hiddenPosts()).not.toExist(); + }) + + context("showing a single post", function(){ + it("removes the shields when the post is clicked", function(){ + expect(this.hiddenPosts()).toExist(); + this.view.$(".nsfw-shield .show_nsfw_post").click(); + expect(this.hiddenPosts()).not.toExist(); + }); + }); + + context("clicking the toggle nsfw link toggles it on the user", function(){ + it("calls toggleNsfw on the user", function(){ + spyOn(app.user(), "toggleNsfwState") + this.view.$(".toggle_nsfw_state").first().click(); + expect(app.user().toggleNsfwState).toHaveBeenCalled(); + }); + }) + }) + + context("user views their own post", function(){ + beforeEach(function(){ + this.statusMessage.set({ author: { + id : app.user().id + }}); + this.view = new this.PostViewClass({model : this.statusMessage}).render(); + }) + + it("contains remove post", function(){ + expect(this.view.$(".remove_post")).toExist(); + }) + + it("destroys the view when they delete a their post from the show page", function(){ + spyOn(window, "confirm").andReturn(true); + + this.view.$(".remove_post").click(); + + expect(window.confirm).toHaveBeenCalled(); + expect(this.view).not.toExist(); + }) + }) + + }) +});