From a519fd5bcf0f62b465cf7e7aed2b1661aa0ea14a Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 12 Feb 2015 15:37:02 -0500 Subject: [PATCH] FIX: Highlighting was not being applied after some rendering. Also includes a bunch of ES6 stuff. --- .../discourse/controllers/topic.js.es6 | 11 +- .../initializers/post-decorations.js.es6 | 11 + .../discourse/lib/highlight-syntax.js.es6 | 10 + .../javascripts/discourse/lib/lightbox.js | 54 --- .../javascripts/discourse/lib/lightbox.js.es6 | 45 ++ .../discourse/lib/search-for-term.js.es6 | 8 +- .../discourse/lib/syntax_highlighting.js | 26 -- .../javascripts/discourse/models/composer.js | 1 + .../{post_stream.js => post-stream.js.es6} | 404 ++++++------------ ...{topic_details.js => topic-details.js.es6} | 20 +- .../models/{topic.js => topic.js.es6} | 167 ++++---- .../discourse/routes/topic-by-slug.js.es6 | 4 +- .../javascripts/discourse/routes/topic.js.es6 | 3 +- .../discourse/views/composer.js.es6 | 2 - .../javascripts/discourse/views/post.js.es6 | 2 - app/assets/javascripts/main_include.js | 2 + .../javascripts/controllers/topic-test.js.es6 | 4 +- .../mixins/selected-posts-count-test.js.es6 | 4 +- .../models/post-stream-test.js.es6 | 9 +- .../models/topic-details-test.js.es6 | 12 +- test/javascripts/models/topic-test.js.es6 | 18 +- 21 files changed, 314 insertions(+), 503 deletions(-) create mode 100644 app/assets/javascripts/discourse/initializers/post-decorations.js.es6 create mode 100644 app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 delete mode 100644 app/assets/javascripts/discourse/lib/lightbox.js create mode 100644 app/assets/javascripts/discourse/lib/lightbox.js.es6 delete mode 100644 app/assets/javascripts/discourse/lib/syntax_highlighting.js rename app/assets/javascripts/discourse/models/{post_stream.js => post-stream.js.es6} (65%) rename app/assets/javascripts/discourse/models/{topic_details.js => topic-details.js.es6} (86%) rename app/assets/javascripts/discourse/models/{topic.js => topic.js.es6} (77%) diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index 0d88867463d..40cfab14eeb 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -1,6 +1,7 @@ import ObjectController from 'discourse/controllers/object'; import BufferedContent from 'discourse/mixins/buffered-content'; import { spinnerHTML } from 'discourse/helpers/loading-spinner'; +import Topic from 'discourse/models/topic'; export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedContent, { multiSelect: false, @@ -272,7 +273,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon var self = this, props = this.get('buffered.buffer'); - Discourse.Topic.update(this.get('model'), props).then(function() { + Topic.update(this.get('model'), props).then(function() { // Note we roll back on success here because `update` saves // the properties to the topic. self.rollbackBuffer(); @@ -555,13 +556,13 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon }, // Receive notifications for this topic - subscribe: function() { + subscribe() { // Unsubscribe before subscribing again this.unsubscribe(); - var topicController = this; + const self = this; Discourse.MessageBus.subscribe("/topic/" + this.get('id'), function(data) { - var topic = topicController.get('model'); + const topic = self.get('model'); if (data.notification_level_change) { topic.set('details.notification_level', data.notification_level_change); @@ -569,7 +570,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon return; } - var postStream = topicController.get('postStream'); + const postStream = self.get('postStream'); switch (data.type) { case "revised": case "acted": diff --git a/app/assets/javascripts/discourse/initializers/post-decorations.js.es6 b/app/assets/javascripts/discourse/initializers/post-decorations.js.es6 new file mode 100644 index 00000000000..5d82473b89a --- /dev/null +++ b/app/assets/javascripts/discourse/initializers/post-decorations.js.es6 @@ -0,0 +1,11 @@ +import { decorateCooked } from 'discourse/lib/plugin-api'; +import HighlightSyntax from 'discourse/lib/highlight-syntax'; +import Lightbox from 'discourse/lib/lightbox'; + +export default { + name: "post-decorations", + initialize: function(container) { + decorateCooked(container, HighlightSyntax); + decorateCooked(container, Lightbox); + } +}; diff --git a/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 b/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 new file mode 100644 index 00000000000..784add9d223 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 @@ -0,0 +1,10 @@ +/*global hljs:true */ + +export default function highlightSyntax($elem) { + const selector = Discourse.SiteSettings.autohighlight_all_code ? 'pre code' : 'pre code[class]'; + $(selector, $elem).each(function(i, e) { + return $LAB.script("/javascripts/highlight.pack.js").wait(function() { + return hljs.highlightBlock(e); + }); + }); +} diff --git a/app/assets/javascripts/discourse/lib/lightbox.js b/app/assets/javascripts/discourse/lib/lightbox.js deleted file mode 100644 index 143393109f9..00000000000 --- a/app/assets/javascripts/discourse/lib/lightbox.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - Helper object for lightboxes. - - @class Lightbox - @namespace Discourse - @module Discourse -**/ -Discourse.Lightbox = { - apply: function($elem) { - $LAB.script("/javascripts/jquery.magnific-popup-min.js").wait(function() { - $("a.lightbox", $elem).each(function(i, e) { - var $e = $(e); - // do not lightbox spoiled images - if ($e.parents(".spoiler").length > 0 || $e.parents(".spoiled").length > 0) { return; } - - $e.magnificPopup({ - type: "image", - closeOnContentClick: false, - removalDelay: 300, - mainClass: "mfp-zoom-in", - - callbacks: { - open: function() { - var wrap = this.wrap, - img = this.currItem.img, - maxHeight = img.css("max-height"); - - wrap.on("click.pinhandler", "img", function() { - wrap.toggleClass("mfp-force-scrollbars"); - img.css("max-height", wrap.hasClass("mfp-force-scrollbars") ? "none" : maxHeight); - }); - }, - beforeClose: function() { - this.wrap.off("click.pinhandler"); - this.wrap.removeClass("mfp-force-scrollbars"); - } - }, - - image: { - titleSrc: function(item) { - var href = item.el.data("download-href") || item.src; - return [ - item.el.attr("title"), - $("span.informations", item.el).text().replace('x', '×'), - '' + I18n.t("lightbox.download") + '' - ].join(' · '); - } - } - - }); - }); - }); - } -}; diff --git a/app/assets/javascripts/discourse/lib/lightbox.js.es6 b/app/assets/javascripts/discourse/lib/lightbox.js.es6 new file mode 100644 index 00000000000..b5f272180a8 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/lightbox.js.es6 @@ -0,0 +1,45 @@ +export default function($elem) { + $("a.lightbox", $elem).each(function(i, e) { + $LAB.script("/javascripts/jquery.magnific-popup-min.js").wait(function() { + var $e = $(e); + // do not lightbox spoiled images + if ($e.parents(".spoiler").length > 0 || $e.parents(".spoiled").length > 0) { return; } + + $e.magnificPopup({ + type: "image", + closeOnContentClick: false, + removalDelay: 300, + mainClass: "mfp-zoom-in", + + callbacks: { + open: function() { + var wrap = this.wrap, + img = this.currItem.img, + maxHeight = img.css("max-height"); + + wrap.on("click.pinhandler", "img", function() { + wrap.toggleClass("mfp-force-scrollbars"); + img.css("max-height", wrap.hasClass("mfp-force-scrollbars") ? "none" : maxHeight); + }); + }, + beforeClose: function() { + this.wrap.off("click.pinhandler"); + this.wrap.removeClass("mfp-force-scrollbars"); + } + }, + + image: { + titleSrc: function(item) { + var href = item.el.data("download-href") || item.src; + return [ + item.el.attr("title"), + $("span.informations", item.el).text().replace('x', '×'), + '' + I18n.t("lightbox.download") + '' + ].join(' · '); + } + } + + }); + }); + }); +} diff --git a/app/assets/javascripts/discourse/lib/search-for-term.js.es6 b/app/assets/javascripts/discourse/lib/search-for-term.js.es6 index 9f9c3fabaa3..0c4f77dc715 100644 --- a/app/assets/javascripts/discourse/lib/search-for-term.js.es6 +++ b/app/assets/javascripts/discourse/lib/search-for-term.js.es6 @@ -1,4 +1,6 @@ -export default function searchForTerm(term, opts) { +import Topic from 'discourse/models/topic'; + +function searchForTerm(term, opts) { if (!opts) opts = {}; // Only include the data we have @@ -22,7 +24,7 @@ export default function searchForTerm(term, opts) { var topicMap = {}; results.topics = results.topics.map(function(topic){ - topic = Discourse.Topic.create(topic); + topic = Topic.create(topic); topicMap[topic.id] = topic; return topic; }); @@ -66,3 +68,5 @@ export default function searchForTerm(term, opts) { return noResults ? null : Em.Object.create(results); }); } + +export default searchForTerm; diff --git a/app/assets/javascripts/discourse/lib/syntax_highlighting.js b/app/assets/javascripts/discourse/lib/syntax_highlighting.js deleted file mode 100644 index 794375a9a49..00000000000 --- a/app/assets/javascripts/discourse/lib/syntax_highlighting.js +++ /dev/null @@ -1,26 +0,0 @@ -/*global hljs:true */ - -/** - Helper object for syntax highlighting. Uses highlight.js which is loaded on demand. - - @class SyntaxHighlighting - @namespace Discourse - @module Discourse -**/ -Discourse.SyntaxHighlighting = { - - /** - Apply syntax highlighting to a jQuery element - - @method apply - @param {jQuery.selector} $elem The element we want to apply our highlighting to - **/ - apply: function($elem) { - var selector = Discourse.SiteSettings.autohighlight_all_code ? 'pre code' : 'pre code[class]'; - $(selector, $elem).each(function(i, e) { - return $LAB.script("/javascripts/highlight.pack.js").wait(function() { - return hljs.highlightBlock(e); - }); - }); - } -}; diff --git a/app/assets/javascripts/discourse/models/composer.js b/app/assets/javascripts/discourse/models/composer.js index 3103c80b19c..d8277785456 100644 --- a/app/assets/javascripts/discourse/models/composer.js +++ b/app/assets/javascripts/discourse/models/composer.js @@ -532,6 +532,7 @@ Discourse.Composer = Discourse.Model.extend({ }); } + // If we're in a topic, we can append the post instantly. if (postStream) { // If it's in reply to another post, increase the reply count diff --git a/app/assets/javascripts/discourse/models/post_stream.js b/app/assets/javascripts/discourse/models/post-stream.js.es6 similarity index 65% rename from app/assets/javascripts/discourse/models/post_stream.js rename to app/assets/javascripts/discourse/models/post-stream.js.es6 index 2a35c6ac8ae..8116e41be73 100644 --- a/app/assets/javascripts/discourse/models/post_stream.js +++ b/app/assets/javascripts/discourse/models/post-stream.js.es6 @@ -1,5 +1,4 @@ -Discourse.PostStream = Em.Object.extend({ - +const PostStream = Ember.Object.extend({ loading: Em.computed.or('loadingAbove', 'loadingBelow', 'loadingFilter', 'stagingPost'), notLoading: Em.computed.not('loading'), filteredPostsCount: Em.computed.alias("stream.length"), @@ -45,15 +44,13 @@ Discourse.PostStream = Em.Object.extend({ /** Returns a JS Object of current stream filter options. It should match the query params for the stream. - - @property streamFilters **/ streamFilters: function() { - var result = {}; + const result = {}; if (this.get('summary')) { result.filter = "summary"; } if (this.get('show_deleted')) { result.show_deleted = true; } - var userFilters = this.get('userFilters'); + const userFilters = this.get('userFilters'); if (!Em.isEmpty(userFilters)) { result.username_filters = userFilters.join(","); } @@ -62,27 +59,25 @@ Discourse.PostStream = Em.Object.extend({ }.property('userFilters.[]', 'summary', 'show_deleted'), hasNoFilters: function() { - var streamFilters = this.get('streamFilters'); + const streamFilters = this.get('streamFilters'); return !(streamFilters && ((streamFilters.filter === 'summary') || streamFilters.username_filters)); }.property('streamFilters.[]', 'topic.posts_count', 'posts.length'), /** Returns the window of posts above the current set in the stream, bound to the top of the stream. This is the collection we'll ask for when scrolling upwards. - - @property previousWindow **/ previousWindow: function() { // If we can't find the last post loaded, bail - var firstPost = _.first(this.get('posts')); + const firstPost = _.first(this.get('posts')); if (!firstPost) { return []; } // Find the index of the last post loaded, if not found, bail - var stream = this.get('stream'); - var firstIndex = this.indexOf(firstPost); + const stream = this.get('stream'); + const firstIndex = this.indexOf(firstPost); if (firstIndex === -1) { return []; } - var startIndex = firstIndex - this.get('topic.chunk_size'); + let startIndex = firstIndex - this.get('topic.chunk_size'); if (startIndex < 0) { startIndex = 0; } return stream.slice(startIndex, firstIndex); @@ -91,17 +86,15 @@ Discourse.PostStream = Em.Object.extend({ /** Returns the window of posts below the current set in the stream, bound by the bottom of the stream. This is the collection we use when scrolling downwards. - - @property nextWindow **/ nextWindow: function() { // If we can't find the last post loaded, bail - var lastLoadedPost = this.get('lastLoadedPost'); + const lastLoadedPost = this.get('lastLoadedPost'); if (!lastLoadedPost) { return []; } // Find the index of the last post loaded, if not found, bail - var stream = this.get('stream'); - var lastIndex = this.indexOf(lastLoadedPost); + const stream = this.get('stream'); + const lastIndex = this.indexOf(lastLoadedPost); if (lastIndex === -1) { return []; } if ((lastIndex + 1) >= this.get('highest_post_number')) { return []; } @@ -109,41 +102,26 @@ Discourse.PostStream = Em.Object.extend({ return stream.slice(lastIndex+1, lastIndex + this.get('topic.chunk_size') + 1); }.property('lastLoadedPost', 'stream.@each'), - - /** - Cancel any active filters on the stream. - - @method cancelFilter - **/ - cancelFilter: function() { + cancelFilter() { this.set('summary', false); this.set('show_deleted', false); this.get('userFilters').clear(); }, - /** - Toggle summary mode for the stream. - - @method toggleSummary - **/ - toggleSummary: function() { + toggleSummary() { this.get('userFilters').clear(); this.toggleProperty('summary'); return this.refresh(); }, - toggleDeleted: function() { + toggleDeleted() { this.toggleProperty('show_deleted'); return this.refresh(); }, - /** - Filter the stream to a particular user. - - @method toggleParticipant - **/ - toggleParticipant: function(username) { - var userFilters = this.get('userFilters'); + // Filter the stream to a particular user. + toggleParticipant(username) { + const userFilters = this.get('userFilters'); this.set('summary', false); this.set('show_deleted', true); if (userFilters.contains(username)) { @@ -157,22 +135,16 @@ Discourse.PostStream = Em.Object.extend({ /** Loads a new set of posts into the stream. If you provide a `nearPost` option and the post is already loaded, it will simply scroll there and load nothing. - - @method refresh - @param {Object} opts Options for loading the stream - @param {Integer} opts.nearPost The post we want to find other posts near to. - @param {Boolean} opts.track_visit Whether or not to track this as a visit to a topic. - @returns {Promise} a promise that is resolved when the posts have been inserted into the stream. **/ - refresh: function(opts) { + refresh(opts) { opts = opts || {}; opts.nearPost = parseInt(opts.nearPost, 10); - var topic = this.get('topic'), + const topic = this.get('topic'), self = this; // Do we already have the post in our list of posts? Jump there. - var postWeWant = this.get('posts').findProperty('post_number', opts.nearPost); + const postWeWant = this.get('posts').findProperty('post_number', opts.nearPost); if (postWeWant) { return Ember.RSVP.resolve(); } // TODO: if we have all the posts in the filter, don't go to the server for them. @@ -192,10 +164,10 @@ Discourse.PostStream = Em.Object.extend({ }, hasLoadedData: Em.computed.and('hasPosts', 'hasStream'), - collapsePosts: function(from, to){ - var posts = this.get('posts'); - var remove = posts.filter(function(post){ - var postNumber = post.get('post_number'); + collapsePosts(from, to){ + const posts = this.get('posts'); + const remove = posts.filter(function(post){ + const postNumber = post.get('post_number'); return postNumber >= from && postNumber <= to; }); @@ -203,9 +175,9 @@ Discourse.PostStream = Em.Object.extend({ // make gap this.set('gaps', this.get('gaps') || {before: {}, after: {}}); - var before = this.get('gaps.before'); + const before = this.get('gaps.before'); - var post = posts.find(function(post){ + const post = posts.find(function(post){ return post.get('post_number') > to; }); @@ -218,16 +190,9 @@ Discourse.PostStream = Em.Object.extend({ }, - /** - Fill in a gap of posts before a particular post - - @method fillGapBefore - @paaram {Discourse.Post} post beside gap - @paaram {Array} gap array of post ids to load - @returns {Promise} a promise that's resolved when the posts have been added. - **/ - fillGapBefore: function(post, gap) { - var postId = post.get('id'), + // Fill in a gap of posts before a particular post + fillGapBefore(post, gap) { + const postId = post.get('id'), stream = this.get('stream'), idx = stream.indexOf(postId), currentPosts = this.get('posts'), @@ -237,11 +202,11 @@ Discourse.PostStream = Em.Object.extend({ // Insert the gap at the appropriate place stream.splice.apply(stream, [idx, 0].concat(gap)); - var postIdx = currentPosts.indexOf(post); + let postIdx = currentPosts.indexOf(post); if (postIdx !== -1) { return this.findPostsByIds(gap).then(function(posts) { posts.forEach(function(p) { - var stored = self.storePost(p); + const stored = self.storePost(p); if (!currentPosts.contains(stored)) { currentPosts.insertAt(postIdx++, stored); } @@ -256,16 +221,9 @@ Discourse.PostStream = Em.Object.extend({ return Ember.RSVP.resolve(); }, - /** - Fill in a gap of posts after a particular post - - @method fillGapAfter - @paaram {Discourse.Post} post beside gap - @paaram {Array} gap array of post ids to load - @returns {Promise} a promise that's resolved when the posts have been added. - **/ - fillGapAfter: function(post, gap) { - var postId = post.get('id'), + // Fill in a gap of posts after a particular post + fillGapAfter(post, gap) { + const postId = post.get('id'), stream = this.get('stream'), idx = stream.indexOf(postId), self = this; @@ -279,24 +237,19 @@ Discourse.PostStream = Em.Object.extend({ return Ember.RSVP.resolve(); }, - /** - Appends the next window of posts to the stream. Call it when scrolling downwards. - - @method appendMore - @returns {Promise} a promise that's resolved when the posts have been added. - **/ - appendMore: function() { - var self = this; + // Appends the next window of posts to the stream. Call it when scrolling downwards. + appendMore() { + const self = this; // Make sure we can append more posts if (!self.get('canAppendMore')) { return Ember.RSVP.resolve(); } - var postIds = self.get('nextWindow'); + const postIds = self.get('nextWindow'); if (Ember.isEmpty(postIds)) { return Ember.RSVP.resolve(); } self.set('loadingBelow', true); - var stopLoading = function() { + const stopLoading = function() { self.set('loadingBelow', false); }; @@ -308,19 +261,14 @@ Discourse.PostStream = Em.Object.extend({ }, stopLoading); }, - /** - Prepend the previous window of posts to the stream. Call it when scrolling upwards. - - @method prependMore - @returns {Promise} a promise that's resolved when the posts have been added. - **/ - prependMore: function() { - var postStream = this; + // Prepend the previous window of posts to the stream. Call it when scrolling upwards. + prependMore() { + const postStream = this; // Make sure we can append more posts if (!postStream.get('canPrependMore')) { return Ember.RSVP.resolve(); } - var postIds = postStream.get('previousWindow'); + const postIds = postStream.get('previousWindow'); if (Ember.isEmpty(postIds)) { return Ember.RSVP.resolve(); } postStream.set('loadingAbove', true); @@ -336,18 +284,13 @@ Discourse.PostStream = Em.Object.extend({ Stage a post for insertion in the stream. It should be rendered right away under the assumption that the post will succeed. We can then `commitPost` when it succeeds or `undoPost` when it fails. - - @method stagePost - @param {Discourse.Post} post the post to stage in the stream - @param {Discourse.User} user the user creating the post **/ - stagePost: function(post, user) { - + stagePost(post, user) { // We can't stage two posts simultaneously if (this.get('stagingPost')) { return false; } this.set('stagingPost', true); - var topic = this.get('topic'); + const topic = this.get('topic'); topic.setProperties({ posts_count: (topic.get('posts_count') || 0) + 1, last_posted_at: new Date(), @@ -371,13 +314,8 @@ Discourse.PostStream = Em.Object.extend({ return true; }, - /** - Commit the post we staged. Call this after a save succeeds. - - @method commitPost - @param {Discourse.Post} the post we saved in the stream. - **/ - commitPost: function(post) { + // Commit the post we staged. Call this after a save succeeds. + commitPost(post) { if (this.get('loadedAllPosts')) { this.appendPost(post); } @@ -398,16 +336,13 @@ Discourse.PostStream = Em.Object.extend({ /** Undo a post we've staged in the stream. Remove it from being rendered and revert the state we changed. - - @method undoPost - @param {Discourse.Post} the post to undo from the stream **/ - undoPost: function(post) { + undoPost(post) { this.get('stream').removeObject(-1); this.posts.removeObject(post); this.get('postIdentityMap').set(-1, null); - var topic = this.get('topic'); + const topic = this.get('topic'); this.set('stagingPost', false); topic.setProperties({ @@ -418,44 +353,24 @@ Discourse.PostStream = Em.Object.extend({ // TODO unfudge reply count on parent post }, - /** - Prepends a single post to the stream. - - @method prependPost - @param {Discourse.Post} post The post we're prepending - @returns {Discourse.Post} the post that was inserted. - **/ - prependPost: function(post) { + prependPost(post) { this.get('posts').unshiftObject(this.storePost(post)); return post; }, - /** - Appends a single post into the stream. - - @method appendPost - @param {Discourse.Post} post The post we're appending - @returns {Discourse.Post} the post that was inserted. - **/ - appendPost: function(post) { - var stored = this.storePost(post); + appendPost(post) { + const stored = this.storePost(post); if (stored) { this.get('posts').addObject(stored); } return post; }, - /** - Removes posts from the stream. - - @method removePosts - @param {Array} posts the collection of posts to remove - **/ - removePosts: function(posts) { + removePosts(posts) { if (Em.isEmpty(posts)) { return; } - var postIds = posts.map(function (p) { return p.get('id'); }); - var identityMap = this.get('postIdentityMap'); + const postIds = posts.map(function (p) { return p.get('id'); }); + const identityMap = this.get('postIdentityMap'); this.get('stream').removeObjects(postIds); this.get('posts').removeObjects(posts); @@ -464,14 +379,8 @@ Discourse.PostStream = Em.Object.extend({ }); }, - /** - Returns a post from the identity map if it's been inserted. - - @method findLoadedPost - @param {Integer} id The post we want from the identity map. - @returns {Discourse.Post} the post that was inserted. - **/ - findLoadedPost: function(id) { + // Returns a post from the identity map if it's been inserted. + findLoadedPost(id) { return this.get('postIdentityMap').get(id); }, @@ -479,17 +388,14 @@ Discourse.PostStream = Em.Object.extend({ Finds and adds a post to the stream by id. Typically this would happen if we receive a message from the message bus indicating there's a new post. We'll only insert it if we currently have no filters. - - @method triggerNewPostInStream - @param {Integer} postId The id of the new post to be inserted into the stream **/ - triggerNewPostInStream: function(postId) { + triggerNewPostInStream(postId) { if (!postId) { return; } // We only trigger if there are no filters active if (!this.get('hasNoFilters')) { return; } - var loadedAllPosts = this.get('loadedAllPosts'); + const loadedAllPosts = this.get('loadedAllPosts'); if (this.get('stream').indexOf(postId) === -1) { this.get('stream').addObject(postId); @@ -497,8 +403,8 @@ Discourse.PostStream = Em.Object.extend({ } }, - triggerRecoveredPost: function(postId){ - var self = this, + triggerRecoveredPost(postId){ + const self = this, postIdentityMap = this.get('postIdentityMap'), existing = postIdentityMap.get(postId); @@ -506,15 +412,15 @@ Discourse.PostStream = Em.Object.extend({ this.triggerChangedPost(postId, new Date()); } else { // need to insert into stream - var url = "/posts/" + postId; + const url = "/posts/" + postId; Discourse.ajax(url).then(function(p){ - var post = Discourse.Post.create(p); - var stream = self.get("stream"); - var posts = self.get("posts"); + const post = Discourse.Post.create(p); + const stream = self.get("stream"); + const posts = self.get("posts"); self.storePost(post); // we need to zip this into the stream - var index = 0; + let index = 0; stream.forEach(function(postId){ if(postId < p.id){ index+= 1; @@ -541,13 +447,13 @@ Discourse.PostStream = Em.Object.extend({ } }, - triggerDeletedPost: function(postId){ - var self = this, + triggerDeletedPost(postId){ + const self = this, postIdentityMap = this.get('postIdentityMap'), existing = postIdentityMap.get(postId); if(existing){ - var url = "/posts/" + postId; + const url = "/posts/" + postId; Discourse.ajax(url).then( function(p){ self.storePost(Discourse.Post.create(p)); @@ -558,30 +464,24 @@ Discourse.PostStream = Em.Object.extend({ } }, - triggerChangedPost: function(postId, updatedAt) { + triggerChangedPost(postId, updatedAt) { if (!postId) { return; } - var postIdentityMap = this.get('postIdentityMap'), + const postIdentityMap = this.get('postIdentityMap'), existing = postIdentityMap.get(postId), self = this; if (existing && existing.updated_at !== updatedAt) { - var url = "/posts/" + postId; + const url = "/posts/" + postId; Discourse.ajax(url).then(function(p){ self.storePost(Discourse.Post.create(p)); }); } }, - /** - Returns the "thread" of posts in the history of a post. - - @method findReplyHistory - @param {Discourse.Post} post the post whose history we want - @returns {Array} the posts in the history. - **/ - findReplyHistory: function(post) { - var postStream = this, + // Returns the "thread" of posts in the history of a post. + findReplyHistory(post) { + const postStream = this, url = "/posts/" + post.get('id') + "/reply-history.json?max_replies=" + Discourse.SiteSettings.max_reply_history; return Discourse.ajax(url).then(function(result) { @@ -597,16 +497,11 @@ Discourse.PostStream = Em.Object.extend({ Returns the closest post given a postNumber that may not exist in the stream. For example, if the user asks for a post that's deleted or otherwise outside the range. This allows us to set the progress bar with the correct number. - - @method closestPostForPostNumber - @param {Number} postNumber the post number we're looking for - @return {Post} the closest post - @see PostStream.closestPostNumberFor **/ - closestPostForPostNumber: function(postNumber) { + closestPostForPostNumber(postNumber) { if (!this.get('hasPosts')) { return; } - var closest = null; + let closest = null; this.get('posts').forEach(function (p) { if (!closest) { closest = p; @@ -628,17 +523,12 @@ Discourse.PostStream = Em.Object.extend({ @returns {Number} 1-starting index of the post, or 0 if not found @see PostStream.progressIndexOfPostId **/ - progressIndexOfPost: function(post) { + progressIndexOfPost(post) { return this.progressIndexOfPostId(post.get('id')); }, - /** - Get the index in the stream of a post id. (Use this for the topic progress bar.) - - @param post_id - post id to search for - @returns {Number} 1-starting index of the post, or 0 if not found - **/ - progressIndexOfPostId: function(post_id) { + // Get the index in the stream of a post id. (Use this for the topic progress bar.) + progressIndexOfPostId(post_id) { return this.get('stream').indexOf(post_id) + 1; }, @@ -646,15 +536,11 @@ Discourse.PostStream = Em.Object.extend({ Returns the closest post number given a postNumber that may not exist in the stream. For example, if the user asks for a post that's deleted or otherwise outside the range. This allows us to set the progress bar with the correct number. - - @method closestPostNumberFor - @param {Number} postNumber the post number we're looking for - @return {Number} a close post number **/ - closestPostNumberFor: function(postNumber) { + closestPostNumberFor(postNumber) { if (!this.get('hasPosts')) { return; } - var closest = null; + let closest = null; this.get('posts').forEach(function (p) { if (closest === postNumber) { return; } if (!closest) { closest = p.get('post_number'); } @@ -668,41 +554,33 @@ Discourse.PostStream = Em.Object.extend({ }, // Find a postId for a postNumber, respecting gaps - findPostIdForPostNumber: function(postNumber) { - var count = 1, - stream = this.get('stream'), - beforeLookup = this.get('gaps.before'), - streamLength = stream.length; + findPostIdForPostNumber(postNumber) { + const stream = this.get('stream'), + beforeLookup = this.get('gaps.before'), + streamLength = stream.length; - for (var i=0; i (this.get('topic.highest_post_number') || 0)) { this.set('topic.highest_post_number', postNumber); } @@ -761,17 +633,11 @@ Discourse.PostStream = Em.Object.extend({ }, /** - @private - Given a list of postIds, returns a list of the posts we don't have in our identity map and need to load. - - @method listUnloadedIds - @param {Array} postIds The post Ids we want to load from the server - @returns {Array} the array of postIds we don't have loaded. **/ - listUnloadedIds: function(postIds) { - var unloaded = Em.A(), + listUnloadedIds(postIds) { + const unloaded = Em.A(), postIdentityMap = this.get('postIdentityMap'); postIds.forEach(function(p) { if (!postIdentityMap.has(p)) { unloaded.pushObject(p); } @@ -779,17 +645,8 @@ Discourse.PostStream = Em.Object.extend({ return unloaded; }, - /** - @private - - Returns a list of posts in order requested, by id. - - @method findPostsByIds - @param {Array} postIds The post Ids we want to retrieve, in order. - @returns {Promise} a promise that will resolve to the posts in the order requested. - **/ - findPostsByIds: function(postIds) { - var unloaded = this.listUnloadedIds(postIds), + findPostsByIds(postIds) { + const unloaded = this.listUnloadedIds(postIds), postIdentityMap = this.get('postIdentityMap'); // Load our unloaded posts by id @@ -800,27 +657,18 @@ Discourse.PostStream = Em.Object.extend({ }); }, - /** - @private - - Loads a list of posts from the server and inserts them into our identity map. - - @method loadIntoIdentityMap - @param {Array} postIds The post Ids we want to insert into the identity map. - @returns {Promise} a promise that will resolve to the posts in the order requested. - **/ - loadIntoIdentityMap: function(postIds) { + loadIntoIdentityMap(postIds) { // If we don't want any posts, return a promise that resolves right away if (Em.isEmpty(postIds)) { return Ember.RSVP.resolve(); } - var url = "/t/" + this.get('topic.id') + "/posts.json", + const url = "/t/" + this.get('topic.id') + "/posts.json", data = { post_ids: postIds }, postStream = this; return Discourse.ajax(url, {data: data}).then(function(result) { - var posts = Em.get(result, "post_stream.posts"); + const posts = Em.get(result, "post_stream.posts"); if (posts) { posts.forEach(function (p) { postStream.storePost(Discourse.Post.create(p)); @@ -830,33 +678,19 @@ Discourse.PostStream = Em.Object.extend({ }, - /** - @private - - Returns the index of a particular post in the stream - - @method indexOf - @param {Discourse.Post} post The post we're looking for - **/ - indexOf: function(post) { + indexOf(post) { return this.get('stream').indexOf(post.get('id')); }, /** - @private - Handles an error loading a topic based on a HTTP status code. Updates the text to the correct values. - - @method errorLoading - @param {Integer} status the HTTP status code - @param {Discourse.Topic} topic The topic instance we were trying to load **/ - errorLoading: function(result) { - var status = result.status; + errorLoading(result) { + const status = result.status; - var topic = this.get('topic'); + const topic = this.get('topic'); topic.set('loadingFilter', false); topic.set('errorLoading', true); @@ -887,10 +721,10 @@ Discourse.PostStream = Em.Object.extend({ }); -Discourse.PostStream.reopenClass({ +PostStream.reopenClass({ - create: function() { - var postStream = this._super.apply(this, arguments); + create() { + const postStream = this._super.apply(this, arguments); postStream.setProperties({ posts: [], stream: [], @@ -906,9 +740,9 @@ Discourse.PostStream.reopenClass({ return postStream; }, - loadTopicView: function(topicId, args) { - var opts = _.merge({}, args), - url = Discourse.getURL("/t/") + topicId; + loadTopicView(topicId, args) { + const opts = _.merge({}, args); + let url = Discourse.getURL("/t/") + topicId; if (opts.nearPost) { url += "/" + opts.nearPost; } @@ -921,3 +755,5 @@ Discourse.PostStream.reopenClass({ } }); + +export default PostStream; diff --git a/app/assets/javascripts/discourse/models/topic_details.js b/app/assets/javascripts/discourse/models/topic-details.js.es6 similarity index 86% rename from app/assets/javascripts/discourse/models/topic_details.js rename to app/assets/javascripts/discourse/models/topic-details.js.es6 index 280a1bb9800..6e6c1b05b2a 100644 --- a/app/assets/javascripts/discourse/models/topic_details.js +++ b/app/assets/javascripts/discourse/models/topic-details.js.es6 @@ -1,16 +1,13 @@ /** A model representing a Topic's details that aren't always present, such as a list of participants. When showing topics in lists and such this information should not be required. - - @class TopicDetails - @extends Discourse.Model - @namespace Discourse - @module Discourse **/ -Discourse.TopicDetails = Discourse.Model.extend({ +const TopicDetails = Discourse.Model.extend({ loaded: false, - updateFromJson: function(details) { + updateFromJson(details) { + const topic = this.get('topic'); + if (details.allowed_users) { details.allowed_users = details.allowed_users.map(function (u) { return Discourse.User.create(u); @@ -24,10 +21,9 @@ Discourse.TopicDetails = Discourse.Model.extend({ } if (details.participants) { - var topic = this.get('topic'); details.participants = details.participants.map(function (p) { p.topic = topic; - return Em.Object.create(p); + return Ember.Object.create(p); }); } @@ -59,7 +55,7 @@ Discourse.TopicDetails = Discourse.Model.extend({ }.property('notification_level', 'notifications_reason_id'), - updateNotifications: function(v) { + updateNotifications(v) { this.set('notification_level', v); this.set('notifications_reason_id', null); return Discourse.ajax("/t/" + (this.get('topic.id')) + "/notifications", { @@ -68,7 +64,7 @@ Discourse.TopicDetails = Discourse.Model.extend({ }); }, - removeAllowedUser: function(user) { + removeAllowedUser(user) { var users = this.get('allowed_users'), username = user.get('username'); @@ -80,3 +76,5 @@ Discourse.TopicDetails = Discourse.Model.extend({ }); } }); + +export default TopicDetails; diff --git a/app/assets/javascripts/discourse/models/topic.js b/app/assets/javascripts/discourse/models/topic.js.es6 similarity index 77% rename from app/assets/javascripts/discourse/models/topic.js rename to app/assets/javascripts/discourse/models/topic.js.es6 index 0d301fe188c..cd134683a25 100644 --- a/app/assets/javascripts/discourse/models/topic.js +++ b/app/assets/javascripts/discourse/models/topic.js.es6 @@ -1,8 +1,11 @@ -Discourse.Topic = Discourse.Model.extend({ +import TopicDetails from 'discourse/models/topic-details'; +import PostStream from 'discourse/models/post-stream'; + +const Topic = Discourse.Model.extend({ // returns createdAt if there's no bumped date bumpedAt: function() { - var bumpedAt = this.get('bumped_at'); + const bumpedAt = this.get('bumped_at'); if (bumpedAt) { return new Date(bumpedAt); } else { @@ -20,11 +23,11 @@ Discourse.Topic = Discourse.Model.extend({ }.property('created_at'), postStream: function() { - return Discourse.PostStream.create({topic: this}); + return PostStream.create({topic: this}); }.property(), details: function() { - return Discourse.TopicDetails.create({topic: this}); + return TopicDetails.create({topic: this}); }.property(), invisible: Em.computed.not('visible'), @@ -35,12 +38,12 @@ Discourse.Topic = Discourse.Model.extend({ }.property('id'), category: function() { - var categoryId = this.get('category_id'); + const categoryId = this.get('category_id'); if (categoryId) { return Discourse.Category.list().findProperty('id', categoryId); } - var categoryName = this.get('categoryName'); + const categoryName = this.get('categoryName'); if (categoryName) { return Discourse.Category.list().findProperty('name', categoryName); } @@ -52,12 +55,12 @@ Discourse.Topic = Discourse.Model.extend({ }.property('category.fullSlug'), shareUrl: function(){ - var user = Discourse.User.current(); + const user = Discourse.User.current(); return this.get('url') + (user ? '?u=' + user.get('username_lower') : ''); }.property('url'), url: function() { - var slug = this.get('slug'); + let slug = this.get('slug'); if (slug.trim().length === 0) { slug = "topic"; } @@ -65,8 +68,8 @@ Discourse.Topic = Discourse.Model.extend({ }.property('id', 'slug'), // Helper to build a Url with a post number - urlForPostNumber: function(postNumber) { - var url = this.get('url'); + urlForPostNumber(postNumber) { + let url = this.get('url'); if (postNumber && (postNumber > 0)) { url += "/" + postNumber; } @@ -74,7 +77,7 @@ Discourse.Topic = Discourse.Model.extend({ }, totalUnread: function() { - var count = (this.get('unread') || 0) + (this.get('new_posts') || 0); + const count = (this.get('unread') || 0) + (this.get('new_posts') || 0); return count > 0 ? count : null; }.property('new_posts', 'unread'), @@ -83,7 +86,7 @@ Discourse.Topic = Discourse.Model.extend({ }.property('url', 'last_read_post_number'), lastUnreadUrl: function() { - var postNumber = Math.min(this.get('last_read_post_number') + 1, this.get('highest_post_number')); + const postNumber = Math.min(this.get('last_read_post_number') + 1, this.get('highest_post_number')); return this.urlForPostNumber(postNumber); }.property('url', 'last_read_post_number', 'highest_post_number'), @@ -107,12 +110,11 @@ Discourse.Topic = Discourse.Model.extend({ // tells us if we are still asynchronously flushing our "recently read" data. // So take what the browser has seen into consideration. displayNewPosts: function() { - var delta, result; - var highestSeen = Discourse.Session.currentProp('highestSeenByTopic')[this.get('id')]; + const highestSeen = Discourse.Session.currentProp('highestSeenByTopic')[this.get('id')]; if (highestSeen) { - delta = highestSeen - this.get('last_read_post_number'); + let delta = highestSeen - this.get('last_read_post_number'); if (delta > 0) { - result = this.get('new_posts') - delta; + let result = this.get('new_posts') - delta; if (result < 0) { result = 0; } @@ -123,7 +125,7 @@ Discourse.Topic = Discourse.Model.extend({ }.property('new_posts', 'id'), viewsHeat: function() { - var v = this.get('views'); + const v = this.get('views'); if( v >= Discourse.SiteSettings.topic_views_heat_high ) return 'heatmap-high'; if( v >= Discourse.SiteSettings.topic_views_heat_medium ) return 'heatmap-med'; if( v >= Discourse.SiteSettings.topic_views_heat_low ) return 'heatmap-low'; @@ -137,17 +139,17 @@ Discourse.Topic = Discourse.Model.extend({ isPrivateMessage: Em.computed.equal('archetype', 'private_message'), isBanner: Em.computed.equal('archetype', 'banner'), - toggleStatus: function(property) { + toggleStatus(property) { this.toggleProperty(property); this.saveStatus(property, this.get(property) ? true : false); }, - setStatus: function(property, value) { + setStatus(property, value) { this.set(property, value); this.saveStatus(property, value); }, - saveStatus: function(property, value) { + saveStatus(property, value) { if (property === 'closed' && value === true) { this.set('details.auto_close_at', null); } @@ -160,28 +162,28 @@ Discourse.Topic = Discourse.Model.extend({ }); }, - makeBanner: function() { - var self = this; + makeBanner() { + const self = this; return Discourse.ajax('/t/' + this.get('id') + '/make-banner', { type: 'PUT' }) .then(function () { self.set('archetype', 'banner'); }); }, - removeBanner: function() { - var self = this; + removeBanner() { + const self = this; return Discourse.ajax('/t/' + this.get('id') + '/remove-banner', { type: 'PUT' }) .then(function () { self.set('archetype', 'regular'); }); }, estimatedReadingTime: function() { - var wordCount = this.get('word_count'); + const wordCount = this.get('word_count'); if (!wordCount) return; // Avg for 500 words per minute when you account for skimming return Math.floor(wordCount / 500.0); }.property('word_count'), - toggleBookmark: function() { - var self = this, firstPost = this.get("postStream.posts")[0]; + toggleBookmark() { + const self = this, firstPost = this.get("postStream.posts")[0]; this.toggleProperty('bookmarked'); if (this.get("postStream.firstPostPresent")) { firstPost.toggleProperty("bookmarked"); } @@ -194,8 +196,7 @@ Discourse.Topic = Discourse.Model.extend({ self.toggleProperty('bookmarked'); if (self.get("postStream.firstPostPresent")) { firstPost.toggleProperty('bookmarked'); } - var showGenericError = true; - + let showGenericError = true; if (error && error.responseText) { try { bootbox.alert($.parseJSON(error.responseText).errors); @@ -209,13 +210,7 @@ Discourse.Topic = Discourse.Model.extend({ }); }, - /** - Invite a user to this topic - - @method createInvite - @param {String} emailOrUsername The email or username of the user to be invited - **/ - createInvite: function(emailOrUsername, groupNames) { + createInvite(emailOrUsername, groupNames) { return Discourse.ajax("/t/" + this.get('id') + "/invite", { type: 'POST', data: { user: emailOrUsername, group_names: groupNames } @@ -223,7 +218,7 @@ Discourse.Topic = Discourse.Model.extend({ }, // Delete this topic - destroy: function(deleted_by) { + destroy(deleted_by) { this.setProperties({ deleted_at: new Date(), deleted_by: deleted_by, @@ -237,7 +232,7 @@ Discourse.Topic = Discourse.Model.extend({ }, // Recover this topic if deleted - recover: function() { + recover() { this.setProperties({ deleted_at: null, deleted_by: null, @@ -248,14 +243,14 @@ Discourse.Topic = Discourse.Model.extend({ }, // Update our attributes from a JSON result - updateFromJson: function(json) { + updateFromJson(json) { this.get('details').updateFromJson(json.details); - var keys = Object.keys(json); + const keys = Object.keys(json); keys.removeObject('details'); keys.removeObject('post_stream'); - var topic = this; + const topic = this; keys.forEach(function (key) { topic.set(key, json[key]); }); @@ -266,13 +261,8 @@ Discourse.Topic = Discourse.Model.extend({ return this.get('pinned') && this.get('category.isUncategorizedCategory'); }.property('pinned', 'category.isUncategorizedCategory'), - /** - Clears the pin from a topic for the currently logged in user - - @method clearPin - **/ - clearPin: function() { - var topic = this; + clearPin() { + const topic = this; // Clear the pin optimistically from the object topic.set('pinned', false); @@ -287,7 +277,7 @@ Discourse.Topic = Discourse.Model.extend({ }); }, - togglePinnedForUser: function() { + togglePinnedForUser() { if (this.get('pinned')) { this.clearPin(); } else { @@ -295,13 +285,8 @@ Discourse.Topic = Discourse.Model.extend({ } }, - /** - Re-pins a topic with a cleared pin - - @method rePin - **/ - rePin: function() { - var topic = this; + rePin() { + const topic = this; // Clear the pin optimistically from the object topic.set('pinned', true); @@ -317,12 +302,12 @@ Discourse.Topic = Discourse.Model.extend({ }, // Is the reply to a post directly below it? - isReplyDirectlyBelow: function(post) { - var posts = this.get('postStream.posts'); - var postNumber = post.get('post_number'); + isReplyDirectlyBelow(post) { + const posts = this.get('postStream.posts'); + const postNumber = post.get('post_number'); if (!posts) return; - var postBelow = posts[posts.indexOf(post) + 1]; + const postBelow = posts[posts.indexOf(post) + 1]; // If the post directly below's reply_to_post_number is our post number or we are quoted, // it's considered directly below. @@ -340,7 +325,7 @@ Discourse.Topic = Discourse.Model.extend({ hasExcerpt: Em.computed.and('pinned', 'excerptNotEmpty'), excerptTruncated: function() { - var e = this.get('excerpt'); + const e = this.get('excerpt'); return( e && e.substr(e.length - 8,8) === '…' ); }.property('excerpt'), @@ -349,7 +334,7 @@ Discourse.Topic = Discourse.Model.extend({ }); -Discourse.Topic.reopenClass({ +Topic.reopenClass({ NotificationLevel: { WATCHING: 3, TRACKING: 2, @@ -357,13 +342,13 @@ Discourse.Topic.reopenClass({ MUTED: 0 }, - createActionSummary: function(result) { + createActionSummary(result) { if (result.actions_summary) { - var lookup = Em.Object.create(); + const lookup = Em.Object.create(); result.actions_summary = result.actions_summary.map(function(a) { a.post = result; a.actionType = Discourse.Site.current().postActionTypeById(a.id); - var actionSummary = Discourse.ActionSummary.create(a); + const actionSummary = Discourse.ActionSummary.create(a); lookup.set(a.actionType.get('name_key'), actionSummary); return actionSummary; }); @@ -371,7 +356,7 @@ Discourse.Topic.reopenClass({ } }, - update: function(topic, props) { + update(topic, props) { props = JSON.parse(JSON.stringify(props)) || {}; // We support `category_id` and `categoryId` for compatibility @@ -384,7 +369,7 @@ Discourse.Topic.reopenClass({ // allows us to make a distinction between arrays that were not // sent and arrays that we specifically want to be empty. Object.keys(props).forEach(function(k) { - var v = props[k]; + const v = props[k]; if (v instanceof Array && v.length === 0) { props[k + '_empty_array'] = true; } @@ -400,24 +385,16 @@ Discourse.Topic.reopenClass({ }); }, - create: function() { - var result = this._super.apply(this, arguments); + create() { + const result = this._super.apply(this, arguments); this.createActionSummary(result); return result; }, - /** - Find similar topics to a given title and body - - @method findSimilar - @param {String} title The current title - @param {String} body The current body - @returns A promise that will resolve to the topics - **/ - findSimilarTo: function(title, body) { + findSimilarTo(title, body) { return Discourse.ajax("/topics/similar_to", { data: {title: title, raw: body} }).then(function (results) { if (Array.isArray(results)) { - return results.map(function(topic) { return Discourse.Topic.create(topic); }); + return results.map(function(topic) { return Topic.create(topic); }); } else { return Ember.A(); } @@ -425,14 +402,13 @@ Discourse.Topic.reopenClass({ }, // Load a topic, but accepts a set of filters - find: function(topicId, opts) { - var url = Discourse.getURL("/t/") + topicId; - + find(topicId, opts) { + let url = Discourse.getURL("/t/") + topicId; if (opts.nearPost) { url += "/" + opts.nearPost; } - var data = {}; + const data = {}; if (opts.postsAfter) { data.posts_after = opts.postsAfter; } @@ -461,8 +437,8 @@ Discourse.Topic.reopenClass({ return Discourse.ajax(url + ".json", {data: data}); }, - mergeTopic: function(topicId, destinationTopicId) { - var promise = Discourse.ajax("/t/" + topicId + "/merge-topic", { + mergeTopic(topicId, destinationTopicId) { + const promise = Discourse.ajax("/t/" + topicId + "/merge-topic", { type: 'POST', data: {destination_topic_id: destinationTopicId} }).then(function (result) { @@ -472,8 +448,8 @@ Discourse.Topic.reopenClass({ return promise; }, - movePosts: function(topicId, opts) { - var promise = Discourse.ajax("/t/" + topicId + "/move-posts", { + movePosts(topicId, opts) { + const promise = Discourse.ajax("/t/" + topicId + "/move-posts", { type: 'POST', data: opts }).then(function (result) { @@ -483,8 +459,8 @@ Discourse.Topic.reopenClass({ return promise; }, - changeOwners: function(topicId, opts) { - var promise = Discourse.ajax("/t/" + topicId + "/change-owner", { + changeOwners(topicId, opts) { + const promise = Discourse.ajax("/t/" + topicId + "/change-owner", { type: 'POST', data: opts }).then(function (result) { @@ -494,7 +470,7 @@ Discourse.Topic.reopenClass({ return promise; }, - bulkOperation: function(topics, operation) { + bulkOperation(topics, operation) { return Discourse.ajax("/topics/bulk", { type: 'PUT', data: { @@ -504,8 +480,8 @@ Discourse.Topic.reopenClass({ }); }, - bulkOperationByFilter: function(filter, operation, categoryId) { - var data = { filter: filter, operation: operation }; + bulkOperationByFilter(filter, operation, categoryId) { + const data = { filter: filter, operation: operation }; if (categoryId) data['category_id'] = categoryId; return Discourse.ajax("/topics/bulk", { type: 'PUT', @@ -513,12 +489,13 @@ Discourse.Topic.reopenClass({ }); }, - resetNew: function() { + resetNew() { return Discourse.ajax("/topics/reset-new", {type: 'PUT'}); }, - idForSlug: function(slug) { + idForSlug(slug) { return Discourse.ajax("/t/id_for/" + slug); } - }); + +export default Topic; diff --git a/app/assets/javascripts/discourse/routes/topic-by-slug.js.es6 b/app/assets/javascripts/discourse/routes/topic-by-slug.js.es6 index e9482adb5bd..898fbfe65e5 100644 --- a/app/assets/javascripts/discourse/routes/topic-by-slug.js.es6 +++ b/app/assets/javascripts/discourse/routes/topic-by-slug.js.es6 @@ -1,6 +1,8 @@ +import Topic from 'discourse/models/topic'; + export default Discourse.Route.extend({ model: function(params) { - return Discourse.Topic.idForSlug(params.slug); + return Topic.idForSlug(params.slug); }, afterModel: function(result) { diff --git a/app/assets/javascripts/discourse/routes/topic.js.es6 b/app/assets/javascripts/discourse/routes/topic.js.es6 index 993aeab1623..a384f362c10 100644 --- a/app/assets/javascripts/discourse/routes/topic.js.es6 +++ b/app/assets/javascripts/discourse/routes/topic.js.es6 @@ -4,6 +4,7 @@ var isTransitioning = false, SCROLL_DELAY = 500; import ShowFooter from "discourse/mixins/show-footer"; +import Topic from 'discourse/models/topic'; var TopicRoute = Discourse.Route.extend(ShowFooter, { redirect: function() { return this.redirectIfLoginRequired(); }, @@ -163,7 +164,7 @@ var TopicRoute = Discourse.Route.extend(ShowFooter, { return topic; }); } else { - return this.setupParams(Discourse.Topic.create(_.omit(params, 'username_filters', 'filter')), queryParams); + return this.setupParams(Topic.create(_.omit(params, 'username_filters', 'filter')), queryParams); } }, diff --git a/app/assets/javascripts/discourse/views/composer.js.es6 b/app/assets/javascripts/discourse/views/composer.js.es6 index f060f28ae75..42b620b185e 100644 --- a/app/assets/javascripts/discourse/views/composer.js.es6 +++ b/app/assets/javascripts/discourse/views/composer.js.es6 @@ -154,8 +154,6 @@ var ComposerView = Discourse.View.extend(Ember.Evented, { var $wmdPreview = $('#wmd-preview'); if ($wmdPreview.length === 0) return; - Discourse.SyntaxHighlighting.apply($wmdPreview); - var post = this.get('model.post'), refresh = false; diff --git a/app/assets/javascripts/discourse/views/post.js.es6 b/app/assets/javascripts/discourse/views/post.js.es6 index 879f51b6760..422771c061c 100644 --- a/app/assets/javascripts/discourse/views/post.js.es6 +++ b/app/assets/javascripts/discourse/views/post.js.es6 @@ -264,8 +264,6 @@ var PostView = Discourse.GroupedView.extend(Ember.Evented, { this._showLinkCounts(); Discourse.ScreenTrack.current().track(this.$().prop('id'), postNumber); - Discourse.SyntaxHighlighting.apply($post); - Discourse.Lightbox.apply($post); this.trigger('postViewInserted', $post); diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js index 3e6caae8533..15f6bd8f454 100644 --- a/app/assets/javascripts/main_include.js +++ b/app/assets/javascripts/main_include.js @@ -28,6 +28,8 @@ //= require ./discourse/models/model //= require ./discourse/models/user_action //= require ./discourse/models/composer +//= require ./discourse/models/post-stream +//= require ./discourse/models/topic-details //= require ./discourse/models/topic //= require ./discourse/models/top-period //= require ./discourse/controllers/controller diff --git a/test/javascripts/controllers/topic-test.js.es6 b/test/javascripts/controllers/topic-test.js.es6 index 5b9bb5135aa..295583db629 100644 --- a/test/javascripts/controllers/topic-test.js.es6 +++ b/test/javascripts/controllers/topic-test.js.es6 @@ -3,8 +3,10 @@ moduleFor('controller:topic', 'controller:topic', { 'controller:search', 'controller:topic-progress', 'controller:application'] }); +import Topic from 'discourse/models/topic'; + var buildTopic = function() { - return Discourse.Topic.create({ + return Topic.create({ title: "Qunit Test Topic", participants: [ {id: 1234, diff --git a/test/javascripts/mixins/selected-posts-count-test.js.es6 b/test/javascripts/mixins/selected-posts-count-test.js.es6 index d8ecc084e4a..830d9033ee4 100644 --- a/test/javascripts/mixins/selected-posts-count-test.js.es6 +++ b/test/javascripts/mixins/selected-posts-count-test.js.es6 @@ -1,5 +1,7 @@ module("Discourse.SelectedPostsCount"); +import Topic from 'discourse/models/topic'; + var buildTestObj = function(params) { return Ember.Object.createWithMixins(Discourse.SelectedPostsCount, params || {}); }; @@ -26,7 +28,7 @@ test("when all posts are selected and there is a posts_count", function() { test("when all posts are selected and there is topic with a posts_count", function() { var testObj = buildTestObj({ allPostsSelected: true, - topic: Discourse.Topic.create({ posts_count: 3456 }) + topic: Topic.create({ posts_count: 3456 }) }); equal(testObj.get('selectedPostsCount'), 3456, "It returns the topic's posts_count"); diff --git a/test/javascripts/models/post-stream-test.js.es6 b/test/javascripts/models/post-stream-test.js.es6 index b4c68cb7016..7162b49c969 100644 --- a/test/javascripts/models/post-stream-test.js.es6 +++ b/test/javascripts/models/post-stream-test.js.es6 @@ -1,7 +1,10 @@ -module("Discourse.PostStream"); +module("model:post-stream"); + +import PostStream from 'discourse/models/post-stream'; +import Topic from 'discourse/models/topic'; var buildStream = function(id, stream) { - var topic = Discourse.Topic.create({id: id, chunk_size: 5}); + var topic = Topic.create({id: id, chunk_size: 5}); var ps = topic.get('postStream'); if (stream) { ps.set('stream', stream); @@ -12,7 +15,7 @@ var buildStream = function(id, stream) { var participant = {username: 'eviltrout'}; test('create', function() { - ok(Discourse.PostStream.create(), 'it can be created with no parameters'); + ok(PostStream.create(), 'it can be created with no parameters'); }); test('defaults', function() { diff --git a/test/javascripts/models/topic-details-test.js.es6 b/test/javascripts/models/topic-details-test.js.es6 index 7ca709f4004..7fb7fc2f25a 100644 --- a/test/javascripts/models/topic-details-test.js.es6 +++ b/test/javascripts/models/topic-details-test.js.es6 @@ -1,7 +1,9 @@ -module("Discourse.TopicDetails"); +module("model:topic-details"); + +import Topic from 'discourse/models/topic'; var buildDetails = function(id) { - var topic = Discourse.Topic.create({id: id}); + var topic = Topic.create({id: id}); return topic.get('details'); }; @@ -20,13 +22,9 @@ test('updateFromJson', function() { }); equal(details.get('suggested_topics.length'), 2, 'it loaded the suggested_topics'); - containsInstance(details.get('suggested_topics'), Discourse.Topic); + containsInstance(details.get('suggested_topics'), Topic); equal(details.get('allowed_users.length'), 1, 'it loaded the allowed users'); containsInstance(details.get('allowed_users'), Discourse.User); }); - - - - diff --git a/test/javascripts/models/topic-test.js.es6 b/test/javascripts/models/topic-test.js.es6 index e557cf7c1b7..3bd2230171e 100644 --- a/test/javascripts/models/topic-test.js.es6 +++ b/test/javascripts/models/topic-test.js.es6 @@ -1,20 +1,22 @@ -module("Discourse.Topic"); +module("model:topic"); + +import Topic from 'discourse/models/topic'; test("defaults", function() { - var topic = Discourse.Topic.create({id: 1234}); + var topic = Topic.create({id: 1234}); blank(topic.get('deleted_at'), 'deleted_at defaults to blank'); blank(topic.get('deleted_by'), 'deleted_by defaults to blank'); }); test('has details', function() { - var topic = Discourse.Topic.create({id: 1234}); + var topic = Topic.create({id: 1234}); var topicDetails = topic.get('details'); present(topicDetails, "a topic has topicDetails after we create it"); equal(topicDetails.get('topic'), topic, "the topicDetails has a reference back to the topic"); }); test('has a postStream', function() { - var topic = Discourse.Topic.create({id: 1234}); + var topic = Topic.create({id: 1234}); var postStream = topic.get('postStream'); present(postStream, "a topic has a postStream after we create it"); equal(postStream.get('topic'), topic, "the postStream has a reference back to the topic"); @@ -24,13 +26,13 @@ test('has a postStream', function() { test('category relationship', function() { // It finds the category by id var category = Discourse.Category.list()[0], - topic = Discourse.Topic.create({id: 1111, category_id: category.get('id') }); + topic = Topic.create({id: 1111, category_id: category.get('id') }); equal(topic.get('category'), category); }); test("updateFromJson", function() { - var topic = Discourse.Topic.create({id: 1234}), + var topic = Topic.create({id: 1234}), category = Discourse.Category.list()[0]; topic.updateFromJson({ @@ -48,7 +50,7 @@ test("updateFromJson", function() { test("destroy", function() { var user = Discourse.User.create({username: 'eviltrout'}); - var topic = Discourse.Topic.create({id: 1234}); + var topic = Topic.create({id: 1234}); sandbox.stub(Discourse, 'ajax'); @@ -60,7 +62,7 @@ test("destroy", function() { test("recover", function() { var user = Discourse.User.create({username: 'eviltrout'}); - var topic = Discourse.Topic.create({id: 1234, deleted_at: new Date(), deleted_by: user}); + var topic = Topic.create({id: 1234, deleted_at: new Date(), deleted_by: user}); sandbox.stub(Discourse, 'ajax');