FEATURE: improves composer-actions toggle menu
* only toggles * fix a bug with presence * more tests * do not duplicate `continuing discussion...` text * persist state to allow switching between toggles
This commit is contained in:
parent
3b06e5502b
commit
190d208631
|
@ -8,4 +8,6 @@
|
|||
action=model.action}}
|
||||
{{/if}}
|
||||
|
||||
{{actionTitle}}
|
||||
<span class="action-title">
|
||||
{{actionTitle}}
|
||||
</span>
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
|
||||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||
import { default as Composer, REPLY, EDIT } from "discourse/models/composer";
|
||||
import { default as Composer, PRIVATE_MESSAGE, CREATE_TOPIC, REPLY, EDIT } from "discourse/models/composer";
|
||||
|
||||
// Component can get destroyed and lose state
|
||||
let _topicSnapshot = null;
|
||||
let _postSnapshot = null;
|
||||
|
||||
export function _clearSnapshots() {
|
||||
_topicSnapshot = null;
|
||||
_postSnapshot = null;
|
||||
}
|
||||
|
||||
export default DropdownSelectBoxComponent.extend({
|
||||
composerController: Ember.inject.controller("composer"),
|
||||
|
@ -13,10 +22,27 @@ export default DropdownSelectBoxComponent.extend({
|
|||
allowAutoSelectFirst: false,
|
||||
showFullTitle: false,
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super();
|
||||
|
||||
// if we change topic we want to change both snapshots
|
||||
if (this.get("composerModel.topic") && (!_topicSnapshot || this.get("composerModel.topic.id") !== _topicSnapshot.get("id"))) {
|
||||
_topicSnapshot = this.get("composerModel.topic");
|
||||
_postSnapshot = this.get("composerModel.post");
|
||||
}
|
||||
|
||||
// if we hit reply on a different post we want to change postSnapshot
|
||||
if (this.get("composerModel.post") && (!_postSnapshot || this.get("composerModel.post.id") !== _postSnapshot.get("id"))) {
|
||||
_postSnapshot = this.get("composerModel.post");
|
||||
}
|
||||
},
|
||||
|
||||
computeHeaderContent() {
|
||||
let content = this.baseHeaderComputedContent();
|
||||
|
||||
switch (this.get("action")) {
|
||||
case PRIVATE_MESSAGE:
|
||||
case CREATE_TOPIC:
|
||||
case REPLY:
|
||||
content.icon = "mail-forward";
|
||||
break;
|
||||
|
@ -28,18 +54,32 @@ export default DropdownSelectBoxComponent.extend({
|
|||
return content;
|
||||
},
|
||||
|
||||
@computed("options", "canWhisper", "composerModel.post.username")
|
||||
content(options, canWhisper, postUsername) {
|
||||
let items = [
|
||||
{
|
||||
@computed("options", "canWhisper", "action")
|
||||
content(options, canWhisper, action) {
|
||||
let items = [];
|
||||
|
||||
if (action !== CREATE_TOPIC) {
|
||||
items.push({
|
||||
name: I18n.t("composer.composer_actions.reply_as_new_topic.label"),
|
||||
description: I18n.t("composer.composer_actions.reply_as_new_topic.desc"),
|
||||
icon: "plus",
|
||||
id: "reply_as_new_topic"
|
||||
}
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
if (postUsername && postUsername !== this.currentUser.get("username")) {
|
||||
if ((action !== REPLY && _postSnapshot) || (action === REPLY && _postSnapshot && !(options.userAvatar && options.userLink))) {
|
||||
items.push({
|
||||
name: I18n.t("composer.composer_actions.reply_to_post.label", {
|
||||
postNumber: _postSnapshot.get("post_number"),
|
||||
postUsername: _postSnapshot.get("username")
|
||||
}),
|
||||
description: I18n.t("composer.composer_actions.reply_to_post.desc"),
|
||||
icon: "mail-forward",
|
||||
id: "reply_to_post"
|
||||
});
|
||||
}
|
||||
|
||||
if (action !== PRIVATE_MESSAGE) {
|
||||
items.push({
|
||||
name: I18n.t("composer.composer_actions.reply_as_private_message.label"),
|
||||
description: I18n.t("composer.composer_actions.reply_as_private_message.desc"),
|
||||
|
@ -48,7 +88,7 @@ export default DropdownSelectBoxComponent.extend({
|
|||
});
|
||||
}
|
||||
|
||||
if (Ember.get(options, "postLink")) {
|
||||
if ((action !== REPLY && _topicSnapshot) || (action === REPLY && _topicSnapshot && (options.userAvatar && options.userLink && options.topicLink))) {
|
||||
items.push({
|
||||
name: I18n.t("composer.composer_actions.reply_to_topic.label"),
|
||||
description: I18n.t("composer.composer_actions.reply_to_topic.desc"),
|
||||
|
@ -57,7 +97,8 @@ export default DropdownSelectBoxComponent.extend({
|
|||
});
|
||||
}
|
||||
|
||||
if (canWhisper) {
|
||||
// if answered post is a whisper, we can only answer with a whisper so no need for toggle
|
||||
if (canWhisper && (_postSnapshot && _postSnapshot.post_type !== this.site.post_types.whisper)) {
|
||||
items.push({
|
||||
name: I18n.t("composer.composer_actions.toggle_whisper.label"),
|
||||
description: I18n.t("composer.composer_actions.toggle_whisper.desc"),
|
||||
|
@ -69,46 +110,85 @@ export default DropdownSelectBoxComponent.extend({
|
|||
return items;
|
||||
},
|
||||
|
||||
_replyFromExisting(options) {
|
||||
const topicTitle = this.get("composerModel.topic.title");
|
||||
let url = this.get("composerModel.post.url") || this.get("composerModel.topic.url");
|
||||
_replyFromExisting(options, post, topic) {
|
||||
const reply = this.get("composerModel.reply");
|
||||
|
||||
let url;
|
||||
if (post) url = post.get("url");
|
||||
if (!post && topic) url = topic.get("url");
|
||||
|
||||
let topicTitle;
|
||||
if (topic) topicTitle = topic.get("title");
|
||||
|
||||
this.get("composerController").close();
|
||||
this.get("composerController").open(options).then(() => {
|
||||
if (!url || ! topicTitle) return;
|
||||
|
||||
url = `${location.protocol}//${location.host}${url}`;
|
||||
const link = `[${Handlebars.escapeExpression(topicTitle)}](${url})`;
|
||||
this.get("composerController").get("model").prependText(`${I18n.t("post.continue_discussion", { postLink: link })}`, {new_line: true});
|
||||
const continueDiscussion = I18n.t("post.continue_discussion", { postLink: link });
|
||||
|
||||
if (!reply.includes(continueDiscussion)) {
|
||||
this.get("composerController")
|
||||
.get("model")
|
||||
.prependText(continueDiscussion, {new_line: true});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
onSelect(value) {
|
||||
let options = {
|
||||
draftKey: this.get("composerModel.draftKey"),
|
||||
draftSequence: this.get("composerModel.draftSequence"),
|
||||
reply: this.get("composerModel.reply")
|
||||
};
|
||||
|
||||
switch(value) {
|
||||
case "toggle_whisper":
|
||||
this.set("composerModel.whisper", !this.get("composerModel.whisper"));
|
||||
break;
|
||||
|
||||
case "reply_to_post":
|
||||
options.action = Composer.REPLY;
|
||||
options.post = _postSnapshot;
|
||||
|
||||
this.get("composerController").close();
|
||||
this.get("composerController").open(options);
|
||||
break;
|
||||
|
||||
case "reply_to_topic":
|
||||
this.set("composerModel.post", null);
|
||||
this.get("composerController").save();
|
||||
options.action = Composer.REPLY;
|
||||
options.topic = _topicSnapshot;
|
||||
|
||||
this.get("composerController").close();
|
||||
this.get("composerController").open(options);
|
||||
break;
|
||||
|
||||
case "reply_as_new_topic":
|
||||
const replyAsNewTopicOpts = {
|
||||
action: Composer.CREATE_TOPIC,
|
||||
draftKey: Composer.REPLY_AS_NEW_TOPIC_KEY,
|
||||
categoryId: this.get("composerModel.topic.category.id")
|
||||
};
|
||||
this._replyFromExisting(replyAsNewTopicOpts);
|
||||
options.action = Composer.CREATE_TOPIC;
|
||||
options.categoryId = this.get("composerModel.topic.category.id");
|
||||
|
||||
this.get("composerController").close();
|
||||
this.get("composerController").open(options);
|
||||
break;
|
||||
|
||||
case "reply_as_private_message":
|
||||
const replyAsPrivateMsgOpts = {
|
||||
action: Composer.PRIVATE_MESSAGE,
|
||||
archetypeId: "private_message",
|
||||
draftKey: Composer.REPLY_AS_NEW_PRIVATE_MESSAGE_KEY,
|
||||
usernames: this.get("composerModel.post.username")
|
||||
};
|
||||
this._replyFromExisting(replyAsPrivateMsgOpts);
|
||||
let usernames;
|
||||
|
||||
if (_postSnapshot && !_postSnapshot.get("yours")) {
|
||||
const postUsername = _postSnapshot.get("username");
|
||||
if (postUsername) {
|
||||
usernames = postUsername;
|
||||
}
|
||||
}
|
||||
|
||||
options.action = Composer.PRIVATE_MESSAGE;
|
||||
options.usernames = usernames;
|
||||
options.archetypeId = "private_message";
|
||||
options.draftKey = Composer.NEW_PRIVATE_MESSAGE_KEY;
|
||||
|
||||
this._replyFromExisting(options, _postSnapshot, _topicSnapshot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1292,6 +1292,9 @@ en:
|
|||
admin_options_title: "Optional staff settings for this topic"
|
||||
|
||||
composer_actions:
|
||||
reply_to_post:
|
||||
label: Reply to post %{postNumber} by %{postUsername}
|
||||
desc: Reply to a specific post
|
||||
reply_as_new_topic:
|
||||
label: Reply as linked topic
|
||||
desc: Create a new topic
|
||||
|
|
|
@ -68,6 +68,10 @@ export default Ember.Component.extend({
|
|||
|
||||
this.clear();
|
||||
|
||||
if (this.get('action') !== 'reply' || this.get('action') !== 'edit') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.publish({
|
||||
response_needed: true,
|
||||
previous: this.get('previousState'),
|
||||
|
|
|
@ -20,6 +20,7 @@ QUnit.test('replying to post', assert => {
|
|||
assert.equal(composerActions.rowByIndex(1).value(), 'reply_as_private_message');
|
||||
assert.equal(composerActions.rowByIndex(2).value(), 'reply_to_topic');
|
||||
assert.equal(composerActions.rowByIndex(3).value(), 'toggle_whisper');
|
||||
assert.equal(composerActions.rowByIndex(4).value(), undefined);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -42,12 +43,13 @@ QUnit.test('replying to post - reply_to_topic', assert => {
|
|||
|
||||
visit('/t/internationalization-localization/280');
|
||||
click('article#post_3 button.reply');
|
||||
fillIn('.d-editor-input', 'test replying to topic when intially replied to post');
|
||||
fillIn('.d-editor-input', 'test replying to topic when initially replied to post');
|
||||
composerActions.expand().selectRowByValue('reply_to_topic');
|
||||
|
||||
andThen(() => {
|
||||
assert.equal(find('.topic-post:last .cooked p').html().trim(), 'test replying to topic when intially replied to post');
|
||||
assert.notOk(exists(find('.topic-post:last .reply-to-tab')));
|
||||
assert.equal(find('.action-title .topic-link').text().trim(), 'Internationalization / localization');
|
||||
assert.equal(find('.action-title .topic-link').attr("href"), '/t/internationalization-localization/280');
|
||||
assert.equal(find('.d-editor-input').val(), 'test replying to topic when initially replied to post');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -56,7 +58,7 @@ QUnit.test('replying to post - toggle_whisper', assert => {
|
|||
|
||||
visit('/t/internationalization-localization/280');
|
||||
click('article#post_3 button.reply');
|
||||
fillIn('.d-editor-input', 'test replying as whisper to topic when intially not a whisper');
|
||||
fillIn('.d-editor-input', 'test replying as whisper to topic when initially not a whisper');
|
||||
composerActions.expand().selectRowByValue('toggle_whisper');
|
||||
|
||||
andThen(() => {
|
||||
|
@ -78,10 +80,73 @@ QUnit.test('replying to post - reply_as_new_topic', assert => {
|
|||
click('#topic-title .submit-edit');
|
||||
|
||||
click('article#post_3 button.reply');
|
||||
fillIn('.d-editor-input', 'test replying as new topic when initially replied to post');
|
||||
composerActions.expand().selectRowByValue('reply_as_new_topic');
|
||||
|
||||
andThen(() => {
|
||||
assert.equal(categoryChooserReplyArea.header().name(), 'faq');
|
||||
assert.ok(find('.d-editor-input').val().indexOf('Continuing the discussion') >= 0);
|
||||
assert.equal(find('.action-title').text().trim(), I18n.t("topic.create_long"));
|
||||
assert.equal(find('.d-editor-input').val(), 'test replying as new topic when initially replied to post');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('interactions', assert => {
|
||||
const composerActions = selectKit('.composer-actions');
|
||||
const quote = 'Life is like riding a bicycle.';
|
||||
|
||||
visit('/t/internationalization-localization/280');
|
||||
click('article#post_3 button.reply');
|
||||
fillIn('.d-editor-input', quote);
|
||||
composerActions.expand().selectRowByValue('reply_to_topic');
|
||||
|
||||
andThen(() => {
|
||||
assert.equal(find('.action-title').text().trim(), "Internationalization / localization");
|
||||
assert.equal(find('.d-editor-input').val(), quote);
|
||||
});
|
||||
|
||||
composerActions.expand();
|
||||
|
||||
andThen(() => {
|
||||
assert.equal(composerActions.rowByIndex(0).value(), 'reply_as_new_topic');
|
||||
assert.equal(composerActions.rowByIndex(1).value(), 'reply_to_post');
|
||||
assert.equal(composerActions.rowByIndex(2).value(), 'reply_as_private_message');
|
||||
assert.equal(composerActions.rowByIndex(3).value(), 'toggle_whisper');
|
||||
assert.equal(composerActions.rowByIndex(4).value(), undefined);
|
||||
});
|
||||
|
||||
composerActions.selectRowByValue('reply_to_post').expand();
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(exists(find('.action-title img.avatar')));
|
||||
assert.equal(find('.action-title .user-link').text().trim(), "codinghorror");
|
||||
assert.equal(find('.d-editor-input').val(), quote);
|
||||
assert.equal(composerActions.rowByIndex(0).value(), 'reply_as_new_topic');
|
||||
assert.equal(composerActions.rowByIndex(1).value(), 'reply_as_private_message');
|
||||
assert.equal(composerActions.rowByIndex(2).value(), 'reply_to_topic');
|
||||
assert.equal(composerActions.rowByIndex(3).value(), 'toggle_whisper');
|
||||
assert.equal(composerActions.rowByIndex(4).value(), undefined);
|
||||
});
|
||||
|
||||
composerActions.selectRowByValue('reply_as_new_topic').expand();
|
||||
|
||||
andThen(() => {
|
||||
assert.equal(find('.action-title').text().trim(), I18n.t("topic.create_long"));
|
||||
assert.equal(find('.d-editor-input').val(), quote);
|
||||
assert.equal(composerActions.rowByIndex(0).value(), 'reply_to_post');
|
||||
assert.equal(composerActions.rowByIndex(1).value(), 'reply_as_private_message');
|
||||
assert.equal(composerActions.rowByIndex(2).value(), 'reply_to_topic');
|
||||
assert.equal(composerActions.rowByIndex(3).value(), undefined);
|
||||
});
|
||||
|
||||
composerActions.selectRowByValue('reply_as_private_message').expand();
|
||||
|
||||
andThen(() => {
|
||||
assert.equal(find('.action-title').text().trim(), I18n.t("topic.private_message"));
|
||||
assert.ok(find('.d-editor-input').val().indexOf("Continuing the discussion") === 0);
|
||||
assert.equal(composerActions.rowByIndex(0).value(), 'reply_as_new_topic');
|
||||
assert.equal(composerActions.rowByIndex(1).value(), 'reply_to_post');
|
||||
assert.equal(composerActions.rowByIndex(2).value(), 'reply_to_topic');
|
||||
assert.equal(composerActions.rowByIndex(3).value(), undefined);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue