mirror of
https://github.com/discourse/discourse.git
synced 2024-11-27 06:13:43 +08:00
FIX: Highlighting was not being applied after some rendering.
Also includes a bunch of ES6 stuff.
This commit is contained in:
parent
96697c7957
commit
a519fd5bcf
|
@ -1,6 +1,7 @@
|
||||||
import ObjectController from 'discourse/controllers/object';
|
import ObjectController from 'discourse/controllers/object';
|
||||||
import BufferedContent from 'discourse/mixins/buffered-content';
|
import BufferedContent from 'discourse/mixins/buffered-content';
|
||||||
import { spinnerHTML } from 'discourse/helpers/loading-spinner';
|
import { spinnerHTML } from 'discourse/helpers/loading-spinner';
|
||||||
|
import Topic from 'discourse/models/topic';
|
||||||
|
|
||||||
export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedContent, {
|
export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedContent, {
|
||||||
multiSelect: false,
|
multiSelect: false,
|
||||||
|
@ -272,7 +273,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||||
var self = this,
|
var self = this,
|
||||||
props = this.get('buffered.buffer');
|
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
|
// Note we roll back on success here because `update` saves
|
||||||
// the properties to the topic.
|
// the properties to the topic.
|
||||||
self.rollbackBuffer();
|
self.rollbackBuffer();
|
||||||
|
@ -555,13 +556,13 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
|
||||||
},
|
},
|
||||||
|
|
||||||
// Receive notifications for this topic
|
// Receive notifications for this topic
|
||||||
subscribe: function() {
|
subscribe() {
|
||||||
// Unsubscribe before subscribing again
|
// Unsubscribe before subscribing again
|
||||||
this.unsubscribe();
|
this.unsubscribe();
|
||||||
|
|
||||||
var topicController = this;
|
const self = this;
|
||||||
Discourse.MessageBus.subscribe("/topic/" + this.get('id'), function(data) {
|
Discourse.MessageBus.subscribe("/topic/" + this.get('id'), function(data) {
|
||||||
var topic = topicController.get('model');
|
const topic = self.get('model');
|
||||||
|
|
||||||
if (data.notification_level_change) {
|
if (data.notification_level_change) {
|
||||||
topic.set('details.notification_level', 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var postStream = topicController.get('postStream');
|
const postStream = self.get('postStream');
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case "revised":
|
case "revised":
|
||||||
case "acted":
|
case "acted":
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
};
|
10
app/assets/javascripts/discourse/lib/highlight-syntax.js.es6
Normal file
10
app/assets/javascripts/discourse/lib/highlight-syntax.js.es6
Normal file
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -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', '×'),
|
|
||||||
'<a class="image-source-link" href="' + href + '">' + I18n.t("lightbox.download") + '</a>'
|
|
||||||
].join(' · ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
45
app/assets/javascripts/discourse/lib/lightbox.js.es6
Normal file
45
app/assets/javascripts/discourse/lib/lightbox.js.es6
Normal file
|
@ -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', '×'),
|
||||||
|
'<a class="image-source-link" href="' + href + '">' + I18n.t("lightbox.download") + '</a>'
|
||||||
|
].join(' · ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
export default function searchForTerm(term, opts) {
|
import Topic from 'discourse/models/topic';
|
||||||
|
|
||||||
|
function searchForTerm(term, opts) {
|
||||||
if (!opts) opts = {};
|
if (!opts) opts = {};
|
||||||
|
|
||||||
// Only include the data we have
|
// Only include the data we have
|
||||||
|
@ -22,7 +24,7 @@ export default function searchForTerm(term, opts) {
|
||||||
|
|
||||||
var topicMap = {};
|
var topicMap = {};
|
||||||
results.topics = results.topics.map(function(topic){
|
results.topics = results.topics.map(function(topic){
|
||||||
topic = Discourse.Topic.create(topic);
|
topic = Topic.create(topic);
|
||||||
topicMap[topic.id] = topic;
|
topicMap[topic.id] = topic;
|
||||||
return topic;
|
return topic;
|
||||||
});
|
});
|
||||||
|
@ -66,3 +68,5 @@ export default function searchForTerm(term, opts) {
|
||||||
return noResults ? null : Em.Object.create(results);
|
return noResults ? null : Em.Object.create(results);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default searchForTerm;
|
||||||
|
|
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -532,6 +532,7 @@ Discourse.Composer = Discourse.Model.extend({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If we're in a topic, we can append the post instantly.
|
// If we're in a topic, we can append the post instantly.
|
||||||
if (postStream) {
|
if (postStream) {
|
||||||
// If it's in reply to another post, increase the reply count
|
// If it's in reply to another post, increase the reply count
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
Discourse.PostStream = Em.Object.extend({
|
const PostStream = Ember.Object.extend({
|
||||||
|
|
||||||
loading: Em.computed.or('loadingAbove', 'loadingBelow', 'loadingFilter', 'stagingPost'),
|
loading: Em.computed.or('loadingAbove', 'loadingBelow', 'loadingFilter', 'stagingPost'),
|
||||||
notLoading: Em.computed.not('loading'),
|
notLoading: Em.computed.not('loading'),
|
||||||
filteredPostsCount: Em.computed.alias("stream.length"),
|
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
|
Returns a JS Object of current stream filter options. It should match the query
|
||||||
params for the stream.
|
params for the stream.
|
||||||
|
|
||||||
@property streamFilters
|
|
||||||
**/
|
**/
|
||||||
streamFilters: function() {
|
streamFilters: function() {
|
||||||
var result = {};
|
const result = {};
|
||||||
if (this.get('summary')) { result.filter = "summary"; }
|
if (this.get('summary')) { result.filter = "summary"; }
|
||||||
if (this.get('show_deleted')) { result.show_deleted = true; }
|
if (this.get('show_deleted')) { result.show_deleted = true; }
|
||||||
|
|
||||||
var userFilters = this.get('userFilters');
|
const userFilters = this.get('userFilters');
|
||||||
if (!Em.isEmpty(userFilters)) {
|
if (!Em.isEmpty(userFilters)) {
|
||||||
result.username_filters = userFilters.join(",");
|
result.username_filters = userFilters.join(",");
|
||||||
}
|
}
|
||||||
|
@ -62,27 +59,25 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
}.property('userFilters.[]', 'summary', 'show_deleted'),
|
}.property('userFilters.[]', 'summary', 'show_deleted'),
|
||||||
|
|
||||||
hasNoFilters: function() {
|
hasNoFilters: function() {
|
||||||
var streamFilters = this.get('streamFilters');
|
const streamFilters = this.get('streamFilters');
|
||||||
return !(streamFilters && ((streamFilters.filter === 'summary') || streamFilters.username_filters));
|
return !(streamFilters && ((streamFilters.filter === 'summary') || streamFilters.username_filters));
|
||||||
}.property('streamFilters.[]', 'topic.posts_count', 'posts.length'),
|
}.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.
|
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.
|
This is the collection we'll ask for when scrolling upwards.
|
||||||
|
|
||||||
@property previousWindow
|
|
||||||
**/
|
**/
|
||||||
previousWindow: function() {
|
previousWindow: function() {
|
||||||
// If we can't find the last post loaded, bail
|
// 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 []; }
|
if (!firstPost) { return []; }
|
||||||
|
|
||||||
// Find the index of the last post loaded, if not found, bail
|
// Find the index of the last post loaded, if not found, bail
|
||||||
var stream = this.get('stream');
|
const stream = this.get('stream');
|
||||||
var firstIndex = this.indexOf(firstPost);
|
const firstIndex = this.indexOf(firstPost);
|
||||||
if (firstIndex === -1) { return []; }
|
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; }
|
if (startIndex < 0) { startIndex = 0; }
|
||||||
return stream.slice(startIndex, firstIndex);
|
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
|
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.
|
stream. This is the collection we use when scrolling downwards.
|
||||||
|
|
||||||
@property nextWindow
|
|
||||||
**/
|
**/
|
||||||
nextWindow: function() {
|
nextWindow: function() {
|
||||||
// If we can't find the last post loaded, bail
|
// If we can't find the last post loaded, bail
|
||||||
var lastLoadedPost = this.get('lastLoadedPost');
|
const lastLoadedPost = this.get('lastLoadedPost');
|
||||||
if (!lastLoadedPost) { return []; }
|
if (!lastLoadedPost) { return []; }
|
||||||
|
|
||||||
// Find the index of the last post loaded, if not found, bail
|
// Find the index of the last post loaded, if not found, bail
|
||||||
var stream = this.get('stream');
|
const stream = this.get('stream');
|
||||||
var lastIndex = this.indexOf(lastLoadedPost);
|
const lastIndex = this.indexOf(lastLoadedPost);
|
||||||
if (lastIndex === -1) { return []; }
|
if (lastIndex === -1) { return []; }
|
||||||
if ((lastIndex + 1) >= this.get('highest_post_number')) { 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);
|
return stream.slice(lastIndex+1, lastIndex + this.get('topic.chunk_size') + 1);
|
||||||
}.property('lastLoadedPost', 'stream.@each'),
|
}.property('lastLoadedPost', 'stream.@each'),
|
||||||
|
|
||||||
|
cancelFilter() {
|
||||||
/**
|
|
||||||
Cancel any active filters on the stream.
|
|
||||||
|
|
||||||
@method cancelFilter
|
|
||||||
**/
|
|
||||||
cancelFilter: function() {
|
|
||||||
this.set('summary', false);
|
this.set('summary', false);
|
||||||
this.set('show_deleted', false);
|
this.set('show_deleted', false);
|
||||||
this.get('userFilters').clear();
|
this.get('userFilters').clear();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
toggleSummary() {
|
||||||
Toggle summary mode for the stream.
|
|
||||||
|
|
||||||
@method toggleSummary
|
|
||||||
**/
|
|
||||||
toggleSummary: function() {
|
|
||||||
this.get('userFilters').clear();
|
this.get('userFilters').clear();
|
||||||
this.toggleProperty('summary');
|
this.toggleProperty('summary');
|
||||||
return this.refresh();
|
return this.refresh();
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleDeleted: function() {
|
toggleDeleted() {
|
||||||
this.toggleProperty('show_deleted');
|
this.toggleProperty('show_deleted');
|
||||||
return this.refresh();
|
return this.refresh();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
// Filter the stream to a particular user.
|
||||||
Filter the stream to a particular user.
|
toggleParticipant(username) {
|
||||||
|
const userFilters = this.get('userFilters');
|
||||||
@method toggleParticipant
|
|
||||||
**/
|
|
||||||
toggleParticipant: function(username) {
|
|
||||||
var userFilters = this.get('userFilters');
|
|
||||||
this.set('summary', false);
|
this.set('summary', false);
|
||||||
this.set('show_deleted', true);
|
this.set('show_deleted', true);
|
||||||
if (userFilters.contains(username)) {
|
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
|
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.
|
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 = opts || {};
|
||||||
opts.nearPost = parseInt(opts.nearPost, 10);
|
opts.nearPost = parseInt(opts.nearPost, 10);
|
||||||
|
|
||||||
var topic = this.get('topic'),
|
const topic = this.get('topic'),
|
||||||
self = this;
|
self = this;
|
||||||
|
|
||||||
// Do we already have the post in our list of posts? Jump there.
|
// 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(); }
|
if (postWeWant) { return Ember.RSVP.resolve(); }
|
||||||
|
|
||||||
// TODO: if we have all the posts in the filter, don't go to the server for them.
|
// 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'),
|
hasLoadedData: Em.computed.and('hasPosts', 'hasStream'),
|
||||||
|
|
||||||
collapsePosts: function(from, to){
|
collapsePosts(from, to){
|
||||||
var posts = this.get('posts');
|
const posts = this.get('posts');
|
||||||
var remove = posts.filter(function(post){
|
const remove = posts.filter(function(post){
|
||||||
var postNumber = post.get('post_number');
|
const postNumber = post.get('post_number');
|
||||||
return postNumber >= from && postNumber <= to;
|
return postNumber >= from && postNumber <= to;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -203,9 +175,9 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
|
|
||||||
// make gap
|
// make gap
|
||||||
this.set('gaps', this.get('gaps') || {before: {}, after: {}});
|
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;
|
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
|
||||||
Fill in a gap of posts before a particular post
|
fillGapBefore(post, gap) {
|
||||||
|
const postId = post.get('id'),
|
||||||
@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'),
|
|
||||||
stream = this.get('stream'),
|
stream = this.get('stream'),
|
||||||
idx = stream.indexOf(postId),
|
idx = stream.indexOf(postId),
|
||||||
currentPosts = this.get('posts'),
|
currentPosts = this.get('posts'),
|
||||||
|
@ -237,11 +202,11 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
// Insert the gap at the appropriate place
|
// Insert the gap at the appropriate place
|
||||||
stream.splice.apply(stream, [idx, 0].concat(gap));
|
stream.splice.apply(stream, [idx, 0].concat(gap));
|
||||||
|
|
||||||
var postIdx = currentPosts.indexOf(post);
|
let postIdx = currentPosts.indexOf(post);
|
||||||
if (postIdx !== -1) {
|
if (postIdx !== -1) {
|
||||||
return this.findPostsByIds(gap).then(function(posts) {
|
return this.findPostsByIds(gap).then(function(posts) {
|
||||||
posts.forEach(function(p) {
|
posts.forEach(function(p) {
|
||||||
var stored = self.storePost(p);
|
const stored = self.storePost(p);
|
||||||
if (!currentPosts.contains(stored)) {
|
if (!currentPosts.contains(stored)) {
|
||||||
currentPosts.insertAt(postIdx++, stored);
|
currentPosts.insertAt(postIdx++, stored);
|
||||||
}
|
}
|
||||||
|
@ -256,16 +221,9 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
return Ember.RSVP.resolve();
|
return Ember.RSVP.resolve();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
// Fill in a gap of posts after a particular post
|
||||||
Fill in a gap of posts after a particular post
|
fillGapAfter(post, gap) {
|
||||||
|
const postId = post.get('id'),
|
||||||
@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'),
|
|
||||||
stream = this.get('stream'),
|
stream = this.get('stream'),
|
||||||
idx = stream.indexOf(postId),
|
idx = stream.indexOf(postId),
|
||||||
self = this;
|
self = this;
|
||||||
|
@ -279,24 +237,19 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
return Ember.RSVP.resolve();
|
return Ember.RSVP.resolve();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
// Appends the next window of posts to the stream. Call it when scrolling downwards.
|
||||||
Appends the next window of posts to the stream. Call it when scrolling downwards.
|
appendMore() {
|
||||||
|
const self = this;
|
||||||
@method appendMore
|
|
||||||
@returns {Promise} a promise that's resolved when the posts have been added.
|
|
||||||
**/
|
|
||||||
appendMore: function() {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
// Make sure we can append more posts
|
// Make sure we can append more posts
|
||||||
if (!self.get('canAppendMore')) { return Ember.RSVP.resolve(); }
|
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(); }
|
if (Ember.isEmpty(postIds)) { return Ember.RSVP.resolve(); }
|
||||||
|
|
||||||
self.set('loadingBelow', true);
|
self.set('loadingBelow', true);
|
||||||
|
|
||||||
var stopLoading = function() {
|
const stopLoading = function() {
|
||||||
self.set('loadingBelow', false);
|
self.set('loadingBelow', false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -308,19 +261,14 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
}, stopLoading);
|
}, stopLoading);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
// Prepend the previous window of posts to the stream. Call it when scrolling upwards.
|
||||||
Prepend the previous window of posts to the stream. Call it when scrolling upwards.
|
prependMore() {
|
||||||
|
const postStream = this;
|
||||||
@method prependMore
|
|
||||||
@returns {Promise} a promise that's resolved when the posts have been added.
|
|
||||||
**/
|
|
||||||
prependMore: function() {
|
|
||||||
var postStream = this;
|
|
||||||
|
|
||||||
// Make sure we can append more posts
|
// Make sure we can append more posts
|
||||||
if (!postStream.get('canPrependMore')) { return Ember.RSVP.resolve(); }
|
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(); }
|
if (Ember.isEmpty(postIds)) { return Ember.RSVP.resolve(); }
|
||||||
|
|
||||||
postStream.set('loadingAbove', true);
|
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
|
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
|
assumption that the post will succeed. We can then `commitPost` when it succeeds or
|
||||||
`undoPost` when it fails.
|
`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
|
// We can't stage two posts simultaneously
|
||||||
if (this.get('stagingPost')) { return false; }
|
if (this.get('stagingPost')) { return false; }
|
||||||
this.set('stagingPost', true);
|
this.set('stagingPost', true);
|
||||||
|
|
||||||
var topic = this.get('topic');
|
const topic = this.get('topic');
|
||||||
topic.setProperties({
|
topic.setProperties({
|
||||||
posts_count: (topic.get('posts_count') || 0) + 1,
|
posts_count: (topic.get('posts_count') || 0) + 1,
|
||||||
last_posted_at: new Date(),
|
last_posted_at: new Date(),
|
||||||
|
@ -371,13 +314,8 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
// Commit the post we staged. Call this after a save succeeds.
|
||||||
Commit the post we staged. Call this after a save succeeds.
|
commitPost(post) {
|
||||||
|
|
||||||
@method commitPost
|
|
||||||
@param {Discourse.Post} the post we saved in the stream.
|
|
||||||
**/
|
|
||||||
commitPost: function(post) {
|
|
||||||
if (this.get('loadedAllPosts')) {
|
if (this.get('loadedAllPosts')) {
|
||||||
this.appendPost(post);
|
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
|
Undo a post we've staged in the stream. Remove it from being rendered and revert the
|
||||||
state we changed.
|
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.get('stream').removeObject(-1);
|
||||||
this.posts.removeObject(post);
|
this.posts.removeObject(post);
|
||||||
this.get('postIdentityMap').set(-1, null);
|
this.get('postIdentityMap').set(-1, null);
|
||||||
|
|
||||||
var topic = this.get('topic');
|
const topic = this.get('topic');
|
||||||
this.set('stagingPost', false);
|
this.set('stagingPost', false);
|
||||||
|
|
||||||
topic.setProperties({
|
topic.setProperties({
|
||||||
|
@ -418,44 +353,24 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
// TODO unfudge reply count on parent post
|
// TODO unfudge reply count on parent post
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
prependPost(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) {
|
|
||||||
this.get('posts').unshiftObject(this.storePost(post));
|
this.get('posts').unshiftObject(this.storePost(post));
|
||||||
return post;
|
return post;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
appendPost(post) {
|
||||||
Appends a single post into the stream.
|
const stored = this.storePost(post);
|
||||||
|
|
||||||
@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);
|
|
||||||
if (stored) {
|
if (stored) {
|
||||||
this.get('posts').addObject(stored);
|
this.get('posts').addObject(stored);
|
||||||
}
|
}
|
||||||
return post;
|
return post;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
removePosts(posts) {
|
||||||
Removes posts from the stream.
|
|
||||||
|
|
||||||
@method removePosts
|
|
||||||
@param {Array} posts the collection of posts to remove
|
|
||||||
**/
|
|
||||||
removePosts: function(posts) {
|
|
||||||
if (Em.isEmpty(posts)) { return; }
|
if (Em.isEmpty(posts)) { return; }
|
||||||
|
|
||||||
var postIds = posts.map(function (p) { return p.get('id'); });
|
const postIds = posts.map(function (p) { return p.get('id'); });
|
||||||
var identityMap = this.get('postIdentityMap');
|
const identityMap = this.get('postIdentityMap');
|
||||||
|
|
||||||
this.get('stream').removeObjects(postIds);
|
this.get('stream').removeObjects(postIds);
|
||||||
this.get('posts').removeObjects(posts);
|
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.
|
||||||
Returns a post from the identity map if it's been inserted.
|
findLoadedPost(id) {
|
||||||
|
|
||||||
@method findLoadedPost
|
|
||||||
@param {Integer} id The post we want from the identity map.
|
|
||||||
@returns {Discourse.Post} the post that was inserted.
|
|
||||||
**/
|
|
||||||
findLoadedPost: function(id) {
|
|
||||||
return this.get('postIdentityMap').get(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
|
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
|
from the message bus indicating there's a new post. We'll only insert it if we currently
|
||||||
have no filters.
|
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; }
|
if (!postId) { return; }
|
||||||
|
|
||||||
// We only trigger if there are no filters active
|
// We only trigger if there are no filters active
|
||||||
if (!this.get('hasNoFilters')) { return; }
|
if (!this.get('hasNoFilters')) { return; }
|
||||||
|
|
||||||
var loadedAllPosts = this.get('loadedAllPosts');
|
const loadedAllPosts = this.get('loadedAllPosts');
|
||||||
|
|
||||||
if (this.get('stream').indexOf(postId) === -1) {
|
if (this.get('stream').indexOf(postId) === -1) {
|
||||||
this.get('stream').addObject(postId);
|
this.get('stream').addObject(postId);
|
||||||
|
@ -497,8 +403,8 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
triggerRecoveredPost: function(postId){
|
triggerRecoveredPost(postId){
|
||||||
var self = this,
|
const self = this,
|
||||||
postIdentityMap = this.get('postIdentityMap'),
|
postIdentityMap = this.get('postIdentityMap'),
|
||||||
existing = postIdentityMap.get(postId);
|
existing = postIdentityMap.get(postId);
|
||||||
|
|
||||||
|
@ -506,15 +412,15 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
this.triggerChangedPost(postId, new Date());
|
this.triggerChangedPost(postId, new Date());
|
||||||
} else {
|
} else {
|
||||||
// need to insert into stream
|
// need to insert into stream
|
||||||
var url = "/posts/" + postId;
|
const url = "/posts/" + postId;
|
||||||
Discourse.ajax(url).then(function(p){
|
Discourse.ajax(url).then(function(p){
|
||||||
var post = Discourse.Post.create(p);
|
const post = Discourse.Post.create(p);
|
||||||
var stream = self.get("stream");
|
const stream = self.get("stream");
|
||||||
var posts = self.get("posts");
|
const posts = self.get("posts");
|
||||||
self.storePost(post);
|
self.storePost(post);
|
||||||
|
|
||||||
// we need to zip this into the stream
|
// we need to zip this into the stream
|
||||||
var index = 0;
|
let index = 0;
|
||||||
stream.forEach(function(postId){
|
stream.forEach(function(postId){
|
||||||
if(postId < p.id){
|
if(postId < p.id){
|
||||||
index+= 1;
|
index+= 1;
|
||||||
|
@ -541,13 +447,13 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
triggerDeletedPost: function(postId){
|
triggerDeletedPost(postId){
|
||||||
var self = this,
|
const self = this,
|
||||||
postIdentityMap = this.get('postIdentityMap'),
|
postIdentityMap = this.get('postIdentityMap'),
|
||||||
existing = postIdentityMap.get(postId);
|
existing = postIdentityMap.get(postId);
|
||||||
|
|
||||||
if(existing){
|
if(existing){
|
||||||
var url = "/posts/" + postId;
|
const url = "/posts/" + postId;
|
||||||
Discourse.ajax(url).then(
|
Discourse.ajax(url).then(
|
||||||
function(p){
|
function(p){
|
||||||
self.storePost(Discourse.Post.create(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; }
|
if (!postId) { return; }
|
||||||
|
|
||||||
var postIdentityMap = this.get('postIdentityMap'),
|
const postIdentityMap = this.get('postIdentityMap'),
|
||||||
existing = postIdentityMap.get(postId),
|
existing = postIdentityMap.get(postId),
|
||||||
self = this;
|
self = this;
|
||||||
|
|
||||||
if (existing && existing.updated_at !== updatedAt) {
|
if (existing && existing.updated_at !== updatedAt) {
|
||||||
var url = "/posts/" + postId;
|
const url = "/posts/" + postId;
|
||||||
Discourse.ajax(url).then(function(p){
|
Discourse.ajax(url).then(function(p){
|
||||||
self.storePost(Discourse.Post.create(p));
|
self.storePost(Discourse.Post.create(p));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
// Returns the "thread" of posts in the history of a post.
|
||||||
Returns the "thread" of posts in the history of a post.
|
findReplyHistory(post) {
|
||||||
|
const postStream = this,
|
||||||
@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,
|
|
||||||
url = "/posts/" + post.get('id') + "/reply-history.json?max_replies=" + Discourse.SiteSettings.max_reply_history;
|
url = "/posts/" + post.get('id') + "/reply-history.json?max_replies=" + Discourse.SiteSettings.max_reply_history;
|
||||||
|
|
||||||
return Discourse.ajax(url).then(function(result) {
|
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.
|
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.
|
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.
|
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; }
|
if (!this.get('hasPosts')) { return; }
|
||||||
|
|
||||||
var closest = null;
|
let closest = null;
|
||||||
this.get('posts').forEach(function (p) {
|
this.get('posts').forEach(function (p) {
|
||||||
if (!closest) {
|
if (!closest) {
|
||||||
closest = p;
|
closest = p;
|
||||||
|
@ -628,17 +523,12 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
@returns {Number} 1-starting index of the post, or 0 if not found
|
@returns {Number} 1-starting index of the post, or 0 if not found
|
||||||
@see PostStream.progressIndexOfPostId
|
@see PostStream.progressIndexOfPostId
|
||||||
**/
|
**/
|
||||||
progressIndexOfPost: function(post) {
|
progressIndexOfPost(post) {
|
||||||
return this.progressIndexOfPostId(post.get('id'));
|
return this.progressIndexOfPostId(post.get('id'));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
// Get the index in the stream of a post id. (Use this for the topic progress bar.)
|
||||||
Get the index in the stream of a post id. (Use this for the topic progress bar.)
|
progressIndexOfPostId(post_id) {
|
||||||
|
|
||||||
@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) {
|
|
||||||
return this.get('stream').indexOf(post_id) + 1;
|
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.
|
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.
|
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.
|
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; }
|
if (!this.get('hasPosts')) { return; }
|
||||||
|
|
||||||
var closest = null;
|
let closest = null;
|
||||||
this.get('posts').forEach(function (p) {
|
this.get('posts').forEach(function (p) {
|
||||||
if (closest === postNumber) { return; }
|
if (closest === postNumber) { return; }
|
||||||
if (!closest) { closest = p.get('post_number'); }
|
if (!closest) { closest = p.get('post_number'); }
|
||||||
|
@ -668,41 +554,33 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Find a postId for a postNumber, respecting gaps
|
// Find a postId for a postNumber, respecting gaps
|
||||||
findPostIdForPostNumber: function(postNumber) {
|
findPostIdForPostNumber(postNumber) {
|
||||||
var count = 1,
|
const stream = this.get('stream'),
|
||||||
stream = this.get('stream'),
|
|
||||||
beforeLookup = this.get('gaps.before'),
|
beforeLookup = this.get('gaps.before'),
|
||||||
streamLength = stream.length;
|
streamLength = stream.length;
|
||||||
|
|
||||||
for (var i=0; i<streamLength; i++) {
|
let sum = 1;
|
||||||
var pid = stream[i];
|
for (let i=0; i<streamLength; i++) {
|
||||||
|
const pid = stream[i];
|
||||||
|
|
||||||
// See if there are posts before this post
|
// See if there are posts before this post
|
||||||
if (beforeLookup) {
|
if (beforeLookup) {
|
||||||
var before = beforeLookup[pid];
|
const before = beforeLookup[pid];
|
||||||
if (before) {
|
if (before) {
|
||||||
for (var j=0; j<before.length; j++) {
|
for (let j=0; j<before.length; j++) {
|
||||||
if (count === postNumber) { return pid; }
|
if (sum === postNumber) { return pid; }
|
||||||
count++;
|
sum++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count === postNumber) { return pid; }
|
if (sum === postNumber) { return pid; }
|
||||||
count++;
|
sum++;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
updateFromJson(postStreamData) {
|
||||||
@private
|
const postStream = this,
|
||||||
|
|
||||||
Given a JSON packet, update this stream and the posts that exist in it.
|
|
||||||
|
|
||||||
@param {Object} postStreamData The JSON data we want to update from.
|
|
||||||
@method updateFromJson
|
|
||||||
**/
|
|
||||||
updateFromJson: function(postStreamData) {
|
|
||||||
var postStream = this,
|
|
||||||
posts = this.get('posts');
|
posts = this.get('posts');
|
||||||
|
|
||||||
posts.clear();
|
posts.clear();
|
||||||
|
@ -720,23 +598,17 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@private
|
|
||||||
|
|
||||||
Stores a post in our identity map, and sets up the references it needs to
|
Stores a post in our identity map, and sets up the references it needs to
|
||||||
find associated objects like the topic. It might return a different reference
|
find associated objects like the topic. It might return a different reference
|
||||||
than you supplied if the post has already been loaded.
|
than you supplied if the post has already been loaded.
|
||||||
|
|
||||||
@method storePost
|
|
||||||
@param {Discourse.Post} post The post we're storing in the identity map
|
|
||||||
@returns {Discourse.Post} the post from the identity map
|
|
||||||
**/
|
**/
|
||||||
storePost: function(post) {
|
storePost(post) {
|
||||||
// Calling `Em.get(undefined` raises an error
|
// Calling `Em.get(undefined` raises an error
|
||||||
if (!post) { return; }
|
if (!post) { return; }
|
||||||
|
|
||||||
var postId = Em.get(post, 'id');
|
const postId = Em.get(post, 'id');
|
||||||
if (postId) {
|
if (postId) {
|
||||||
var postIdentityMap = this.get('postIdentityMap'),
|
const postIdentityMap = this.get('postIdentityMap'),
|
||||||
existing = postIdentityMap.get(post.get('id'));
|
existing = postIdentityMap.get(post.get('id'));
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
|
@ -752,7 +624,7 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
postIdentityMap.set(post.get('id'), post);
|
postIdentityMap.set(post.get('id'), post);
|
||||||
|
|
||||||
// Update the `highest_post_number` if this post is higher.
|
// Update the `highest_post_number` if this post is higher.
|
||||||
var postNumber = post.get('post_number');
|
const postNumber = post.get('post_number');
|
||||||
if (postNumber && postNumber > (this.get('topic.highest_post_number') || 0)) {
|
if (postNumber && postNumber > (this.get('topic.highest_post_number') || 0)) {
|
||||||
this.set('topic.highest_post_number', postNumber);
|
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
|
Given a list of postIds, returns a list of the posts we don't have in our
|
||||||
identity map and need to load.
|
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) {
|
listUnloadedIds(postIds) {
|
||||||
var unloaded = Em.A(),
|
const unloaded = Em.A(),
|
||||||
postIdentityMap = this.get('postIdentityMap');
|
postIdentityMap = this.get('postIdentityMap');
|
||||||
postIds.forEach(function(p) {
|
postIds.forEach(function(p) {
|
||||||
if (!postIdentityMap.has(p)) { unloaded.pushObject(p); }
|
if (!postIdentityMap.has(p)) { unloaded.pushObject(p); }
|
||||||
|
@ -779,17 +645,8 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
return unloaded;
|
return unloaded;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
findPostsByIds(postIds) {
|
||||||
@private
|
const unloaded = this.listUnloadedIds(postIds),
|
||||||
|
|
||||||
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),
|
|
||||||
postIdentityMap = this.get('postIdentityMap');
|
postIdentityMap = this.get('postIdentityMap');
|
||||||
|
|
||||||
// Load our unloaded posts by id
|
// Load our unloaded posts by id
|
||||||
|
@ -800,27 +657,18 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
loadIntoIdentityMap(postIds) {
|
||||||
@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) {
|
|
||||||
// If we don't want any posts, return a promise that resolves right away
|
// If we don't want any posts, return a promise that resolves right away
|
||||||
if (Em.isEmpty(postIds)) {
|
if (Em.isEmpty(postIds)) {
|
||||||
return Ember.RSVP.resolve();
|
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 },
|
data = { post_ids: postIds },
|
||||||
postStream = this;
|
postStream = this;
|
||||||
|
|
||||||
return Discourse.ajax(url, {data: data}).then(function(result) {
|
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) {
|
if (posts) {
|
||||||
posts.forEach(function (p) {
|
posts.forEach(function (p) {
|
||||||
postStream.storePost(Discourse.Post.create(p));
|
postStream.storePost(Discourse.Post.create(p));
|
||||||
|
@ -830,33 +678,19 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
indexOf(post) {
|
||||||
@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) {
|
|
||||||
return this.get('stream').indexOf(post.get('id'));
|
return this.get('stream').indexOf(post.get('id'));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@private
|
|
||||||
|
|
||||||
Handles an error loading a topic based on a HTTP status code. Updates
|
Handles an error loading a topic based on a HTTP status code. Updates
|
||||||
the text to the correct values.
|
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) {
|
errorLoading(result) {
|
||||||
var status = result.status;
|
const status = result.status;
|
||||||
|
|
||||||
var topic = this.get('topic');
|
const topic = this.get('topic');
|
||||||
topic.set('loadingFilter', false);
|
topic.set('loadingFilter', false);
|
||||||
topic.set('errorLoading', true);
|
topic.set('errorLoading', true);
|
||||||
|
|
||||||
|
@ -887,10 +721,10 @@ Discourse.PostStream = Em.Object.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Discourse.PostStream.reopenClass({
|
PostStream.reopenClass({
|
||||||
|
|
||||||
create: function() {
|
create() {
|
||||||
var postStream = this._super.apply(this, arguments);
|
const postStream = this._super.apply(this, arguments);
|
||||||
postStream.setProperties({
|
postStream.setProperties({
|
||||||
posts: [],
|
posts: [],
|
||||||
stream: [],
|
stream: [],
|
||||||
|
@ -906,9 +740,9 @@ Discourse.PostStream.reopenClass({
|
||||||
return postStream;
|
return postStream;
|
||||||
},
|
},
|
||||||
|
|
||||||
loadTopicView: function(topicId, args) {
|
loadTopicView(topicId, args) {
|
||||||
var opts = _.merge({}, args),
|
const opts = _.merge({}, args);
|
||||||
url = Discourse.getURL("/t/") + topicId;
|
let url = Discourse.getURL("/t/") + topicId;
|
||||||
if (opts.nearPost) {
|
if (opts.nearPost) {
|
||||||
url += "/" + opts.nearPost;
|
url += "/" + opts.nearPost;
|
||||||
}
|
}
|
||||||
|
@ -921,3 +755,5 @@ Discourse.PostStream.reopenClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default PostStream;
|
|
@ -1,16 +1,13 @@
|
||||||
/**
|
/**
|
||||||
A model representing a Topic's details that aren't always present, such as a list of participants.
|
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.
|
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,
|
loaded: false,
|
||||||
|
|
||||||
updateFromJson: function(details) {
|
updateFromJson(details) {
|
||||||
|
const topic = this.get('topic');
|
||||||
|
|
||||||
if (details.allowed_users) {
|
if (details.allowed_users) {
|
||||||
details.allowed_users = details.allowed_users.map(function (u) {
|
details.allowed_users = details.allowed_users.map(function (u) {
|
||||||
return Discourse.User.create(u);
|
return Discourse.User.create(u);
|
||||||
|
@ -24,10 +21,9 @@ Discourse.TopicDetails = Discourse.Model.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (details.participants) {
|
if (details.participants) {
|
||||||
var topic = this.get('topic');
|
|
||||||
details.participants = details.participants.map(function (p) {
|
details.participants = details.participants.map(function (p) {
|
||||||
p.topic = topic;
|
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'),
|
}.property('notification_level', 'notifications_reason_id'),
|
||||||
|
|
||||||
|
|
||||||
updateNotifications: function(v) {
|
updateNotifications(v) {
|
||||||
this.set('notification_level', v);
|
this.set('notification_level', v);
|
||||||
this.set('notifications_reason_id', null);
|
this.set('notifications_reason_id', null);
|
||||||
return Discourse.ajax("/t/" + (this.get('topic.id')) + "/notifications", {
|
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'),
|
var users = this.get('allowed_users'),
|
||||||
username = user.get('username');
|
username = user.get('username');
|
||||||
|
|
||||||
|
@ -80,3 +76,5 @@ Discourse.TopicDetails = Discourse.Model.extend({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default TopicDetails;
|
|
@ -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
|
// returns createdAt if there's no bumped date
|
||||||
bumpedAt: function() {
|
bumpedAt: function() {
|
||||||
var bumpedAt = this.get('bumped_at');
|
const bumpedAt = this.get('bumped_at');
|
||||||
if (bumpedAt) {
|
if (bumpedAt) {
|
||||||
return new Date(bumpedAt);
|
return new Date(bumpedAt);
|
||||||
} else {
|
} else {
|
||||||
|
@ -20,11 +23,11 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
}.property('created_at'),
|
}.property('created_at'),
|
||||||
|
|
||||||
postStream: function() {
|
postStream: function() {
|
||||||
return Discourse.PostStream.create({topic: this});
|
return PostStream.create({topic: this});
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
details: function() {
|
details: function() {
|
||||||
return Discourse.TopicDetails.create({topic: this});
|
return TopicDetails.create({topic: this});
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
invisible: Em.computed.not('visible'),
|
invisible: Em.computed.not('visible'),
|
||||||
|
@ -35,12 +38,12 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
}.property('id'),
|
}.property('id'),
|
||||||
|
|
||||||
category: function() {
|
category: function() {
|
||||||
var categoryId = this.get('category_id');
|
const categoryId = this.get('category_id');
|
||||||
if (categoryId) {
|
if (categoryId) {
|
||||||
return Discourse.Category.list().findProperty('id', categoryId);
|
return Discourse.Category.list().findProperty('id', categoryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var categoryName = this.get('categoryName');
|
const categoryName = this.get('categoryName');
|
||||||
if (categoryName) {
|
if (categoryName) {
|
||||||
return Discourse.Category.list().findProperty('name', categoryName);
|
return Discourse.Category.list().findProperty('name', categoryName);
|
||||||
}
|
}
|
||||||
|
@ -52,12 +55,12 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
}.property('category.fullSlug'),
|
}.property('category.fullSlug'),
|
||||||
|
|
||||||
shareUrl: function(){
|
shareUrl: function(){
|
||||||
var user = Discourse.User.current();
|
const user = Discourse.User.current();
|
||||||
return this.get('url') + (user ? '?u=' + user.get('username_lower') : '');
|
return this.get('url') + (user ? '?u=' + user.get('username_lower') : '');
|
||||||
}.property('url'),
|
}.property('url'),
|
||||||
|
|
||||||
url: function() {
|
url: function() {
|
||||||
var slug = this.get('slug');
|
let slug = this.get('slug');
|
||||||
if (slug.trim().length === 0) {
|
if (slug.trim().length === 0) {
|
||||||
slug = "topic";
|
slug = "topic";
|
||||||
}
|
}
|
||||||
|
@ -65,8 +68,8 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
}.property('id', 'slug'),
|
}.property('id', 'slug'),
|
||||||
|
|
||||||
// Helper to build a Url with a post number
|
// Helper to build a Url with a post number
|
||||||
urlForPostNumber: function(postNumber) {
|
urlForPostNumber(postNumber) {
|
||||||
var url = this.get('url');
|
let url = this.get('url');
|
||||||
if (postNumber && (postNumber > 0)) {
|
if (postNumber && (postNumber > 0)) {
|
||||||
url += "/" + postNumber;
|
url += "/" + postNumber;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +77,7 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
totalUnread: function() {
|
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;
|
return count > 0 ? count : null;
|
||||||
}.property('new_posts', 'unread'),
|
}.property('new_posts', 'unread'),
|
||||||
|
|
||||||
|
@ -83,7 +86,7 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
}.property('url', 'last_read_post_number'),
|
}.property('url', 'last_read_post_number'),
|
||||||
|
|
||||||
lastUnreadUrl: function() {
|
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);
|
return this.urlForPostNumber(postNumber);
|
||||||
}.property('url', 'last_read_post_number', 'highest_post_number'),
|
}.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.
|
// tells us if we are still asynchronously flushing our "recently read" data.
|
||||||
// So take what the browser has seen into consideration.
|
// So take what the browser has seen into consideration.
|
||||||
displayNewPosts: function() {
|
displayNewPosts: function() {
|
||||||
var delta, result;
|
const highestSeen = Discourse.Session.currentProp('highestSeenByTopic')[this.get('id')];
|
||||||
var highestSeen = Discourse.Session.currentProp('highestSeenByTopic')[this.get('id')];
|
|
||||||
if (highestSeen) {
|
if (highestSeen) {
|
||||||
delta = highestSeen - this.get('last_read_post_number');
|
let delta = highestSeen - this.get('last_read_post_number');
|
||||||
if (delta > 0) {
|
if (delta > 0) {
|
||||||
result = this.get('new_posts') - delta;
|
let result = this.get('new_posts') - delta;
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
result = 0;
|
result = 0;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +125,7 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
}.property('new_posts', 'id'),
|
}.property('new_posts', 'id'),
|
||||||
|
|
||||||
viewsHeat: function() {
|
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_high ) return 'heatmap-high';
|
||||||
if( v >= Discourse.SiteSettings.topic_views_heat_medium ) return 'heatmap-med';
|
if( v >= Discourse.SiteSettings.topic_views_heat_medium ) return 'heatmap-med';
|
||||||
if( v >= Discourse.SiteSettings.topic_views_heat_low ) return 'heatmap-low';
|
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'),
|
isPrivateMessage: Em.computed.equal('archetype', 'private_message'),
|
||||||
isBanner: Em.computed.equal('archetype', 'banner'),
|
isBanner: Em.computed.equal('archetype', 'banner'),
|
||||||
|
|
||||||
toggleStatus: function(property) {
|
toggleStatus(property) {
|
||||||
this.toggleProperty(property);
|
this.toggleProperty(property);
|
||||||
this.saveStatus(property, this.get(property) ? true : false);
|
this.saveStatus(property, this.get(property) ? true : false);
|
||||||
},
|
},
|
||||||
|
|
||||||
setStatus: function(property, value) {
|
setStatus(property, value) {
|
||||||
this.set(property, value);
|
this.set(property, value);
|
||||||
this.saveStatus(property, value);
|
this.saveStatus(property, value);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveStatus: function(property, value) {
|
saveStatus(property, value) {
|
||||||
if (property === 'closed' && value === true) {
|
if (property === 'closed' && value === true) {
|
||||||
this.set('details.auto_close_at', null);
|
this.set('details.auto_close_at', null);
|
||||||
}
|
}
|
||||||
|
@ -160,28 +162,28 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
makeBanner: function() {
|
makeBanner() {
|
||||||
var self = this;
|
const self = this;
|
||||||
return Discourse.ajax('/t/' + this.get('id') + '/make-banner', { type: 'PUT' })
|
return Discourse.ajax('/t/' + this.get('id') + '/make-banner', { type: 'PUT' })
|
||||||
.then(function () { self.set('archetype', 'banner'); });
|
.then(function () { self.set('archetype', 'banner'); });
|
||||||
},
|
},
|
||||||
|
|
||||||
removeBanner: function() {
|
removeBanner() {
|
||||||
var self = this;
|
const self = this;
|
||||||
return Discourse.ajax('/t/' + this.get('id') + '/remove-banner', { type: 'PUT' })
|
return Discourse.ajax('/t/' + this.get('id') + '/remove-banner', { type: 'PUT' })
|
||||||
.then(function () { self.set('archetype', 'regular'); });
|
.then(function () { self.set('archetype', 'regular'); });
|
||||||
},
|
},
|
||||||
|
|
||||||
estimatedReadingTime: function() {
|
estimatedReadingTime: function() {
|
||||||
var wordCount = this.get('word_count');
|
const wordCount = this.get('word_count');
|
||||||
if (!wordCount) return;
|
if (!wordCount) return;
|
||||||
|
|
||||||
// Avg for 500 words per minute when you account for skimming
|
// Avg for 500 words per minute when you account for skimming
|
||||||
return Math.floor(wordCount / 500.0);
|
return Math.floor(wordCount / 500.0);
|
||||||
}.property('word_count'),
|
}.property('word_count'),
|
||||||
|
|
||||||
toggleBookmark: function() {
|
toggleBookmark() {
|
||||||
var self = this, firstPost = this.get("postStream.posts")[0];
|
const self = this, firstPost = this.get("postStream.posts")[0];
|
||||||
|
|
||||||
this.toggleProperty('bookmarked');
|
this.toggleProperty('bookmarked');
|
||||||
if (this.get("postStream.firstPostPresent")) { firstPost.toggleProperty("bookmarked"); }
|
if (this.get("postStream.firstPostPresent")) { firstPost.toggleProperty("bookmarked"); }
|
||||||
|
@ -194,8 +196,7 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
self.toggleProperty('bookmarked');
|
self.toggleProperty('bookmarked');
|
||||||
if (self.get("postStream.firstPostPresent")) { firstPost.toggleProperty('bookmarked'); }
|
if (self.get("postStream.firstPostPresent")) { firstPost.toggleProperty('bookmarked'); }
|
||||||
|
|
||||||
var showGenericError = true;
|
let showGenericError = true;
|
||||||
|
|
||||||
if (error && error.responseText) {
|
if (error && error.responseText) {
|
||||||
try {
|
try {
|
||||||
bootbox.alert($.parseJSON(error.responseText).errors);
|
bootbox.alert($.parseJSON(error.responseText).errors);
|
||||||
|
@ -209,13 +210,7 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
createInvite(emailOrUsername, groupNames) {
|
||||||
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) {
|
|
||||||
return Discourse.ajax("/t/" + this.get('id') + "/invite", {
|
return Discourse.ajax("/t/" + this.get('id') + "/invite", {
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: { user: emailOrUsername, group_names: groupNames }
|
data: { user: emailOrUsername, group_names: groupNames }
|
||||||
|
@ -223,7 +218,7 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Delete this topic
|
// Delete this topic
|
||||||
destroy: function(deleted_by) {
|
destroy(deleted_by) {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
deleted_at: new Date(),
|
deleted_at: new Date(),
|
||||||
deleted_by: deleted_by,
|
deleted_by: deleted_by,
|
||||||
|
@ -237,7 +232,7 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Recover this topic if deleted
|
// Recover this topic if deleted
|
||||||
recover: function() {
|
recover() {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
deleted_at: null,
|
deleted_at: null,
|
||||||
deleted_by: null,
|
deleted_by: null,
|
||||||
|
@ -248,14 +243,14 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Update our attributes from a JSON result
|
// Update our attributes from a JSON result
|
||||||
updateFromJson: function(json) {
|
updateFromJson(json) {
|
||||||
this.get('details').updateFromJson(json.details);
|
this.get('details').updateFromJson(json.details);
|
||||||
|
|
||||||
var keys = Object.keys(json);
|
const keys = Object.keys(json);
|
||||||
keys.removeObject('details');
|
keys.removeObject('details');
|
||||||
keys.removeObject('post_stream');
|
keys.removeObject('post_stream');
|
||||||
|
|
||||||
var topic = this;
|
const topic = this;
|
||||||
keys.forEach(function (key) {
|
keys.forEach(function (key) {
|
||||||
topic.set(key, json[key]);
|
topic.set(key, json[key]);
|
||||||
});
|
});
|
||||||
|
@ -266,13 +261,8 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
return this.get('pinned') && this.get('category.isUncategorizedCategory');
|
return this.get('pinned') && this.get('category.isUncategorizedCategory');
|
||||||
}.property('pinned', 'category.isUncategorizedCategory'),
|
}.property('pinned', 'category.isUncategorizedCategory'),
|
||||||
|
|
||||||
/**
|
clearPin() {
|
||||||
Clears the pin from a topic for the currently logged in user
|
const topic = this;
|
||||||
|
|
||||||
@method clearPin
|
|
||||||
**/
|
|
||||||
clearPin: function() {
|
|
||||||
var topic = this;
|
|
||||||
|
|
||||||
// Clear the pin optimistically from the object
|
// Clear the pin optimistically from the object
|
||||||
topic.set('pinned', false);
|
topic.set('pinned', false);
|
||||||
|
@ -287,7 +277,7 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
togglePinnedForUser: function() {
|
togglePinnedForUser() {
|
||||||
if (this.get('pinned')) {
|
if (this.get('pinned')) {
|
||||||
this.clearPin();
|
this.clearPin();
|
||||||
} else {
|
} else {
|
||||||
|
@ -295,13 +285,8 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
rePin() {
|
||||||
Re-pins a topic with a cleared pin
|
const topic = this;
|
||||||
|
|
||||||
@method rePin
|
|
||||||
**/
|
|
||||||
rePin: function() {
|
|
||||||
var topic = this;
|
|
||||||
|
|
||||||
// Clear the pin optimistically from the object
|
// Clear the pin optimistically from the object
|
||||||
topic.set('pinned', true);
|
topic.set('pinned', true);
|
||||||
|
@ -317,12 +302,12 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Is the reply to a post directly below it?
|
// Is the reply to a post directly below it?
|
||||||
isReplyDirectlyBelow: function(post) {
|
isReplyDirectlyBelow(post) {
|
||||||
var posts = this.get('postStream.posts');
|
const posts = this.get('postStream.posts');
|
||||||
var postNumber = post.get('post_number');
|
const postNumber = post.get('post_number');
|
||||||
if (!posts) return;
|
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,
|
// If the post directly below's reply_to_post_number is our post number or we are quoted,
|
||||||
// it's considered directly below.
|
// it's considered directly below.
|
||||||
|
@ -340,7 +325,7 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
hasExcerpt: Em.computed.and('pinned', 'excerptNotEmpty'),
|
hasExcerpt: Em.computed.and('pinned', 'excerptNotEmpty'),
|
||||||
|
|
||||||
excerptTruncated: function() {
|
excerptTruncated: function() {
|
||||||
var e = this.get('excerpt');
|
const e = this.get('excerpt');
|
||||||
return( e && e.substr(e.length - 8,8) === '…' );
|
return( e && e.substr(e.length - 8,8) === '…' );
|
||||||
}.property('excerpt'),
|
}.property('excerpt'),
|
||||||
|
|
||||||
|
@ -349,7 +334,7 @@ Discourse.Topic = Discourse.Model.extend({
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Discourse.Topic.reopenClass({
|
Topic.reopenClass({
|
||||||
NotificationLevel: {
|
NotificationLevel: {
|
||||||
WATCHING: 3,
|
WATCHING: 3,
|
||||||
TRACKING: 2,
|
TRACKING: 2,
|
||||||
|
@ -357,13 +342,13 @@ Discourse.Topic.reopenClass({
|
||||||
MUTED: 0
|
MUTED: 0
|
||||||
},
|
},
|
||||||
|
|
||||||
createActionSummary: function(result) {
|
createActionSummary(result) {
|
||||||
if (result.actions_summary) {
|
if (result.actions_summary) {
|
||||||
var lookup = Em.Object.create();
|
const lookup = Em.Object.create();
|
||||||
result.actions_summary = result.actions_summary.map(function(a) {
|
result.actions_summary = result.actions_summary.map(function(a) {
|
||||||
a.post = result;
|
a.post = result;
|
||||||
a.actionType = Discourse.Site.current().postActionTypeById(a.id);
|
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);
|
lookup.set(a.actionType.get('name_key'), actionSummary);
|
||||||
return actionSummary;
|
return actionSummary;
|
||||||
});
|
});
|
||||||
|
@ -371,7 +356,7 @@ Discourse.Topic.reopenClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
update: function(topic, props) {
|
update(topic, props) {
|
||||||
props = JSON.parse(JSON.stringify(props)) || {};
|
props = JSON.parse(JSON.stringify(props)) || {};
|
||||||
|
|
||||||
// We support `category_id` and `categoryId` for compatibility
|
// 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
|
// allows us to make a distinction between arrays that were not
|
||||||
// sent and arrays that we specifically want to be empty.
|
// sent and arrays that we specifically want to be empty.
|
||||||
Object.keys(props).forEach(function(k) {
|
Object.keys(props).forEach(function(k) {
|
||||||
var v = props[k];
|
const v = props[k];
|
||||||
if (v instanceof Array && v.length === 0) {
|
if (v instanceof Array && v.length === 0) {
|
||||||
props[k + '_empty_array'] = true;
|
props[k + '_empty_array'] = true;
|
||||||
}
|
}
|
||||||
|
@ -400,24 +385,16 @@ Discourse.Topic.reopenClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
create: function() {
|
create() {
|
||||||
var result = this._super.apply(this, arguments);
|
const result = this._super.apply(this, arguments);
|
||||||
this.createActionSummary(result);
|
this.createActionSummary(result);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
findSimilarTo(title, body) {
|
||||||
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) {
|
|
||||||
return Discourse.ajax("/topics/similar_to", { data: {title: title, raw: body} }).then(function (results) {
|
return Discourse.ajax("/topics/similar_to", { data: {title: title, raw: body} }).then(function (results) {
|
||||||
if (Array.isArray(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 {
|
} else {
|
||||||
return Ember.A();
|
return Ember.A();
|
||||||
}
|
}
|
||||||
|
@ -425,14 +402,13 @@ Discourse.Topic.reopenClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Load a topic, but accepts a set of filters
|
// Load a topic, but accepts a set of filters
|
||||||
find: function(topicId, opts) {
|
find(topicId, opts) {
|
||||||
var url = Discourse.getURL("/t/") + topicId;
|
let url = Discourse.getURL("/t/") + topicId;
|
||||||
|
|
||||||
if (opts.nearPost) {
|
if (opts.nearPost) {
|
||||||
url += "/" + opts.nearPost;
|
url += "/" + opts.nearPost;
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = {};
|
const data = {};
|
||||||
if (opts.postsAfter) {
|
if (opts.postsAfter) {
|
||||||
data.posts_after = opts.postsAfter;
|
data.posts_after = opts.postsAfter;
|
||||||
}
|
}
|
||||||
|
@ -461,8 +437,8 @@ Discourse.Topic.reopenClass({
|
||||||
return Discourse.ajax(url + ".json", {data: data});
|
return Discourse.ajax(url + ".json", {data: data});
|
||||||
},
|
},
|
||||||
|
|
||||||
mergeTopic: function(topicId, destinationTopicId) {
|
mergeTopic(topicId, destinationTopicId) {
|
||||||
var promise = Discourse.ajax("/t/" + topicId + "/merge-topic", {
|
const promise = Discourse.ajax("/t/" + topicId + "/merge-topic", {
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: {destination_topic_id: destinationTopicId}
|
data: {destination_topic_id: destinationTopicId}
|
||||||
}).then(function (result) {
|
}).then(function (result) {
|
||||||
|
@ -472,8 +448,8 @@ Discourse.Topic.reopenClass({
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
movePosts: function(topicId, opts) {
|
movePosts(topicId, opts) {
|
||||||
var promise = Discourse.ajax("/t/" + topicId + "/move-posts", {
|
const promise = Discourse.ajax("/t/" + topicId + "/move-posts", {
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: opts
|
data: opts
|
||||||
}).then(function (result) {
|
}).then(function (result) {
|
||||||
|
@ -483,8 +459,8 @@ Discourse.Topic.reopenClass({
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
changeOwners: function(topicId, opts) {
|
changeOwners(topicId, opts) {
|
||||||
var promise = Discourse.ajax("/t/" + topicId + "/change-owner", {
|
const promise = Discourse.ajax("/t/" + topicId + "/change-owner", {
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: opts
|
data: opts
|
||||||
}).then(function (result) {
|
}).then(function (result) {
|
||||||
|
@ -494,7 +470,7 @@ Discourse.Topic.reopenClass({
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
bulkOperation: function(topics, operation) {
|
bulkOperation(topics, operation) {
|
||||||
return Discourse.ajax("/topics/bulk", {
|
return Discourse.ajax("/topics/bulk", {
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
data: {
|
data: {
|
||||||
|
@ -504,8 +480,8 @@ Discourse.Topic.reopenClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
bulkOperationByFilter: function(filter, operation, categoryId) {
|
bulkOperationByFilter(filter, operation, categoryId) {
|
||||||
var data = { filter: filter, operation: operation };
|
const data = { filter: filter, operation: operation };
|
||||||
if (categoryId) data['category_id'] = categoryId;
|
if (categoryId) data['category_id'] = categoryId;
|
||||||
return Discourse.ajax("/topics/bulk", {
|
return Discourse.ajax("/topics/bulk", {
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
|
@ -513,12 +489,13 @@ Discourse.Topic.reopenClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
resetNew: function() {
|
resetNew() {
|
||||||
return Discourse.ajax("/topics/reset-new", {type: 'PUT'});
|
return Discourse.ajax("/topics/reset-new", {type: 'PUT'});
|
||||||
},
|
},
|
||||||
|
|
||||||
idForSlug: function(slug) {
|
idForSlug(slug) {
|
||||||
return Discourse.ajax("/t/id_for/" + slug);
|
return Discourse.ajax("/t/id_for/" + slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default Topic;
|
|
@ -1,6 +1,8 @@
|
||||||
|
import Topic from 'discourse/models/topic';
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
export default Discourse.Route.extend({
|
||||||
model: function(params) {
|
model: function(params) {
|
||||||
return Discourse.Topic.idForSlug(params.slug);
|
return Topic.idForSlug(params.slug);
|
||||||
},
|
},
|
||||||
|
|
||||||
afterModel: function(result) {
|
afterModel: function(result) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ var isTransitioning = false,
|
||||||
SCROLL_DELAY = 500;
|
SCROLL_DELAY = 500;
|
||||||
|
|
||||||
import ShowFooter from "discourse/mixins/show-footer";
|
import ShowFooter from "discourse/mixins/show-footer";
|
||||||
|
import Topic from 'discourse/models/topic';
|
||||||
|
|
||||||
var TopicRoute = Discourse.Route.extend(ShowFooter, {
|
var TopicRoute = Discourse.Route.extend(ShowFooter, {
|
||||||
redirect: function() { return this.redirectIfLoginRequired(); },
|
redirect: function() { return this.redirectIfLoginRequired(); },
|
||||||
|
@ -163,7 +164,7 @@ var TopicRoute = Discourse.Route.extend(ShowFooter, {
|
||||||
return topic;
|
return topic;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return this.setupParams(Discourse.Topic.create(_.omit(params, 'username_filters', 'filter')), queryParams);
|
return this.setupParams(Topic.create(_.omit(params, 'username_filters', 'filter')), queryParams);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -154,8 +154,6 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
var $wmdPreview = $('#wmd-preview');
|
var $wmdPreview = $('#wmd-preview');
|
||||||
if ($wmdPreview.length === 0) return;
|
if ($wmdPreview.length === 0) return;
|
||||||
|
|
||||||
Discourse.SyntaxHighlighting.apply($wmdPreview);
|
|
||||||
|
|
||||||
var post = this.get('model.post'),
|
var post = this.get('model.post'),
|
||||||
refresh = false;
|
refresh = false;
|
||||||
|
|
||||||
|
|
|
@ -264,8 +264,6 @@ var PostView = Discourse.GroupedView.extend(Ember.Evented, {
|
||||||
this._showLinkCounts();
|
this._showLinkCounts();
|
||||||
|
|
||||||
Discourse.ScreenTrack.current().track(this.$().prop('id'), postNumber);
|
Discourse.ScreenTrack.current().track(this.$().prop('id'), postNumber);
|
||||||
Discourse.SyntaxHighlighting.apply($post);
|
|
||||||
Discourse.Lightbox.apply($post);
|
|
||||||
|
|
||||||
this.trigger('postViewInserted', $post);
|
this.trigger('postViewInserted', $post);
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
//= require ./discourse/models/model
|
//= require ./discourse/models/model
|
||||||
//= require ./discourse/models/user_action
|
//= require ./discourse/models/user_action
|
||||||
//= require ./discourse/models/composer
|
//= require ./discourse/models/composer
|
||||||
|
//= require ./discourse/models/post-stream
|
||||||
|
//= require ./discourse/models/topic-details
|
||||||
//= require ./discourse/models/topic
|
//= require ./discourse/models/topic
|
||||||
//= require ./discourse/models/top-period
|
//= require ./discourse/models/top-period
|
||||||
//= require ./discourse/controllers/controller
|
//= require ./discourse/controllers/controller
|
||||||
|
|
|
@ -3,8 +3,10 @@ moduleFor('controller:topic', 'controller:topic', {
|
||||||
'controller:search', 'controller:topic-progress', 'controller:application']
|
'controller:search', 'controller:topic-progress', 'controller:application']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
import Topic from 'discourse/models/topic';
|
||||||
|
|
||||||
var buildTopic = function() {
|
var buildTopic = function() {
|
||||||
return Discourse.Topic.create({
|
return Topic.create({
|
||||||
title: "Qunit Test Topic",
|
title: "Qunit Test Topic",
|
||||||
participants: [
|
participants: [
|
||||||
{id: 1234,
|
{id: 1234,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
module("Discourse.SelectedPostsCount");
|
module("Discourse.SelectedPostsCount");
|
||||||
|
|
||||||
|
import Topic from 'discourse/models/topic';
|
||||||
|
|
||||||
var buildTestObj = function(params) {
|
var buildTestObj = function(params) {
|
||||||
return Ember.Object.createWithMixins(Discourse.SelectedPostsCount, 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() {
|
test("when all posts are selected and there is topic with a posts_count", function() {
|
||||||
var testObj = buildTestObj({
|
var testObj = buildTestObj({
|
||||||
allPostsSelected: true,
|
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");
|
equal(testObj.get('selectedPostsCount'), 3456, "It returns the topic's posts_count");
|
||||||
|
|
|
@ -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 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');
|
var ps = topic.get('postStream');
|
||||||
if (stream) {
|
if (stream) {
|
||||||
ps.set('stream', stream);
|
ps.set('stream', stream);
|
||||||
|
@ -12,7 +15,7 @@ var buildStream = function(id, stream) {
|
||||||
var participant = {username: 'eviltrout'};
|
var participant = {username: 'eviltrout'};
|
||||||
|
|
||||||
test('create', function() {
|
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() {
|
test('defaults', function() {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
module("Discourse.TopicDetails");
|
module("model:topic-details");
|
||||||
|
|
||||||
|
import Topic from 'discourse/models/topic';
|
||||||
|
|
||||||
var buildDetails = function(id) {
|
var buildDetails = function(id) {
|
||||||
var topic = Discourse.Topic.create({id: id});
|
var topic = Topic.create({id: id});
|
||||||
return topic.get('details');
|
return topic.get('details');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,13 +22,9 @@ test('updateFromJson', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
equal(details.get('suggested_topics.length'), 2, 'it loaded the suggested_topics');
|
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');
|
equal(details.get('allowed_users.length'), 1, 'it loaded the allowed users');
|
||||||
containsInstance(details.get('allowed_users'), Discourse.User);
|
containsInstance(details.get('allowed_users'), Discourse.User);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
module("Discourse.Topic");
|
module("model:topic");
|
||||||
|
|
||||||
|
import Topic from 'discourse/models/topic';
|
||||||
|
|
||||||
test("defaults", function() {
|
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_at'), 'deleted_at defaults to blank');
|
||||||
blank(topic.get('deleted_by'), 'deleted_by defaults to blank');
|
blank(topic.get('deleted_by'), 'deleted_by defaults to blank');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('has details', function() {
|
test('has details', function() {
|
||||||
var topic = Discourse.Topic.create({id: 1234});
|
var topic = Topic.create({id: 1234});
|
||||||
var topicDetails = topic.get('details');
|
var topicDetails = topic.get('details');
|
||||||
present(topicDetails, "a topic has topicDetails after we create it");
|
present(topicDetails, "a topic has topicDetails after we create it");
|
||||||
equal(topicDetails.get('topic'), topic, "the topicDetails has a reference back to the topic");
|
equal(topicDetails.get('topic'), topic, "the topicDetails has a reference back to the topic");
|
||||||
});
|
});
|
||||||
|
|
||||||
test('has a postStream', function() {
|
test('has a postStream', function() {
|
||||||
var topic = Discourse.Topic.create({id: 1234});
|
var topic = Topic.create({id: 1234});
|
||||||
var postStream = topic.get('postStream');
|
var postStream = topic.get('postStream');
|
||||||
present(postStream, "a topic has a postStream after we create it");
|
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");
|
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() {
|
test('category relationship', function() {
|
||||||
// It finds the category by id
|
// It finds the category by id
|
||||||
var category = Discourse.Category.list()[0],
|
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);
|
equal(topic.get('category'), category);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("updateFromJson", function() {
|
test("updateFromJson", function() {
|
||||||
var topic = Discourse.Topic.create({id: 1234}),
|
var topic = Topic.create({id: 1234}),
|
||||||
category = Discourse.Category.list()[0];
|
category = Discourse.Category.list()[0];
|
||||||
|
|
||||||
topic.updateFromJson({
|
topic.updateFromJson({
|
||||||
|
@ -48,7 +50,7 @@ test("updateFromJson", function() {
|
||||||
|
|
||||||
test("destroy", function() {
|
test("destroy", function() {
|
||||||
var user = Discourse.User.create({username: 'eviltrout'});
|
var user = Discourse.User.create({username: 'eviltrout'});
|
||||||
var topic = Discourse.Topic.create({id: 1234});
|
var topic = Topic.create({id: 1234});
|
||||||
|
|
||||||
sandbox.stub(Discourse, 'ajax');
|
sandbox.stub(Discourse, 'ajax');
|
||||||
|
|
||||||
|
@ -60,7 +62,7 @@ test("destroy", function() {
|
||||||
|
|
||||||
test("recover", function() {
|
test("recover", function() {
|
||||||
var user = Discourse.User.create({username: 'eviltrout'});
|
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');
|
sandbox.stub(Discourse, 'ajax');
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user