(core) Improve focus and keyboard shortcuts in modals.

Summary:
- Factor out focusing logic from Clipboard to FocusLayer.
- Generalize FocusLayer to support adding a temporary layer while a modal is open.
- Stop Mousetrap shortcuts while a modal is open.
- Refactor how Mousetrap's custom stopCallback is implemented to avoid
  needing to bundle knockout for mousetrap.

Test Plan: Added a test that Enter in a UserManager doesn't open a cell editor from underneath the modal.

Reviewers: paulfitz

Reviewed By: paulfitz

Differential Revision: https://phab.getgrist.com/D2626
This commit is contained in:
Dmitry S
2020-10-02 15:26:14 -04:00
parent 1654a2681f
commit 90db5020c9
6 changed files with 224 additions and 81 deletions

View File

@@ -17,13 +17,14 @@ if (typeof window === 'undefined') {
} else {
var Mousetrap = require('mousetrap');
var ko = require('knockout');
// Minus is different on Gecko:
// see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
// and https://github.com/ccampbell/mousetrap/pull/215
Mousetrap.addKeycodes({173: '-'});
var customStopCallbacks = new WeakMap();
var MousetrapProtype = Mousetrap.prototype;
var origStopCallback = MousetrapProtype.stopCallback;
@@ -36,9 +37,10 @@ if (typeof window === 'undefined') {
if (mousetrapBindingsPaused) {
return true;
}
var cmdGroup = ko.utils.domData.get(element, 'mousetrapCommandGroup');
if (cmdGroup) {
return !cmdGroup.knownKeys.hasOwnProperty(combo);
// If we have a custom stopCallback, use it now.
const custom = customStopCallbacks.get(element);
if (custom) {
return custom(combo);
}
try {
return origStopCallback.call(this, e, element, combo, sequence);
@@ -63,5 +65,13 @@ if (typeof window === 'undefined') {
mousetrapBindingsPaused = yesNo;
};
/**
* Set a custom stopCallback for an element. When a key combo is pressed for this element,
* callback(combo) is called. If it returns true, Mousetrap should NOT process the combo.
*/
Mousetrap.setCustomStopCallback = function(element, callback) {
customStopCallbacks.set(element, callback);
};
module.exports = Mousetrap;
}