diff --git a/app/assets/javascripts/discourse/models/topic.js b/app/assets/javascripts/discourse/models/topic.js index 5ba6b0292a8..1b3151ebc2f 100644 --- a/app/assets/javascripts/discourse/models/topic.js +++ b/app/assets/javascripts/discourse/models/topic.js @@ -142,18 +142,15 @@ Discourse.Topic = Discourse.Model.extend({ }, toggleStar: function() { - var _this = this; - this.toggleProperty('starred'); + var topic = this; + topic.toggleProperty('starred'); return jQuery.ajax({ url: "" + (this.get('url')) + "/star", type: 'PUT', - data: { - starred: this.get('starred') ? true : false - }, + data: { starred: topic.get('starred') ? true : false }, error: function(error) { - var errors; - _this.toggleProperty('starred'); - errors = jQuery.parseJSON(error.responseText).errors; + topic.toggleProperty('starred'); + var errors = jQuery.parseJSON(error.responseText).errors; return bootbox.alert(errors[0]); } }); @@ -203,31 +200,22 @@ Discourse.Topic = Discourse.Model.extend({ // Load the posts for this topic loadPosts: function(opts) { - var _this = this; - if (!opts) { - opts = {}; - } + var topic = this; + + if (!opts) opts = {}; // Load the first post by default - if (!opts.bestOf) { - if (!opts.nearPost) opts.nearPost = 1 - } + if ((!opts.bestOf) && (!opts.nearPost)) opts.nearPost = 1; // If we already have that post in the DOM, jump to it if (Discourse.TopicView.scrollTo(this.get('id'), opts.nearPost)) return; - return Discourse.Topic.find(this.get('id'), { - nearPost: opts.nearPost, - bestOf: opts.bestOf, - trackVisit: opts.trackVisit - }).then(function(result) { - - // If loading the topic succeeded... - // Update the slug if different + // If loading the topic succeeded... + var afterTopicLoaded = function(result) { var closestPostNumber, lastPost, postDiff; - if (result.slug) { - _this.set('slug', result.slug); - } + + // Update the slug if different + if (result.slug) topic.set('slug', result.slug); // If we want to scroll to a post that doesn't exist, just pop them to the closest // one instead. This is likely happening due to a deleted post. @@ -235,34 +223,29 @@ Discourse.Topic = Discourse.Model.extend({ closestPostNumber = 0; postDiff = Number.MAX_VALUE; result.posts.each(function(p) { - var diff; - diff = Math.abs(p.post_number - opts.nearPost); + var diff = Math.abs(p.post_number - opts.nearPost); if (diff < postDiff) { postDiff = diff; closestPostNumber = p.post_number; - if (diff === 0) { - return false; - } + if (diff === 0) return false; } }); opts.nearPost = closestPostNumber; - if (_this.get('participants')) { - _this.get('participants').clear(); + if (topic.get('participants')) { + topic.get('participants').clear(); } if (result.suggested_topics) { - _this.set('suggested_topics', Em.A()); + topic.set('suggested_topics', Em.A()); } - _this.mergeAttributes(result, { - suggested_topics: Discourse.Topic - }); - _this.set('posts', Em.A()); + topic.mergeAttributes(result, { suggested_topics: Discourse.Topic }); + topic.set('posts', Em.A()); if (opts.trackVisit && result.draft && result.draft.length > 0) { Discourse.openComposer({ draft: Discourse.Draft.getLocal(result.draft_key, result.draft), draftKey: result.draft_key, draftSequence: result.draft_sequence, - topic: _this, + topic: topic, ignoreIfChanged: true }); } @@ -273,15 +256,41 @@ Discourse.Topic = Discourse.Model.extend({ var post; p.scrollToAfterInsert = opts.nearPost; post = Discourse.Post.create(p); - post.set('topic', _this); - _this.get('posts').pushObject(post); + post.set('topic', topic); + topic.get('posts').pushObject(post); lastPost = post; }); - return _this.set('loaded', true); - }, function(result) { - _this.set('missing', true); - return _this.set('message', Em.String.i18n('topic.not_found.description')); - }); + topic.set('loaded', true); + } + + var errorLoadingTopic = function(result) { + topic.set('errorLoading', true); + + // If the result was 404 the post is not found + if (result.status == 404) { + topic.set('errorTitle', Em.String.i18n('topic.not_found.title')) + topic.set('message', Em.String.i18n('topic.not_found.description')); + return; + } + + // If the result is 403 it means invalid access + if (result.status == 403) { + topic.set('errorTitle', Em.String.i18n('topic.invalid_access.title')) + topic.set('message', Em.String.i18n('topic.invalid_access.description')); + return; + } + + // Otherwise supply a generic error message + topic.set('errorTitle', Em.String.i18n('topic.server_error.title')) + topic.set('message', Em.String.i18n('topic.server_error.description')); + } + + // Finally, call our find method + Discourse.Topic.find(this.get('id'), { + nearPost: opts.nearPost, + bestOf: opts.bestOf, + trackVisit: opts.trackVisit + }).then(afterTopicLoaded, errorLoadingTopic); }, notificationReasonText: (function() { @@ -324,10 +333,10 @@ Discourse.Topic = Discourse.Model.extend({ isReplyDirectlyBelow: function(post) { var postBelow, posts; posts = this.get('posts'); - if (!posts) { - return; - } + if (!posts) return; + postBelow = posts[posts.indexOf(post) + 1]; + // If the post directly below's reply_to_post_number is our post number, it's // considered directly below. return (postBelow ? postBelow.get('reply_to_post_number') : void 0) === post.get('post_number'); @@ -346,12 +355,13 @@ window.Discourse.Topic.reopenClass({ // options: // onLoad - the callback after the topic is loaded find: function(topicId, opts) { - var data, promise, url, - _this = this; + var data, promise, url; url = "/t/" + topicId; + if (opts.nearPost) { url += "/" + opts.nearPost; } + data = {}; if (opts.postsAfter) { data.posts_after = opts.postsAfter; @@ -397,15 +407,11 @@ window.Discourse.Topic.reopenClass({ movePosts: function(topicId, title, postIds) { return jQuery.ajax("/t/" + topicId + "/move-posts", { type: 'POST', - data: { - title: title, - post_ids: postIds - } + data: { title: title, post_ids: postIds } }); }, create: function(obj, topicView) { - var _this = this; return Object.tap(this._super(obj), function(result) { if (result.participants) { result.participants = result.participants.map(function(u) { @@ -413,9 +419,7 @@ window.Discourse.Topic.reopenClass({ }); result.fewParticipants = Em.A(); return result.participants.each(function(p) { - if (result.fewParticipants.length >= 8) { - return false; - } + if (result.fewParticipants.length >= 8) return false; result.fewParticipants.pushObject(p); return true; }); diff --git a/app/assets/javascripts/discourse/templates/topic.js.handlebars b/app/assets/javascripts/discourse/templates/topic.js.handlebars index fec4e5dcd86..df6107c6048 100644 --- a/app/assets/javascripts/discourse/templates/topic.js.handlebars +++ b/app/assets/javascripts/discourse/templates/topic.js.handlebars @@ -8,7 +8,7 @@ {{#if view.showFavoriteButton}} {{/if}} - {{#if view.editingTopic}} + {{#if view.editingTopic}} {{view Discourse.ComboboxViewCategory valueAttribute="name" contentBinding="view.categories" valueBinding="view.topic.categoryName"}} @@ -19,8 +19,8 @@ {{view Discourse.TopicStatusView topicBinding="view.topic"}} {{{unbound view.topic.fancy_title}}} {{else}} - {{#if view.topic.missing}} - {{i18n topic.not_found.title}} + {{#if view.topic.errorLoading}} + {{view.topic.errorTitle}} {{else}} {{i18n topic.loading}} {{/if}} @@ -33,7 +33,7 @@ {{/if}} - + {{/if}} @@ -102,7 +102,7 @@ {{/if}} - + diff --git a/app/assets/javascripts/discourse/templates/topic_extra_info.js.handlebars b/app/assets/javascripts/discourse/templates/topic_extra_info.js.handlebars index 1b5520d2123..8809fa5a70e 100644 --- a/app/assets/javascripts/discourse/templates/topic_extra_info.js.handlebars +++ b/app/assets/javascripts/discourse/templates/topic_extra_info.js.handlebars @@ -7,8 +7,8 @@ {{view Discourse.TopicStatusView topicBinding="view.topic"}} {{{view.topic.fancy_title}}} {{else}} - {{#if view.topic.missing}} - {{i18n topic.not_found.title}} + {{#if view.topic.errorLoading}} + {{topic.errorTitle}} {{else}} {{i18n topic.loading}} {{/if}} diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb index a432f77c96c..682e52b5a7f 100644 --- a/app/controllers/topics_controller.rb +++ b/app/controllers/topics_controller.rb @@ -129,12 +129,12 @@ class TopicsController < ApplicationController end def timings - + PostTiming.process_timings( - current_user, - params[:topic_id].to_i, - params[:highest_seen].to_i, - params[:topic_time].to_i, + current_user, + params[:topic_id].to_i, + params[:highest_seen].to_i, + params[:topic_time].to_i, (params[:timings] || []).map{|post_number, t| [post_number.to_i, t.to_i]} ) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 7566edfd7c2..120a415c384 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -170,7 +170,7 @@ en: filters: all: "All" - + stream: posted_by: "Posted by" sent_by: "Sent by" @@ -341,10 +341,15 @@ en: title: 'Topic' loading_more: "Loading more Topics..." loading: 'Loading topic...' - missing: "Topic Not Found" + invalid_access: + title: "You can't do that!" + description: "You don't have access to view that topic." + server_error: + title: "Error loading topic!" + description: "Sorry, we couldn't load that topic, possibly due to a connection problem. Please try again." not_found: - title: "Topic Not Found" - description: "Sorry, we couldn't load that topic, possibly due to a connection problem. Please try again. If the problem persists, perhaps the topic was deleted." + title: "Topic not found!" + description: "That topic could not be found. It's likely it was deleted by a moderator." unread_posts: "you have {{unread}} unread old posts in this topic" new_posts: "there are {{new_posts}} new posts in this topic since you last read it" likes: "there are {{likes}} likes in this topic"