diff --git a/app/assets/javascripts/discourse/controllers/topic_controller.js b/app/assets/javascripts/discourse/controllers/topic_controller.js
index e77a672d6..1ea8ffabc 100644
--- a/app/assets/javascripts/discourse/controllers/topic_controller.js
+++ b/app/assets/javascripts/discourse/controllers/topic_controller.js
@@ -49,6 +49,122 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
},
actions: {
+ // Post related methods
+ replyToPost: function(post) {
+ var 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');
+
+ quoteController.set('buffer', '');
+
+ if (composerController.get('content.topic.id') === topic.get('id') &&
+ composerController.get('content.action') === Discourse.Composer.REPLY) {
+ composerController.set('content.post', post);
+ composerController.set('content.composeState', Discourse.Composer.OPEN);
+ composerController.appendText(quotedText);
+ } else {
+
+ var opts = {
+ action: Discourse.Composer.REPLY,
+ draftKey: topic.get('draft_key'),
+ draftSequence: topic.get('draft_sequence')
+ };
+
+ if(post && post.get("post_number") !== 1){
+ opts.post = post;
+ } else {
+ opts.topic = topic;
+ }
+
+ composerController.open(opts).then(function() {
+ composerController.appendText(quotedText);
+ });
+ }
+ return false;
+ },
+
+ likePost: function(post) {
+ var likeAction = post.get('actionByName.like');
+ if (likeAction && likeAction.get('can_act')) {
+ likeAction.act();
+ }
+ },
+
+ recoverPost: function(post) {
+ // Recovering the first post recovers the topic instead
+ if (post.get('post_number') === 1) {
+ this.recoverTopic();
+ return;
+ }
+ post.recover();
+ },
+
+ deletePost: function(post) {
+
+ // Deleting the first post deletes the topic
+ if (post.get('post_number') === 1) {
+ this.deleteTopic();
+ return;
+ }
+
+ var user = Discourse.User.current(),
+ replyCount = post.get('reply_count'),
+ self = this;
+
+ // If the user is staff and the post has replies, ask if they want to delete replies too.
+ if (user.get('staff') && replyCount > 0) {
+ bootbox.dialog(I18n.t("post.controls.delete_replies.confirm", {count: replyCount}), [
+ {label: I18n.t("cancel"),
+ 'class': 'btn-danger rightg'},
+ {label: I18n.t("post.controls.delete_replies.no_value"),
+ callback: function() {
+ post.destroy(user);
+ }
+ },
+ {label: I18n.t("post.controls.delete_replies.yes_value"),
+ 'class': 'btn-primary',
+ callback: function() {
+ 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')) {
+ p.setDeletedState(user);
+ }
+ });
+ }
+ }
+ ]);
+ } else {
+ post.destroy(user).then(null, function(e) {
+ post.undoDeleteState();
+ var response = $.parseJSON(e.responseText);
+ if (response && response.errors) {
+ bootbox.alert(response.errors[0]);
+ } else {
+ bootbox.alert(I18n.t('generic_error'));
+ }
+ });
+ }
+ },
+
+ editPost: function(post) {
+ this.get('controllers.composer').open({
+ post: post,
+ action: Discourse.Composer.EDIT,
+ draftKey: post.get('topic.draft_key'),
+ draftSequence: post.get('topic.draft_sequence')
+ });
+ },
+
+ toggleBookmark: function(post) {
+ if (!Discourse.User.current()) {
+ alert(I18n.t("bookmarks.not_bookmarked"));
+ return;
+ }
+ post.toggleProperty('bookmarked');
+ return false;
+ },
+
jumpTop: function() {
Discourse.URL.routeTo(this.get('firstPostUrl'));
},
@@ -453,109 +569,11 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
Discourse.MessageBus.unsubscribe('/topic/*');
},
- // Post related methods
- replyToPost: function(post) {
- var 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');
-
- quoteController.set('buffer', '');
-
- if (composerController.get('content.topic.id') === topic.get('id') &&
- composerController.get('content.action') === Discourse.Composer.REPLY) {
- composerController.set('content.post', post);
- composerController.set('content.composeState', Discourse.Composer.OPEN);
- composerController.appendText(quotedText);
- } else {
-
- var opts = {
- action: Discourse.Composer.REPLY,
- draftKey: topic.get('draft_key'),
- draftSequence: topic.get('draft_sequence')
- };
-
- if(post && post.get("post_number") !== 1){
- opts.post = post;
- } else {
- opts.topic = topic;
- }
-
- composerController.open(opts).then(function() {
- composerController.appendText(quotedText);
- });
- }
- return false;
- },
-
// Topic related
reply: function() {
this.replyToPost();
},
- // Edits a post
- editPost: function(post) {
- this.get('controllers.composer').open({
- post: post,
- action: Discourse.Composer.EDIT,
- draftKey: post.get('topic.draft_key'),
- draftSequence: post.get('topic.draft_sequence')
- });
- },
-
- toggleBookmark: function(post) {
- if (!Discourse.User.current()) {
- alert(I18n.t("bookmarks.not_bookmarked"));
- return;
- }
- post.toggleProperty('bookmarked');
- return false;
- },
-
- recoverPost: function(post) {
- post.recover();
- },
-
- deletePost: function(post) {
- var user = Discourse.User.current(),
- replyCount = post.get('reply_count'),
- self = this;
-
- // If the user is staff and the post has replies, ask if they want to delete replies too.
- if (user.get('staff') && replyCount > 0) {
- bootbox.dialog(I18n.t("post.controls.delete_replies.confirm", {count: replyCount}), [
- {label: I18n.t("cancel"),
- 'class': 'btn-danger rightg'},
- {label: I18n.t("post.controls.delete_replies.no_value"),
- callback: function() {
- post.destroy(user);
- }
- },
- {label: I18n.t("post.controls.delete_replies.yes_value"),
- 'class': 'btn-primary',
- callback: function() {
- 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')) {
- p.setDeletedState(user);
- }
- });
- }
- }
- ]);
- } else {
- post.destroy(user).then(null, function(e) {
- post.undoDeleteState();
- var response = $.parseJSON(e.responseText);
- if (response && response.errors) {
- bootbox.alert(response.errors[0]);
- } else {
- bootbox.alert(I18n.t('generic_error'));
- }
- });
- }
- },
-
performTogglePost: function(post) {
var selectedPosts = this.get('selectedPosts');
if (this.postSelected(post)) {
diff --git a/app/assets/javascripts/discourse/initializers/keyboard-shortcuts.js.es6 b/app/assets/javascripts/discourse/initializers/keyboard-shortcuts.js.es6
index 7cc8e63d2..5ae89cdf2 100644
--- a/app/assets/javascripts/discourse/initializers/keyboard-shortcuts.js.es6
+++ b/app/assets/javascripts/discourse/initializers/keyboard-shortcuts.js.es6
@@ -5,7 +5,7 @@
**/
export default {
name: "keyboard-shortcuts",
- initialize: function() {
- Discourse.KeyboardShortcuts.bindEvents(Mousetrap);
+ initialize: function(container) {
+ Discourse.KeyboardShortcuts.bindEvents(Mousetrap, container);
}
};
diff --git a/app/assets/javascripts/discourse/lib/keyboard_shortcuts.js b/app/assets/javascripts/discourse/lib/keyboard_shortcuts.js
index 967220976..e1f1af80c 100644
--- a/app/assets/javascripts/discourse/lib/keyboard_shortcuts.js
+++ b/app/assets/javascripts/discourse/lib/keyboard_shortcuts.js
@@ -16,27 +16,30 @@ Discourse.KeyboardShortcuts = Ember.Object.createWithMixins({
'g t': '/top'
},
+ SELECTED_POST_BINDINGS: {
+ 'b': 'toggleBookmark',
+ 'd': 'deletePost',
+ 'e': 'editPost',
+ 'l': 'likePost',
+ 'r': 'replyToPost',
+ '!': 'showFlags'
+ },
+
CLICK_BINDINGS: {
- 'b': '.topic-post.selected button.bookmark', // bookmark current post
'c': '#create-topic', // create new topic
- 'd': '.topic-post.selected button.delete', // delete selected post
- 'e': '.topic-post.selected button.edit', // edit selected post
// star topic
'f': '#topic-footer-buttons button.star, #topic-list tr.topic-list-item.selected a.star',
- 'l': '.topic-post.selected button.like', // like selected post
'm m': 'div.notification-options li[data-id="0"] a', // mark topic as muted
'm r': 'div.notification-options li[data-id="1"] a', // mark topic as regular
'm t': 'div.notification-options li[data-id="2"] a', // mark topic as tracking
'm w': 'div.notification-options li[data-id="3"] a', // mark topic as watching
'n': '#user-notifications', // open notifictions menu
- 'o,enter': '#topic-list tr.selected a.title', // open selected topic
- 'shift+r': '#topic-footer-buttons button.create', // reply to topic
- 'r': '.topic-post.selected button.create', // reply to selected post
- 'shift+s': '#topic-footer-buttons button.share', // share topic
- 's': '.topic-post.selected button.share', // share selected post
- '!': '.topic-post.selected button.flag' // flag selected post
+ 'o,enter': '#topic-list tr.selected a.title', // open selected topic
+ 'shift+r': '#topic-footer-buttons button.create', // reply to topic
+ 'shift+s': '#topic-footer-buttons button.share', // share topic
+ 's': '.topic-post.selected a.post-date' // share post
},
FUNCTION_BINDINGS: {
@@ -54,10 +57,12 @@ Discourse.KeyboardShortcuts = Ember.Object.createWithMixins({
'q': 'quoteReply'
},
- bindEvents: function(keyTrapper) {
+ bindEvents: function(keyTrapper, container) {
this.keyTrapper = keyTrapper;
+ this.container = container;
_.each(this.PATH_BINDINGS, this._bindToPath, this);
_.each(this.CLICK_BINDINGS, this._bindToClick, this);
+ _.each(this.SELECTED_POST_BINDINGS, this._bindToSelectedPost, this);
_.each(this.FUNCTION_BINDINGS, this._bindToFunction, this);
},
@@ -79,7 +84,7 @@ Discourse.KeyboardShortcuts = Ember.Object.createWithMixins({
_jumpTo: function(direction) {
if ($('.container.posts').length) {
- Discourse.__container__.lookup('controller:topic').send(direction);
+ this.container.lookup('controller:topic').send(direction);
}
},
@@ -136,6 +141,22 @@ Discourse.KeyboardShortcuts = Ember.Object.createWithMixins({
Discourse.__container__.lookup('controller:application').send('showKeyboardShortcutsHelp');
},
+ _bindToSelectedPost: function(action, binding) {
+ var container = this.container;
+
+ this.keyTrapper.bind(binding, function() {
+ // TODO: We should keep track of the post without a CSS class
+ var selectedPostId = parseInt($('.topic-post.selected article.boxed').data('post-id'), 10);
+ if (selectedPostId) {
+ var topicController = container.lookup('controller:topic'),
+ post = topicController.get('postStream.posts').findBy('id', selectedPostId);
+ if (post) {
+ topicController.send(action, post);
+ }
+ }
+ });
+ },
+
_bindToPath: function(path, binding) {
this.keyTrapper.bind(binding, function() {
Discourse.URL.routeTo(path);
diff --git a/app/assets/javascripts/discourse/views/post-menu.js.es6 b/app/assets/javascripts/discourse/views/post-menu.js.es6
index f6f97046c..5a583cf52 100644
--- a/app/assets/javascripts/discourse/views/post-menu.js.es6
+++ b/app/assets/javascripts/discourse/views/post-menu.js.es6
@@ -73,7 +73,7 @@ export default Discourse.View.extend({
var handler = this["click" + action.capitalize()];
if (!handler) return;
- handler.call(this);
+ handler.call(this, this.get('post'));
},
// Replies Button
@@ -109,7 +109,7 @@ export default Discourse.View.extend({
// Delete button
renderDelete: function(post, buffer) {
- var label, action, icon;
+ var label, icon;
if (post.get('post_number') === 1) {
// If it's the first post, the delete/undo actions are related to the topic
@@ -117,12 +117,10 @@ export default Discourse.View.extend({
if (topic.get('deleted_at')) {
if (!topic.get('details.can_recover')) { return; }
label = "topic.actions.recover";
- action = "recoverTopic";
icon = "undo";
} else {
if (!topic.get('details.can_delete')) { return; }
label = "topic.actions.delete";
- action = "deleteTopic";
icon = "trash-o";
}
@@ -131,35 +129,26 @@ export default Discourse.View.extend({
if (post.get('deleted_at') || post.get('user_deleted')) {
if (!post.get('can_recover')) { return; }
label = "post.controls.undelete";
- action = "recover";
icon = "undo";
} else {
if (!post.get('can_delete')) { return; }
label = "post.controls.delete";
- action = "delete";
icon = "trash-o";
}
}
+ var action = (icon === 'trash-o') ? 'delete' : 'recover';
buffer.push("");
},
- clickDeleteTopic: function() {
- this.get('controller').deleteTopic();
+ clickRecover: function(post) {
+ this.get('controller').send('recoverPost', post);
},
- clickRecoverTopic: function() {
- this.get('controller').recoverTopic();
- },
-
- clickRecover: function() {
- this.get('controller').recoverPost(this.get('post'));
- },
-
- clickDelete: function() {
- this.get('controller').deletePost(this.get('post'));
+ clickDelete: function(post) {
+ this.get('controller').send('deletePost', post);
},
// Like button
@@ -170,9 +159,8 @@ export default Discourse.View.extend({
"\" data-action=\"like\" class='like'>");
},
- clickLike: function() {
- var likeAction = this.get('post.actionByName.like');
- if (likeAction) likeAction.act();
+ clickLike: function(post) {
+ this.get('controller').send('likePost', post);
},
// Flag button
@@ -183,8 +171,8 @@ export default Discourse.View.extend({
"\" data-action=\"flag\" class='flag'>");
},
- clickFlag: function() {
- this.get('controller').send('showFlags', this.get('post'));
+ clickFlag: function(post) {
+ this.get('controller').send('showFlags', post);
},
// Edit button
@@ -195,8 +183,8 @@ export default Discourse.View.extend({
"\" data-action=\"edit\" class='edit'>");
},
- clickEdit: function() {
- this.get('controller').editPost(this.get('post'));
+ clickEdit: function(post) {
+ this.get('controller').send('editPost', post);
},
// Share button
@@ -216,8 +204,8 @@ export default Discourse.View.extend({
(I18n.t("topic.reply.title")) + "");
},
- clickReply: function() {
- this.get('controller').replyToPost(this.get('post'));
+ clickReply: function(post) {
+ this.get('controller').send('replyToPost', post);
},
// Bookmark button
@@ -242,8 +230,8 @@ export default Discourse.View.extend({
"'>");
},
- clickBookmark: function() {
- this.get('post').toggleProperty('bookmarked');
+ clickBookmark: function(post) {
+ this.get('controller').send('toggleBookmark', post);
},
renderAdmin: function(post, buffer) {
diff --git a/test/javascripts/components/keyboard_shortcuts_component_test.js b/test/javascripts/components/keyboard_shortcuts_component_test.js
index 5d9efbbdb..da84e5883 100644
--- a/test/javascripts/components/keyboard_shortcuts_component_test.js
+++ b/test/javascripts/components/keyboard_shortcuts_component_test.js
@@ -25,13 +25,7 @@ module("Discourse.KeyboardShortcuts", {
$("#qunit-fixture").html([
"