Add Global Keyboard Shortcuts
Not all of these have been fully implemented yet. **Jump To** * `g` then `h` - Home (Latest) * `g` then `l` - Latest * `g` then `n` - New * `g` then `u` - Unread * `g` then `f` - Favorited * `g` then `c` - Categories List **Navigation** * `u` - Back to topic list * `k` / `j` - Newer/Older conversation or post * `o` or `Enter` - Open selected conversation * <code>`</code> - Go to next section * `~` - Go to previous section **Application** * `c` - Create a new topic * `n` - Open notifications menu * `/` - Search * `?` - Open keyboard shortcut help **Actions** * `f` - Favorite topic * `s` - Share topic * `<Shift>` + `s` - Share selected post * `r` - Reply to topic * `<Shift>` + `r` - Reply to selected post * `l` - Like selected post * `!` - Flag selected post * `b` - Bookmark selected post * `e` - Edit selected post * `d` - Delete selected post * `m` then `m` - Mark topic as muted * `m` then `r` - Mark topic as regular * `m` then `t` - Mark topic as tracking * `m` then `w` - Mark topic as watching
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
Keyboard Shortcut related functions.
|
||||
|
||||
@class KeyboardShortcuts
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.KeyboardShortcuts = Ember.Object.createWithMixins({
|
||||
PATH_BINDINGS: {
|
||||
'g h': '/',
|
||||
'g l': '/latest',
|
||||
'g n': '/new',
|
||||
'g u': '/unread',
|
||||
'g f': '/favorited',
|
||||
'g c': '/categories'
|
||||
},
|
||||
|
||||
CLICK_BINDINGS: {
|
||||
'b': 'article.selected button.bookmark', // bookmark current post
|
||||
'c': '#create-topic', // create new topic
|
||||
'd': 'article.selected button.delete', // delete selected post
|
||||
'e': 'article.selected button.edit', // edit selected post
|
||||
|
||||
// favorite topic
|
||||
'f': '#topic-footer-buttons button.favorite, #topic-list tr.topic-list-item.selected a.star',
|
||||
|
||||
'l': 'article.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.topic-list-item.selected a.title', // open selected topic
|
||||
'r': '#topic-footer-buttons button.create', // reply to topic
|
||||
'R': 'article.selected button.create', // reply to selected post
|
||||
's': '#topic-footer-buttons button.share', // share topic
|
||||
'S': 'article.selected button.share', // share selected post
|
||||
'/': '#search-button', // focus search
|
||||
'!': 'article.selected button.flag', // flag selected post
|
||||
'?': '#keyboard-help' // open keyboard shortcut help
|
||||
},
|
||||
|
||||
FUNCTION_BINDINGS: {
|
||||
'j': 'selectDown',
|
||||
'k': 'selectUp',
|
||||
'u': 'goBack',
|
||||
'`': 'nextSection',
|
||||
'~': 'prevSection'
|
||||
},
|
||||
|
||||
bindEvents: function(keyTrapper) {
|
||||
this.keyTrapper = keyTrapper;
|
||||
_.each(this.PATH_BINDINGS, this._bindToPath, this);
|
||||
_.each(this.CLICK_BINDINGS, this._bindToClick, this);
|
||||
_.each(this.FUNCTION_BINDINGS, this._bindToFunction, this);
|
||||
},
|
||||
|
||||
selectDown: function() {
|
||||
this._moveSelection(1);
|
||||
},
|
||||
|
||||
selectUp: function() {
|
||||
this._moveSelection(-1);
|
||||
},
|
||||
|
||||
goBack: function() {
|
||||
history.back();
|
||||
},
|
||||
|
||||
nextSection: function() {
|
||||
this._changeSection(1);
|
||||
},
|
||||
|
||||
prevSection: function() {
|
||||
this._changeSection(-1);
|
||||
},
|
||||
|
||||
_bindToPath: function(path, binding) {
|
||||
this.keyTrapper.bind(binding, function() {
|
||||
Discourse.URL.routeTo(path);
|
||||
});
|
||||
},
|
||||
|
||||
_bindToClick: function(selector, binding) {
|
||||
binding = binding.split(',');
|
||||
this.keyTrapper.bind(binding, function(e) {
|
||||
if (!_.isUndefined(e) && _.isFunction(e.preventDefault)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
$(selector).click();
|
||||
});
|
||||
},
|
||||
|
||||
_bindToFunction: function(func, binding) {
|
||||
if (typeof this[func] === 'function') {
|
||||
this.keyTrapper.bind(binding, _.bind(this[func], this));
|
||||
}
|
||||
},
|
||||
|
||||
_moveSelection: function(num) {
|
||||
var $articles = this._findArticles();
|
||||
|
||||
if (typeof $articles === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
var $selected = $articles.filter('.selected'),
|
||||
index = $articles.index($selected),
|
||||
$article = $articles.eq(index + num);
|
||||
|
||||
if ($article.size() > 0) {
|
||||
$articles.removeClass('selected');
|
||||
$article.addClass('selected');
|
||||
this._scrollList($article);
|
||||
}
|
||||
},
|
||||
|
||||
_scrollList: function($article) {
|
||||
var $body = $('body'),
|
||||
distToElement = $article.position().top + $article.height() - $(window).height() - $body.scrollTop();
|
||||
|
||||
$('html, body').scrollTop($body.scrollTop() + distToElement);
|
||||
},
|
||||
|
||||
_findArticles: function() {
|
||||
var $topicList = $('#topic-list'),
|
||||
$topicArea = $('.posts-wrapper');
|
||||
|
||||
if ($topicArea.size() > 0) {
|
||||
return $topicArea.find('.topic-post');
|
||||
}
|
||||
else if ($topicList.size() > 0) {
|
||||
return $topicList.find('.topic-list-item');
|
||||
}
|
||||
},
|
||||
|
||||
_changeSection: function(num) {
|
||||
var $sections = $('#category-filter').find('li'),
|
||||
$active = $sections.filter('.active'),
|
||||
index = $sections.index('.active');
|
||||
|
||||
$sections.eq(index + num).find('a').click();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user