mirror of
https://github.com/discourse/discourse.git
synced 2025-05-23 19:24:36 +08:00
FIX: make composer full screen shortcut work when inputs have focus (#6907)
- Uses a Mousetrap plugin for global shortcuts - Implemented for search `ctrl+alt+f` and composer fullscreen `shift+f11` shortcuts
This commit is contained in:
@ -108,6 +108,13 @@ export default Ember.Component.extend({
|
|||||||
this._resetUpload(true);
|
this._resetUpload(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@observes("focusTarget")
|
||||||
|
setFocus() {
|
||||||
|
if (this.get("focusTarget") === "editor") {
|
||||||
|
this.$("textarea").putCursorAtEnd();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
markdownOptions() {
|
markdownOptions() {
|
||||||
return {
|
return {
|
||||||
|
@ -256,15 +256,6 @@ export default Ember.Component.extend({
|
|||||||
const mouseTrap = Mousetrap(this.$(".d-editor-input")[0]);
|
const mouseTrap = Mousetrap(this.$(".d-editor-input")[0]);
|
||||||
const shortcuts = this.get("toolbar.shortcuts");
|
const shortcuts = this.get("toolbar.shortcuts");
|
||||||
|
|
||||||
// for some reason I am having trouble bubbling this so hack it in
|
|
||||||
mouseTrap.bind(["ctrl+alt+f"], event => {
|
|
||||||
this.appEvents.trigger("header:keyboard-trigger", {
|
|
||||||
type: "search",
|
|
||||||
event
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.keys(shortcuts).forEach(sc => {
|
Object.keys(shortcuts).forEach(sc => {
|
||||||
const button = shortcuts[sc];
|
const button = shortcuts[sc];
|
||||||
mouseTrap.bind(sc, () => {
|
mouseTrap.bind(sc, () => {
|
||||||
@ -323,7 +314,6 @@ export default Ember.Component.extend({
|
|||||||
Object.keys(this.get("toolbar.shortcuts")).forEach(sc =>
|
Object.keys(this.get("toolbar.shortcuts")).forEach(sc =>
|
||||||
mouseTrap.unbind(sc)
|
mouseTrap.unbind(sc)
|
||||||
);
|
);
|
||||||
mouseTrap.unbind("ctrl+/", "command+/");
|
|
||||||
this.$(".d-editor-preview").off("click.preview");
|
this.$(".d-editor-preview").off("click.preview");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -133,9 +133,10 @@ export default Ember.Controller.extend({
|
|||||||
@computed(
|
@computed(
|
||||||
"model.replyingToTopic",
|
"model.replyingToTopic",
|
||||||
"model.creatingPrivateMessage",
|
"model.creatingPrivateMessage",
|
||||||
"model.targetUsernames"
|
"model.targetUsernames",
|
||||||
|
"model.composeState"
|
||||||
)
|
)
|
||||||
focusTarget(replyingToTopic, creatingPM, usernames) {
|
focusTarget(replyingToTopic, creatingPM, usernames, composeState) {
|
||||||
if (this.capabilities.isIOS) {
|
if (this.capabilities.isIOS) {
|
||||||
return "none";
|
return "none";
|
||||||
}
|
}
|
||||||
@ -153,6 +154,10 @@ export default Ember.Controller.extend({
|
|||||||
return "reply";
|
return "reply";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (composeState === Composer.FULLSCREEN) {
|
||||||
|
return "editor";
|
||||||
|
}
|
||||||
|
|
||||||
return "title";
|
return "title";
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ const bindings = {
|
|||||||
"!": { postAction: "showFlags" },
|
"!": { postAction: "showFlags" },
|
||||||
"#": { handler: "goToPost", anonymous: true },
|
"#": { handler: "goToPost", anonymous: true },
|
||||||
"/": { handler: "toggleSearch", anonymous: true },
|
"/": { handler: "toggleSearch", anonymous: true },
|
||||||
"ctrl+alt+f": { handler: "toggleSearch", anonymous: true },
|
"ctrl+alt+f": { handler: "toggleSearch", anonymous: true, global: true },
|
||||||
"=": { handler: "toggleHamburgerMenu", anonymous: true },
|
"=": { handler: "toggleHamburgerMenu", anonymous: true },
|
||||||
"?": { handler: "showHelpModal", anonymous: true },
|
"?": { handler: "showHelpModal", anonymous: true },
|
||||||
".": { click: ".alert.alert-info.clickable", anonymous: true }, // show incoming/updated topics
|
".": { click: ".alert.alert-info.clickable", anonymous: true }, // show incoming/updated topics
|
||||||
@ -67,7 +67,7 @@ const bindings = {
|
|||||||
"shift+s": { click: "#topic-footer-buttons button.share", anonymous: true }, // share topic
|
"shift+s": { click: "#topic-footer-buttons button.share", anonymous: true }, // share topic
|
||||||
"shift+u": { handler: "goToUnreadPost" },
|
"shift+u": { handler: "goToUnreadPost" },
|
||||||
"shift+z shift+z": { handler: "logout" },
|
"shift+z shift+z": { handler: "logout" },
|
||||||
"shift+f11": { handler: "fullscreenComposer" },
|
"shift+f11": { handler: "fullscreenComposer", global: true },
|
||||||
t: { postAction: "replyAsNewTopic" },
|
t: { postAction: "replyAsNewTopic" },
|
||||||
u: { handler: "goBack", anonymous: true },
|
u: { handler: "goBack", anonymous: true },
|
||||||
"x r": {
|
"x r": {
|
||||||
@ -101,7 +101,12 @@ export default {
|
|||||||
if (binding.path) {
|
if (binding.path) {
|
||||||
this._bindToPath(binding.path, key);
|
this._bindToPath(binding.path, key);
|
||||||
} else if (binding.handler) {
|
} else if (binding.handler) {
|
||||||
|
if (binding.global) {
|
||||||
|
// global shortcuts will trigger even while focusing on input/textarea
|
||||||
|
this._globalBindToFunction(binding.handler, key);
|
||||||
|
} else {
|
||||||
this._bindToFunction(binding.handler, key);
|
this._bindToFunction(binding.handler, key);
|
||||||
|
}
|
||||||
} else if (binding.postAction) {
|
} else if (binding.postAction) {
|
||||||
this._bindToSelectedPost(binding.postAction, key);
|
this._bindToSelectedPost(binding.postAction, key);
|
||||||
} else if (binding.click) {
|
} else if (binding.click) {
|
||||||
@ -399,6 +404,12 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_globalBindToFunction(func, binding) {
|
||||||
|
if (typeof this[func] === "function") {
|
||||||
|
this.keyTrapper.bindGlobal(binding, _.bind(this[func], this));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_bindToFunction(func, binding) {
|
_bindToFunction(func, binding) {
|
||||||
if (typeof this[func] === "function") {
|
if (typeof this[func] === "function") {
|
||||||
this.keyTrapper.bind(binding, _.bind(this[func], this));
|
this.keyTrapper.bind(binding, _.bind(this[func], this));
|
||||||
|
@ -111,7 +111,8 @@
|
|||||||
importQuote=(action "importQuote")
|
importQuote=(action "importQuote")
|
||||||
togglePreview=(action "togglePreview")
|
togglePreview=(action "togglePreview")
|
||||||
showToolbar=showToolbar
|
showToolbar=showToolbar
|
||||||
afterRefresh=(action "afterRefresh")}}
|
afterRefresh=(action "afterRefresh")
|
||||||
|
focusTarget=focusTarget}}
|
||||||
|
|
||||||
<div class='submit-panel'>
|
<div class='submit-panel'>
|
||||||
{{plugin-outlet name="composer-fields-below" args=(hash model=model)}}
|
{{plugin-outlet name="composer-fields-below" args=(hash model=model)}}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
//= require jquery.sortable.js
|
//= require jquery.sortable.js
|
||||||
//= require lodash.js
|
//= require lodash.js
|
||||||
//= require mousetrap.js
|
//= require mousetrap.js
|
||||||
|
//= require mousetrap-global-bind.js
|
||||||
//= require rsvp.js
|
//= require rsvp.js
|
||||||
//= require show-html.js
|
//= require show-html.js
|
||||||
//= require break_string
|
//= require break_string
|
||||||
|
@ -73,6 +73,8 @@ task 'javascript:update' do
|
|||||||
destination: 'moment-locale',
|
destination: 'moment-locale',
|
||||||
}, {
|
}, {
|
||||||
source: 'moment-timezone/builds/moment-timezone-with-data.js'
|
source: 'moment-timezone/builds/moment-timezone-with-data.js'
|
||||||
|
}, {
|
||||||
|
source: 'mousetrap/plugins/global-bind/mousetrap-global-bind.js'
|
||||||
}, {
|
}, {
|
||||||
source: 'resumablejs/resumable.js'
|
source: 'resumablejs/resumable.js'
|
||||||
}, {
|
}, {
|
||||||
|
43
vendor/assets/javascripts/mousetrap-global-bind.js
vendored
Normal file
43
vendor/assets/javascripts/mousetrap-global-bind.js
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* adds a bindGlobal method to Mousetrap that allows you to
|
||||||
|
* bind specific keyboard shortcuts that will still work
|
||||||
|
* inside a text input field
|
||||||
|
*
|
||||||
|
* usage:
|
||||||
|
* Mousetrap.bindGlobal('ctrl+s', _saveChanges);
|
||||||
|
*/
|
||||||
|
/* global Mousetrap:true */
|
||||||
|
(function(Mousetrap) {
|
||||||
|
var _globalCallbacks = {};
|
||||||
|
var _originalStopCallback = Mousetrap.prototype.stopCallback;
|
||||||
|
|
||||||
|
Mousetrap.prototype.stopCallback = function(e, element, combo, sequence) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (self.paused) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_globalCallbacks[combo] || _globalCallbacks[sequence]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _originalStopCallback.call(self, e, element, combo);
|
||||||
|
};
|
||||||
|
|
||||||
|
Mousetrap.prototype.bindGlobal = function(keys, callback, action) {
|
||||||
|
var self = this;
|
||||||
|
self.bind(keys, callback, action);
|
||||||
|
|
||||||
|
if (keys instanceof Array) {
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
_globalCallbacks[keys[i]] = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_globalCallbacks[keys] = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Mousetrap.init();
|
||||||
|
}) (Mousetrap);
|
Reference in New Issue
Block a user