FIX: Reply as new topic should select the correct category

This commit is contained in:
Robin Ward 2015-03-12 14:41:58 -04:00
parent 3ecb58980f
commit 091af27a31
4 changed files with 205 additions and 207 deletions

View File

@ -1,6 +1,7 @@
var MAX_SHOWN = 5;
import StringBuffer from 'discourse/mixins/string-buffer';
import { iconHTML } from 'discourse/helpers/fa-icon';
export default Em.Component.extend(StringBuffer, {
classNameBindings: [':gutter'],
@ -55,14 +56,14 @@ export default Em.Component.extend(StringBuffer, {
if (collapsed) {
var remaining = links.length - MAX_SHOWN;
if (remaining > 0) {
buffer.push("<li><a href='#' class='toggle-more'>" + I18n.t('post.more_links', {count: remaining}) + "</a></li>");
buffer.push("<li><a href class='toggle-more'>" + I18n.t('post.more_links', {count: remaining}) + "</a></li>");
}
}
buffer.push('</ul>');
}
if ((links.length <= MAX_SHOWN || !collapsed) && this.get('canReplyAsNewTopic')) {
buffer.push("<a href='#' class='reply-new'><i class='fa fa-plus'></i>" + I18n.t('post.reply_as_new_topic') + "</a>");
buffer.push("<a href class='reply-new'>" + iconHTML('plus') + I18n.t('post.reply_as_new_topic') + "</a>");
}
},

View File

@ -410,7 +410,7 @@ export default DiscourseController.extend({
// Given a potential instance and options, set the model for this composer.
_setModel(composerModel, opts) {
if (opts.draft) {
composerModel = Discourse.Composer.loadDraft(opts.draftKey, opts.draftSequence, opts.draft);
composerModel = Discourse.Composer.loadDraft(opts);
if (composerModel) {
composerModel.set('topic', opts.topic);
}

View File

@ -20,7 +20,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}.observes('topic'),
_titleChanged: function() {
var title = this.get('title');
const title = this.get('title');
if (!Ember.isEmpty(title)) {
// Note normally you don't have to trigger this, but topic titles can be updated
@ -30,8 +30,8 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}.observes('title', 'category'),
termChanged: function() {
var dropdown = this.get('controllers.header.visibleDropdown');
var term = this.get('controllers.search.term');
const dropdown = this.get('controllers.header.visibleDropdown');
const term = this.get('controllers.search.term');
if(dropdown === 'search-dropdown' && term){
this.set('searchHighlight', term);
@ -43,13 +43,13 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}.observes('controllers.search.term', 'controllers.header.visibleDropdown'),
postStreamLoadedAllPostsChanged: function(){
postStreamLoadedAllPostsChanged: function() {
// semantics of loaded all posts are slightly diff at topic level,
// it just means that we "once" loaded all posts, this means we don't
// keep re-rendering the suggested topics when new posts zoom in
var loaded = this.get('postStream.loadedAllPosts');
let loaded = this.get('postStream.loadedAllPosts');
if(loaded) {
if (loaded) {
this.set('loadedTopicId', this.get('model.id'));
} else {
loaded = this.get('loadedTopicId') === this.get('model.id');
@ -60,7 +60,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}.observes('postStream', 'postStream.loadedAllPosts'),
show_deleted: function(key, value) {
var postStream = this.get('postStream');
const postStream = this.get('postStream');
if (!postStream) { return; }
if (arguments.length > 1) {
@ -70,7 +70,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}.property('postStream.summary'),
filter: function(key, value) {
var postStream = this.get('postStream');
const postStream = this.get('postStream');
if (!postStream) { return; }
if (arguments.length > 1) {
@ -80,7 +80,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}.property('postStream.summary'),
username_filters: function(key, value) {
var postStream = this.get('postStream');
const postStream = this.get('postStream');
if (!postStream) { return; }
if (arguments.length > 1) {
@ -89,20 +89,19 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
return postStream.get('streamFilters.username_filters');
}.property('postStream.streamFilters.username_filters'),
init: function() {
this._super();
_clearSelected: function() {
this.set('selectedPosts', []);
this.set('selectedReplies', []);
},
}.on('init'),
actions: {
deleteTopic: function() {
deleteTopic() {
this.deleteTopic();
},
// Post related methods
replyToPost: function(post) {
var composerController = this.get('controllers.composer'),
replyToPost(post) {
const composerController = this.get('controllers.composer'),
quoteController = this.get('controllers.quote-button'),
quotedText = Discourse.Quote.build(quoteController.get('post'), quoteController.get('buffer')),
topic = post ? post.get('topic') : this.get('model');
@ -116,7 +115,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
composerController.appendText(quotedText);
} else {
var opts = {
const opts = {
action: Discourse.Composer.REPLY,
draftKey: topic.get('draft_key'),
draftSequence: topic.get('draft_sequence')
@ -135,14 +134,14 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
return false;
},
toggleLike: function(post) {
var likeAction = post.get('actionByName.like');
toggleLike(post) {
const likeAction = post.get('actionByName.like');
if (likeAction && likeAction.get('canToggle')) {
likeAction.toggle();
}
},
recoverPost: function(post) {
recoverPost(post) {
// Recovering the first post recovers the topic instead
if (post.get('post_number') === 1) {
this.recoverTopic();
@ -151,7 +150,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
post.recover();
},
deletePost: function(post) {
deletePost(post) {
// Deleting the first post deletes the topic
if (post.get('post_number') === 1) {
@ -159,7 +158,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
return;
}
var user = Discourse.User.current(),
const user = Discourse.User.current(),
replyCount = post.get('reply_count'),
self = this;
@ -169,13 +168,13 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
{label: I18n.t("cancel"),
'class': 'btn-danger rightg'},
{label: I18n.t("post.controls.delete_replies.no_value"),
callback: function() {
callback() {
post.destroy(user);
}
},
{label: I18n.t("post.controls.delete_replies.yes_value"),
'class': 'btn-primary',
callback: function() {
callback() {
Discourse.Post.deleteMany([post], [post]);
self.get('postStream.posts').forEach(function (p) {
if (p === post || p.get('reply_to_post_number') === post.get('post_number')) {
@ -188,7 +187,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
} else {
post.destroy(user).then(null, function(e) {
post.undoDeleteState();
var response = $.parseJSON(e.responseText);
const response = $.parseJSON(e.responseText);
if (response && response.errors) {
bootbox.alert(response.errors[0]);
} else {
@ -198,7 +197,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}
},
editPost: function(post) {
editPost(post) {
if (!Discourse.User.current()) {
return bootbox.alert(I18n.t('post.controls.edit_anonymous'));
}
@ -211,7 +210,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
});
},
toggleBookmark: function(post) {
toggleBookmark(post) {
if (!Discourse.User.current()) {
alert(I18n.t("bookmarks.not_bookmarked"));
return;
@ -229,12 +228,12 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}
},
jumpTop: function() {
jumpTop() {
this.get('controllers.topic-progress').send('jumpTop');
},
selectAll: function() {
var posts = this.get('postStream.posts'),
selectAll() {
const posts = this.get('postStream.posts'),
selectedPosts = this.get('selectedPosts');
if (posts) {
selectedPosts.addObjects(posts);
@ -242,37 +241,37 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
this.set('allPostsSelected', true);
},
deselectAll: function() {
deselectAll() {
this.get('selectedPosts').clear();
this.get('selectedReplies').clear();
this.set('allPostsSelected', false);
},
toggleParticipant: function(user) {
toggleParticipant(user) {
this.get('postStream').toggleParticipant(Em.get(user, 'username'));
},
editTopic: function() {
editTopic() {
if (!this.get('details.can_edit')) return false;
this.set('editingTopic', true);
return false;
},
cancelEditingTopic: function() {
cancelEditingTopic() {
this.set('editingTopic', false);
this.rollbackBuffer();
},
toggleMultiSelect: function() {
toggleMultiSelect() {
this.toggleProperty('multiSelect');
},
finishedEditingTopic: function() {
finishedEditingTopic() {
if (!this.get('editingTopic')) { return; }
// save the modifications
var self = this,
const self = this,
props = this.get('buffered.buffer');
Topic.update(this.get('model'), props).then(function() {
@ -289,12 +288,12 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
});
},
toggledSelectedPost: function(post) {
toggledSelectedPost(post) {
this.performTogglePost(post);
},
toggledSelectedPostReplies: function(post) {
var selectedReplies = this.get('selectedReplies');
toggledSelectedPostReplies(post) {
const selectedReplies = this.get('selectedReplies');
if (this.performTogglePost(post)) {
selectedReplies.addObject(post);
} else {
@ -302,8 +301,8 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}
},
deleteSelected: function() {
var self = this;
deleteSelected() {
const self = this;
bootbox.confirm(I18n.t("post.delete.confirm", { count: this.get('selectedPostsCount')}), function(result) {
if (result) {
@ -312,7 +311,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
return self.deleteTopic();
}
var selectedPosts = self.get('selectedPosts'),
const selectedPosts = self.get('selectedPosts'),
selectedReplies = self.get('selectedReplies'),
postStream = self.get('postStream'),
toRemove = [];
@ -328,59 +327,54 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
});
},
expandHidden: function(post) {
expandHidden(post) {
post.expandHidden();
},
toggleVisibility: function() {
toggleVisibility() {
this.get('content').toggleStatus('visible');
},
toggleClosed: function() {
toggleClosed() {
this.get('content').toggleStatus('closed');
},
recoverTopic: function() {
recoverTopic() {
this.get('content').recover();
},
makeBanner: function() {
makeBanner() {
this.get('content').makeBanner();
},
removeBanner: function() {
removeBanner() {
this.get('content').removeBanner();
},
togglePinned: function() {
togglePinned() {
// Note that this is different than clearPin
this.get('content').setStatus('pinned', this.get('pinned_at') ? false : true);
},
togglePinnedGlobally: function() {
togglePinnedGlobally() {
// Note that this is different than clearPin
this.get('content').setStatus('pinned_globally', this.get('pinned_at') ? false : true);
},
toggleArchived: function() {
toggleArchived() {
this.get('content').toggleStatus('archived');
},
// Toggle the star on the topic
toggleStar: function() {
toggleStar() {
this.get('content').toggleStar();
},
/**
Clears the pin from a topic for the currently logged in user
@method clearPin
**/
clearPin: function() {
clearPin() {
this.get('content').clearPin();
},
togglePinnedForUser: function() {
togglePinnedForUser() {
if (this.get('pinned_at')) {
if (this.get('pinned')) {
this.get('content').clearPin();
@ -390,28 +384,29 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}
},
replyAsNewTopic: function(post) {
var composerController = this.get('controllers.composer'),
quoteController = this.get('controllers.quote-button'),
quotedText = Discourse.Quote.build(quoteController.get('post'), quoteController.get('buffer')),
self = this;
replyAsNewTopic(post) {
const composerController = this.get('controllers.composer'),
quoteController = this.get('controllers.quote-button'),
quotedText = Discourse.Quote.build(quoteController.get('post'), quoteController.get('buffer')),
self = this;
quoteController.deselectText();
composerController.open({
action: Discourse.Composer.CREATE_TOPIC,
draftKey: Discourse.Composer.REPLY_AS_NEW_TOPIC_KEY
draftKey: Discourse.Composer.REPLY_AS_NEW_TOPIC_KEY,
categoryId: this.get('category.id')
}).then(function() {
return Em.isEmpty(quotedText) ? Discourse.Post.loadQuote(post.get('id')) : quotedText;
}).then(function(q) {
var postUrl = "" + location.protocol + "//" + location.host + (post.get('url')),
postLink = "[" + self.get('title') + "](" + postUrl + ")";
const postUrl = "" + location.protocol + "//" + location.host + (post.get('url')),
postLink = "[" + self.get('title') + "](" + postUrl + ")";
composerController.appendText(I18n.t("post.continue_discussion", { postLink: postLink }) + "\n\n" + q);
});
},
expandFirstPost: function(post) {
var self = this;
expandFirstPost(post) {
const self = this;
this.set('loadingExpanded', true);
post.expand().then(function() {
self.set('firstPostExpanded', true);
@ -422,8 +417,8 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
});
},
retryLoading: function() {
var self = this;
retryLoading() {
const self = this;
self.set('retrying', true);
this.get('postStream').refresh().then(function() {
self.set('retrying', false);
@ -432,7 +427,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
});
},
toggleWiki: function(post) {
toggleWiki(post) {
// the request to the server is made in an observer in the post class
post.toggleProperty('wiki');
},
@ -449,21 +444,21 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}
},
rebakePost: function (post) {
rebakePost(post) {
post.rebake();
},
unhidePost: function (post) {
unhidePost(post) {
post.unhide();
}
},
togglePinnedState: function() {
togglePinnedState() {
this.send('togglePinnedForUser');
},
showExpandButton: function() {
var post = this.get('post');
const post = this.get('post');
return post.get('post_number') === 1 && post.get('topic.expandable_first_post');
}.property(),
@ -495,12 +490,12 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}.property('selectedPostsCount', 'allPostsSelected'),
canDeleteSelected: function() {
var selectedPosts = this.get('selectedPosts');
const selectedPosts = this.get('selectedPosts');
if (this.get('allPostsSelected')) return true;
if (this.get('selectedPostsCount') === 0) return false;
var canDelete = true;
let canDelete = true;
selectedPosts.forEach(function(p) {
if (!p.get('can_delete')) {
canDelete = false;
@ -520,19 +515,19 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}
}.observes('multiSelect'),
deselectPost: function(post) {
deselectPost(post) {
this.get('selectedPosts').removeObject(post);
var selectedReplies = this.get('selectedReplies');
const selectedReplies = this.get('selectedReplies');
selectedReplies.removeObject(post);
var selectedReply = selectedReplies.findProperty('post_number', post.get('reply_to_post_number'));
const selectedReply = selectedReplies.findProperty('post_number', post.get('reply_to_post_number'));
if (selectedReply) { selectedReplies.removeObject(selectedReply); }
this.set('allPostsSelected', false);
},
postSelected: function(post) {
postSelected(post) {
if (this.get('allPostsSelected')) { return true; }
if (this.get('selectedPosts').contains(post)) { return true; }
if (this.get('selectedReplies').findProperty('post_number', post.get('reply_to_post_number'))) { return true; }
@ -548,11 +543,11 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
return spinnerHTML;
}.property(),
recoverTopic: function() {
recoverTopic() {
this.get('content').recover();
},
deleteTopic: function() {
deleteTopic() {
this.unsubscribe();
this.get('content').destroy(Discourse.User.current());
},
@ -600,8 +595,8 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
});
},
unsubscribe: function() {
var topicId = this.get('content.id');
unsubscribe() {
const topicId = this.get('content.id');
if (!topicId) return;
// there is a condition where the view never calls unsubscribe, navigate to a topic from a topic
@ -609,12 +604,12 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
},
// Topic related
reply: function() {
reply() {
this.replyToPost();
},
performTogglePost: function(post) {
var selectedPosts = this.get('selectedPosts');
performTogglePost(post) {
const selectedPosts = this.get('selectedPosts');
if (this.postSelected(post)) {
this.deselectPost(post);
return false;
@ -631,14 +626,14 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
// If our current post is changed, notify the router
_currentPostChanged: function() {
var currentPost = this.get('currentPost');
const currentPost = this.get('currentPost');
if (currentPost) {
this.send('postChangedRoute', currentPost);
}
}.observes('currentPost'),
readPosts: function(topicId, postNumbers) {
var postStream = this.get('postStream');
readPosts(topicId, postNumbers) {
const postStream = this.get('postStream');
if(this.get('postStream.topic.id') === topicId){
_.each(postStream.get('posts'), function(post){
@ -649,7 +644,7 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
}
});
var max = _.max(postNumbers);
const max = _.max(postNumbers);
if(max > this.get('last_read_post_number')){
this.set('last_read_post_number', max);
}
@ -657,10 +652,10 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
},
// Called the the topmost visible post on the page changes.
topVisibleChanged: function(post) {
topVisibleChanged(post) {
if (!post) { return; }
var postStream = this.get('postStream'),
const postStream = this.get('postStream'),
firstLoadedPost = postStream.get('firstLoadedPost');
this.set('currentPost', post.get('post_number'));
@ -671,16 +666,16 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
// Note: jQuery shouldn't be done in a controller, but how else can we
// trigger a scroll after a promise resolves in a controller? We need
// to do this to preserve upwards infinte scrolling.
var $body = $('body'),
$elem = $('#post-cloak-' + post.get('post_number')),
distToElement = $body.scrollTop() - $elem.position().top;
const $body = $('body');
let $elem = $('#post-cloak-' + post.get('post_number'));
const distToElement = $body.scrollTop() - $elem.position().top;
postStream.prependMore().then(function() {
Em.run.next(function () {
$elem = $('#post-cloak-' + post.get('post_number'));
// Quickly going back might mean the element is destroyed
var position = $elem.position();
const position = $elem.position();
if (position && position.top) {
$('html, body').scrollTop(position.top + distToElement);
}
@ -695,10 +690,10 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon
@method bottomVisibleChanged
@params {Discourse.Post} post that is at the bottom
**/
bottomVisibleChanged: function(post) {
bottomVisibleChanged(post) {
if (!post) { return; }
var postStream = this.get('postStream'),
const postStream = this.get('postStream'),
lastLoadedPost = postStream.get('lastLoadedPost');
this.set('controllers.topic-progress.progressPosition', postStream.progressIndexOfPost(post));

View File

@ -1,32 +1,32 @@
var CLOSED = 'closed',
SAVING = 'saving',
OPEN = 'open',
DRAFT = 'draft',
const CLOSED = 'closed',
SAVING = 'saving',
OPEN = 'open',
DRAFT = 'draft',
// The actions the composer can take
CREATE_TOPIC = 'createTopic',
PRIVATE_MESSAGE = 'privateMessage',
REPLY = 'reply',
EDIT = 'edit',
REPLY_AS_NEW_TOPIC_KEY = "reply_as_new_topic",
// The actions the composer can take
CREATE_TOPIC = 'createTopic',
PRIVATE_MESSAGE = 'privateMessage',
REPLY = 'reply',
EDIT = 'edit',
REPLY_AS_NEW_TOPIC_KEY = "reply_as_new_topic",
// When creating, these fields are moved into the post model from the composer model
_create_serializer = {
raw: 'reply',
title: 'title',
category: 'categoryId',
topic_id: 'topic.id',
is_warning: 'isWarning',
archetype: 'archetypeId',
target_usernames: 'targetUsernames'
},
// When creating, these fields are moved into the post model from the composer model
_create_serializer = {
raw: 'reply',
title: 'title',
category: 'categoryId',
topic_id: 'topic.id',
is_warning: 'isWarning',
archetype: 'archetypeId',
target_usernames: 'targetUsernames'
},
_edit_topic_serializer = {
title: 'topic.title',
categoryId: 'topic.category.id'
};
_edit_topic_serializer = {
title: 'topic.title',
categoryId: 'topic.category.id'
};
Discourse.Composer = Discourse.Model.extend({
const Composer = Discourse.Model.extend({
archetypes: function() {
return Discourse.Site.currentProp('archetypes');
@ -46,7 +46,6 @@ Discourse.Composer = Discourse.Model.extend({
viewOpen: Em.computed.equal('composeState', OPEN),
viewDraft: Em.computed.equal('composeState', DRAFT),
archetype: function() {
return this.get('archetypes').findProperty('id', this.get('archetypeId'));
}.property('archetypeId'),
@ -61,18 +60,18 @@ Discourse.Composer = Discourse.Model.extend({
// Determine the appropriate title for this action
actionTitle: function() {
var topic = this.get('topic');
const topic = this.get('topic');
var postLink, topicLink;
let postLink, topicLink;
if (topic) {
var postNumber = this.get('post.post_number');
const postNumber = this.get('post.post_number');
postLink = "<a href='" + (topic.get('url')) + "/" + postNumber + "'>" +
I18n.t("post.post_number", { number: postNumber }) + "</a>";
topicLink = "<a href='" + (topic.get('url')) + "'> " + (Handlebars.Utils.escapeExpression(topic.get('title'))) + "</a>";
}
var postDescription,
post = this.get('post');
let postDescription;
const post = this.get('post');
if (post) {
postDescription = I18n.t('post.' + this.get('action'), {
@ -82,8 +81,8 @@ Discourse.Composer = Discourse.Model.extend({
});
if (!Discourse.Mobile.mobileView) {
var replyUsername = post.get('reply_to_user.username');
var replyAvatarTemplate = post.get('reply_to_user.avatar_template');
const replyUsername = post.get('reply_to_user.username');
const replyAvatarTemplate = post.get('reply_to_user.avatar_template');
if (replyUsername && replyAvatarTemplate && this.get('action') === EDIT) {
postDescription += " " + I18n.t("post.in_reply_to") + " " + Discourse.Utilities.tinyAvatar(replyAvatarTemplate) + " " + replyUsername;
}
@ -164,7 +163,7 @@ Discourse.Composer = Discourse.Model.extend({
}.property('action'),
hasMetaData: function() {
var metaData = this.get('metaData');
const metaData = this.get('metaData');
return metaData ? Em.isEmpty(Em.keys(this.get('metaData'))) : false;
}.property('metaData'),
@ -227,7 +226,7 @@ Discourse.Composer = Discourse.Model.extend({
@property titleLength
**/
titleLength: function() {
var title = this.get('title') || "";
const title = this.get('title') || "";
return title.replace(/\s+/img, " ").trim().length;
}.property('title'),
@ -237,17 +236,16 @@ Discourse.Composer = Discourse.Model.extend({
@property replyLength
**/
replyLength: function() {
var reply = this.get('reply') || "";
let reply = this.get('reply') || "";
while (Discourse.Quote.REGEXP.test(reply)) { reply = reply.replace(Discourse.Quote.REGEXP, ""); }
return reply.replace(/\s+/img, " ").trim().length;
}.property('reply'),
init: function() {
this._super();
var val = (Discourse.Mobile.mobileView ? false : (Discourse.KeyValueStore.get('composer.showPreview') || 'true'));
_setupComposer: function() {
const val = (Discourse.Mobile.mobileView ? false : (Discourse.KeyValueStore.get('composer.showPreview') || 'true'));
this.set('showPreview', val === 'true');
this.set('archetypeId', Discourse.Site.currentProp('default_archetype'));
},
}.on('init'),
/**
Append text to the current reply
@ -255,17 +253,16 @@ Discourse.Composer = Discourse.Model.extend({
@method appendText
@param {String} text the text to append
**/
appendText: function(text,position,opts) {
var reply = (this.get('reply') || '');
appendText(text,position,opts) {
const reply = (this.get('reply') || '');
position = typeof(position) === "number" ? position : reply.length;
var before = reply.slice(0, position) || '';
var after = reply.slice(position) || '';
let before = reply.slice(0, position) || '';
let after = reply.slice(position) || '';
var stripped, i;
if(opts && opts.block){
if(before.trim() !== ""){
let stripped, i;
if (opts && opts.block){
if (before.trim() !== ""){
stripped = before.replace(/\r/g, "");
for(i=0; i<2; i++){
if(stripped[stripped.length - 1 - i] !== "\n"){
@ -298,7 +295,7 @@ Discourse.Composer = Discourse.Model.extend({
return before.length + text.length;
},
togglePreview: function() {
togglePreview() {
this.toggleProperty('showPreview');
Discourse.KeyValueStore.set({ key: 'composer.showPreview', value: this.get('showPreview') });
},
@ -312,13 +309,13 @@ Discourse.Composer = Discourse.Model.extend({
topic - The topic we're replying to, if present
quote - If we're opening a reply from a quote, the quote we're making
*/
open: function(opts) {
open(opts) {
if (!opts) opts = {};
this.set('loading', false);
var replyBlank = Em.isEmpty(this.get("reply"));
const replyBlank = Em.isEmpty(this.get("reply"));
var composer = this;
const composer = this;
if (!replyBlank &&
(opts.action !== this.get('action') || ((opts.reply || opts.action === this.EDIT) && this.get('reply') !== this.get('originalText'))) &&
!opts.tested) {
@ -363,7 +360,7 @@ Discourse.Composer = Discourse.Model.extend({
// If we are editing a post, load it.
if (opts.action === EDIT && opts.post) {
var topicProps = this.serialize(_edit_topic_serializer);
const topicProps = this.serialize(_edit_topic_serializer);
topicProps.loading = true;
this.setProperties(topicProps);
@ -387,7 +384,7 @@ Discourse.Composer = Discourse.Model.extend({
return false;
},
save: function(opts) {
save(opts) {
if( !this.get('cantSubmitPost') ) {
return this.get('editingPost') ? this.editPost(opts) : this.createPost(opts);
}
@ -398,7 +395,7 @@ Discourse.Composer = Discourse.Model.extend({
@method clearState
**/
clearState: function() {
clearState() {
this.setProperties({
originalText: null,
reply: null,
@ -410,11 +407,11 @@ Discourse.Composer = Discourse.Model.extend({
},
// When you edit a post
editPost: function(opts) {
var post = this.get('post'),
editPost(opts) {
const post = this.get('post'),
oldCooked = post.get('cooked'),
self = this,
promise;
self = this;
let promise;
// Update the title if we've changed it, otherwise consider it a
// successful resolved promise
@ -422,7 +419,7 @@ Discourse.Composer = Discourse.Model.extend({
post.get('post_number') === 1 &&
this.get('topic.details.can_edit')) {
var topicProps = this.getProperties(Object.keys(_edit_topic_serializer));
const topicProps = this.getProperties(Object.keys(_edit_topic_serializer));
promise = Discourse.Topic.update(this.get('topic'), topicProps);
} else {
promise = Ember.RSVP.resolve();
@ -441,7 +438,7 @@ Discourse.Composer = Discourse.Model.extend({
post.updateFromPost(result);
self.clearState();
}).catch(function(error) {
var response = $.parseJSON(error.responseText);
const response = $.parseJSON(error.responseText);
if (response && response.errors) {
return(response.errors[0]);
} else {
@ -453,14 +450,14 @@ Discourse.Composer = Discourse.Model.extend({
});
},
serialize: function(serializer, dest) {
serialize(serializer, dest) {
if (!dest) {
dest = {};
}
var self = this;
const self = this;
Object.keys(serializer).forEach(function(f) {
var val = self.get(serializer[f]);
const val = self.get(serializer[f]);
if (typeof val !== 'undefined') {
Ember.set(dest, f, val);
}
@ -469,15 +466,15 @@ Discourse.Composer = Discourse.Model.extend({
},
// Create a new Post
createPost: function(opts) {
var post = this.get('post'),
createPost(opts) {
const post = this.get('post'),
topic = this.get('topic'),
currentUser = Discourse.User.current(),
postStream = this.get('topic.postStream'),
addedToStream = false;
postStream = this.get('topic.postStream');
let addedToStream = false;
// Build the post object
var createdPost = Discourse.Post.create({
const createdPost = Discourse.Post.create({
imageSizes: opts.imageSizes,
cooked: this.getCookedHtml(),
reply_count: 0,
@ -509,7 +506,7 @@ Discourse.Composer = Discourse.Model.extend({
});
}
var state = null;
let state = null;
// If we're in a topic, we can append the post instantly.
if (postStream) {
@ -533,12 +530,12 @@ Discourse.Composer = Discourse.Model.extend({
}
}
var composer = this;
var promise = new Ember.RSVP.Promise(function(resolve, reject) {
const composer = this;
const promise = new Ember.RSVP.Promise(function(resolve, reject) {
composer.set('composeState', SAVING);
createdPost.save(function(result) {
var saving = true;
let saving = true;
createdPost.updateFromJson(result);
@ -555,7 +552,7 @@ Discourse.Composer = Discourse.Model.extend({
saving = false;
// Update topic_count for the category
var category = Discourse.Site.currentProp('categories').find(function(x) { return x.get('id') === (parseInt(createdPost.get('category'),10) || 1); });
const category = Discourse.Site.currentProp('categories').find(function(x) { return x.get('id') === (parseInt(createdPost.get('category'),10) || 1); });
if (category) category.incrementProperty('topic_count');
Discourse.notifyPropertyChange('globalNotice');
}
@ -578,9 +575,9 @@ Discourse.Composer = Discourse.Model.extend({
composer.set('composeState', OPEN);
// TODO extract error handling code
var parsedError;
let parsedError;
try {
var parsedJSON = $.parseJSON(error.responseText);
const parsedJSON = $.parseJSON(error.responseText);
if (parsedJSON.errors) {
parsedError = parsedJSON.errors[0];
} else if (parsedJSON.failed) {
@ -599,11 +596,11 @@ Discourse.Composer = Discourse.Model.extend({
return promise;
},
getCookedHtml: function() {
getCookedHtml() {
return $('#wmd-preview').html().replace(/<span class="marker"><\/span>/g, '');
},
saveDraft: function() {
saveDraft() {
// Do not save when drafts are disabled
if (this.get('disableDrafts')) return;
// Do not save when there is no reply
@ -611,7 +608,7 @@ Discourse.Composer = Discourse.Model.extend({
// Do not save when the reply's length is too small
if (this.get('replyLength') < Discourse.SiteSettings.min_post_length) return;
var data = {
const data = {
reply: this.get('reply'),
action: this.get('action'),
title: this.get('title'),
@ -624,7 +621,7 @@ Discourse.Composer = Discourse.Model.extend({
this.set('draftStatus', I18n.t('composer.saving_draft_tip'));
var composer = this;
const composer = this;
// try to save the draft
return Discourse.Draft.save(this.get('draftKey'), this.get('draftSequence'), data)
@ -637,16 +634,21 @@ Discourse.Composer = Discourse.Model.extend({
});
Discourse.Composer.reopenClass({
Composer.reopenClass({
open: function(opts) {
var composer = Discourse.Composer.create();
open(opts) {
const composer = Composer.create();
composer.open(opts);
return composer;
},
loadDraft: function(draftKey, draftSequence, draft, topic) {
var composer;
loadDraft(opts) {
opts = opts || {};
let draft = opts.draft;
const draftKey = opts.draftKey;
const draftSequence = opts.draftSequence;
try {
if (draft && typeof draft === 'string') {
draft = JSON.parse(draft);
@ -656,13 +658,12 @@ Discourse.Composer.reopenClass({
Discourse.Draft.clear(draftKey, draftSequence);
}
if (draft && ((draft.title && draft.title !== '') || (draft.reply && draft.reply !== ''))) {
composer = this.open({
draftKey: draftKey,
draftSequence: draftSequence,
topic: topic,
return this.open({
draftKey,
draftSequence,
action: draft.action,
title: draft.title,
categoryId: draft.categoryId,
categoryId: draft.categoryId || opts.categoryId,
postId: draft.postId,
archetypeId: draft.archetypeId,
reply: draft.reply,
@ -672,35 +673,36 @@ Discourse.Composer.reopenClass({
composerState: DRAFT
});
}
return composer;
},
serializeToTopic: function(fieldName, property) {
serializeToTopic(fieldName, property) {
if (!property) { property = fieldName; }
_edit_topic_serializer[fieldName] = property;
},
serializeOnCreate: function(fieldName, property) {
serializeOnCreate(fieldName, property) {
if (!property) { property = fieldName; }
_create_serializer[fieldName] = property;
},
serializedFieldsForCreate: function() {
serializedFieldsForCreate() {
return Object.keys(_create_serializer);
},
// The status the compose view can have
CLOSED: CLOSED,
SAVING: SAVING,
OPEN: OPEN,
DRAFT: DRAFT,
CLOSED,
SAVING,
OPEN,
DRAFT,
// The actions the composer can take
CREATE_TOPIC: CREATE_TOPIC,
PRIVATE_MESSAGE: PRIVATE_MESSAGE,
REPLY: REPLY,
EDIT: EDIT,
CREATE_TOPIC,
PRIVATE_MESSAGE,
REPLY,
EDIT,
// Draft key
REPLY_AS_NEW_TOPIC_KEY: REPLY_AS_NEW_TOPIC_KEY
REPLY_AS_NEW_TOPIC_KEY
});
export default Composer;