mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 23:58:31 -05:00
REFACTOR: Keyboard Shortcuts should send their actions directly to
posts, not by activating clicks on buttons.
This commit is contained in:
parent
c1179014fc
commit
176120cbc1
5 changed files with 169 additions and 148 deletions
|
@ -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)) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
**/
|
||||
export default {
|
||||
name: "keyboard-shortcuts",
|
||||
initialize: function() {
|
||||
Discourse.KeyboardShortcuts.bindEvents(Mousetrap);
|
||||
initialize: function(container) {
|
||||
Discourse.KeyboardShortcuts.bindEvents(Mousetrap, container);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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("<button title=\"" +
|
||||
I18n.t(label) +
|
||||
"\" data-action=\"" + action + "\" class=\"delete\"><i class=\"fa fa-" + icon + "\"></i></button>");
|
||||
},
|
||||
|
||||
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'><i class=\"fa fa-heart\"></i></button>");
|
||||
},
|
||||
|
||||
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'><i class=\"fa fa-flag\"></i></button>");
|
||||
},
|
||||
|
||||
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'><i class=\"fa fa-pencil\"></i></button>");
|
||||
},
|
||||
|
||||
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")) + "</span></button>");
|
||||
},
|
||||
|
||||
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({
|
|||
"'></div></button>");
|
||||
},
|
||||
|
||||
clickBookmark: function() {
|
||||
this.get('post').toggleProperty('bookmarked');
|
||||
clickBookmark: function(post) {
|
||||
this.get('controller').send('toggleBookmark', post);
|
||||
},
|
||||
|
||||
renderAdmin: function(post, buffer) {
|
||||
|
|
|
@ -25,13 +25,7 @@ module("Discourse.KeyboardShortcuts", {
|
|||
|
||||
$("#qunit-fixture").html([
|
||||
"<article class='topic-post selected'>",
|
||||
" <button class='bookmark'></button>",
|
||||
" <button class='delete'></button>",
|
||||
" <button class='edit'></button>",
|
||||
" <button class='like'></button>",
|
||||
" <button class='create'></button>",
|
||||
" <button class='share'></button>",
|
||||
" <button class='flag'></button>",
|
||||
"<a class='post-date'></a>" +
|
||||
"</article>",
|
||||
"<div class='notification-options'>",
|
||||
" <ul>",
|
||||
|
|
Loading…
Reference in a new issue