0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

Implement Shortcuts in Ember

Closes #2988, #2752
Ref #1463, #2984,
 # Shortcuts via Keymaster
- Added KeyMaster to bower dependencies. KeyMaster is a minimal keyboard
  shortcuts library.
- Added `ShortcutsRouteMixin` for routes that will use shortcuts.
  Currently, only routes can have shortcuts. See the extensive comment
  at the top of `core/client/mixins/shortcuts-route.js` for a
  description of how to implement shortcuts.

 ## Other Changes
- Injected popover service into ApplicationRoute
- Created `EditorRouteBase` mixin for the `editor.new` and
  `editor.edit` routes to mixin.
- `StyleBodyMixin` now calls `this._super()` on `activate` and
  `deactivate` to play nicely with other mixins.

 ## Shortcuts and Stubs implemented
 #### Application-Wide
- `'esc':'closePopups'` shortcut **stub** to close popovers,
 modals, and notifcations

 #### Editor Shortcuts
- `'ctrl+s, command+s': 'save'` note that `command` is the
  `meta` key.
- `'ctrl+alt+p': 'publish'`
- `'ctrl+alt+z': 'toggleZenMode'`
This commit is contained in:
Matt Enlow 2014-06-19 13:44:44 -06:00
parent 42a5f29263
commit e10c0f20cf
11 changed files with 122 additions and 7 deletions

View file

@ -507,6 +507,7 @@ var path = require('path'),
'bower_components/codemirror/mode/gfm/gfm.js',
'bower_components/showdown/src/showdown.js',
'bower_components/moment/moment.js',
'bower_components/keymaster/keymaster.js',
'bower_components/jquery-ui/ui/jquery-ui.js',
'bower_components/jquery-file-upload/js/jquery.fileupload.js',

View file

@ -16,6 +16,7 @@
"jquery-file-upload": "9.5.6",
"jquery-hammerjs": "1.0.1",
"jquery-ui": "1.10.4",
"keymaster": "madrobby/keymaster#0f09fc1b7e66c2b7e07afe89a419366dcf2d1cd8",
"lodash": "2.4.1",
"moment": "2.4.0",
"nprogress": "0.1.2",

View file

@ -22,6 +22,7 @@ var popoverInitializer = {
application.inject('component:gh-popover', 'popover', 'popover:service');
application.inject('component:gh-popover-button', 'popover', 'popover:service');
application.inject('controller:modals.delete-post', 'popover', 'popover:service');
application.inject('route:application', 'popover', 'popover:service');
}
};

View file

@ -0,0 +1,25 @@
import ShortcutsRoute from 'ghost/mixins/shortcuts-route';
import styleBody from 'ghost/mixins/style-body';
var EditorRouteBase = Ember.Mixin.create(styleBody, ShortcutsRoute, {
shortcuts: {
'ctrl+s, command+s': 'save',
'ctrl+alt+p': 'publish',
'ctrl+alt+z': 'toggleZenMode'
},
actions: {
save: function () {
this.get('controller').send('save');
},
publish: function () {
var controller = this.get('controller');
controller.send('setSaveType', 'publish');
controller.send('save');
},
toggleZenMode: function () {
Ember.$('body').toggleClass('zen');
}
}
});
export default EditorRouteBase;

View file

@ -0,0 +1,61 @@
/* global key, console */
//Configure KeyMaster to respond to all shortcuts,
//even inside of
//input, textarea, and select.
key.filter = function () {
return true;
};
/**
* Only routes can implement shortcuts.
* If you need to trigger actions on the controller,
* simply call them with `this.get('controller').send('action')`.
*
* To implement shortcuts, add this mixin to your `extend()`,
* and implement a `shortcuts` hash.
* In this hash, keys are shortcut combinations
* (see [keymaster docs](https://github.com/madrobby/keymaster/blob/master/README.markdown)), and values are controller action names.
* ```javascript
* shortcuts: {
* 'ctrl+s, command+s': 'save',
* 'ctrl+alt+p': 'toggleZenMode'
* }
* ```
*/
var ShortcutsRoute = Ember.Mixin.create({
registerShortcuts: function () {
var self = this,
shortcuts = this.get('shortcuts');
Ember.keys(shortcuts).forEach(function (shortcut) {
key(shortcut, function (event) {
//stop things like ctrl+s from actually opening a save dialogue
event.preventDefault();
//map the shortcut to its action
self.send(shortcuts[shortcut], event);
});
});
},
removeShortcuts: function () {
var shortcuts = this.get('shortcuts');
Ember.keys(shortcuts).forEach(function (shortcut) {
key.unbind(shortcut);
});
},
activate: function () {
this._super();
if (!this.shortcuts) {
console.error('Shortcuts not found on route');
return;
}
this.registerShortcuts();
},
deactivate: function () {
this._super();
this.removeShortcuts();
}
});
export default ShortcutsRoute;

View file

@ -2,6 +2,7 @@
var styleBody = Ember.Mixin.create({
activate: function () {
this._super();
var cssClasses = this.get('classNames');
if (cssClasses) {
@ -14,6 +15,7 @@ var styleBody = Ember.Mixin.create({
},
deactivate: function () {
this._super();
var cssClasses = this.get('classNames');
Ember.run.schedule('afterRender', null, function () {

View file

@ -1,5 +1,15 @@
var ApplicationRoute = Ember.Route.extend({
import ShortcutsRoute from 'ghost/mixins/shortcuts-route';
var ApplicationRoute = Ember.Route.extend(ShortcutsRoute, {
shortcuts: {
'esc': 'closePopups'
},
actions: {
closePopups: function () {
this.get('popover').closePopovers();
this.get('notifications').closeAll();
// @todo close modals
},
signedIn: function (user) {
// Update the user on all routes and controllers
this.container.unregister('user:current');

View file

@ -1,7 +1,7 @@
import styleBody from 'ghost/mixins/style-body';
import AuthenticatedRoute from 'ghost/routes/authenticated';
import base from 'ghost/mixins/editor-route-base';
var EditorEditRoute = AuthenticatedRoute.extend(styleBody, {
var EditorEditRoute = AuthenticatedRoute.extend(base, {
classNames: ['editor'],
model: function (params) {

View file

@ -1,7 +1,7 @@
import AuthenticatedRoute from 'ghost/routes/authenticated';
import styleBody from 'ghost/mixins/style-body';
import base from 'ghost/mixins/editor-route-base';
var EditorNewRoute = AuthenticatedRoute.extend(styleBody, {
var EditorNewRoute = AuthenticatedRoute.extend(base, {
classNames: ['editor'],
model: function () {

View file

@ -1,5 +1,6 @@
import styleBody from 'ghost/mixins/style-body';
import AuthenticatedRoute from 'ghost/routes/authenticated';
import styleBody from 'ghost/mixins/style-body';
import ShortcutsRoute from 'ghost/mixins/shortcuts-route';
var paginationSettings = {
status: 'all',
@ -8,7 +9,7 @@ var paginationSettings = {
limit: 15
};
var PostsRoute = AuthenticatedRoute.extend(styleBody, {
var PostsRoute = AuthenticatedRoute.extend(ShortcutsRoute, styleBody, {
classNames: ['manage'],
model: function () {
@ -24,9 +25,19 @@ var PostsRoute = AuthenticatedRoute.extend(styleBody, {
controller.set('paginationSettings', paginationSettings);
},
shortcuts: {
'up': 'moveUp',
'down': 'moveDown'
},
actions: {
openEditor: function (post) {
this.transitionTo('editor', post);
},
moveUp: function () {
window.alert('@todo keyboard post navigation: up');
},
moveDown: function () {
window.alert('@todo keyboard post navigation: down');
}
}
});

View file

@ -46,6 +46,9 @@ var Notifications = Ember.ArrayProxy.extend({
type: 'warn',
message: message
});
},
closeAll: function () {
window.alert('@TODO implement closeALl notifications');
}
});