RFC Keyboard's shortcuts trigger unexpected behaviour
Problem
Upon to the removal of the bold styling (strong) functionality of the editor it came to our attention a very weird substance behaviour. The issue was as follows:
When the editor does not contain the Strong Package, provided by Substance, responsible of creating the corresponding annotation on a selected text by pressing ctrl+b/cmd+b
an unexpected series of events occur. More specifically, a document change is triggered which contains text deletions inside the editor.
After investigation, it seems that the way substance handles keyboard events is based on the below logic:
For each imported substance package (e.g emphasis, strong, lists, etc) if there is a specific shortcut declared for this package create an entry in the Editor's Session keyboard manager where the specific shortcut will be bound to its corresponding hook which will trigger the correct command. If a shortcut is not declared in any of the registered packages then let the keyboard event to be handled in a higher level (browser's default behaviour, etc)
In our case, as we no longer have Substance's Strong package, the keyboard event of ctrl+b/cmd+b
creates a DOM mutation in the scope of ContentEditable which is misparsed from Substance as a document change which contains a deletion action.
Solution Attempt
In an attempt of fixing this issue my approach was to extend the functionality of the onKeyDown hook provided by Substance in our implementation of the ContainerEditor (Surface). The logic inside the aforementioned hook will be:
- Retrieve all the registered keyboard shortcuts of the editor
- If the current event is a combination of
ctrl/cmd
key plus a character check if this shortcut is registered in the editor and execute the corresponding command - Else don't do anything (
event.preventDefault
,event.stopPropagation
)
An immediate problem in the above logic is what will happen in the case of some generic keyboard shortcuts such as ctrl+c
, ctrl+v
, ctrl+x
, etc. These generic shortcuts are expected to work in a browser. However, these shortcuts are not registered into Substance's 'world'.
My final thought is to enhance the logic mentioned above (onKeyDown hook) by providing a whitelist of shortcuts (ctrl+c
, ctrl+v
, ctrl+x
, etc) where the keyboard event will be compared against and if and only if that event is contained in the whitelist then allow the browser's default behaviour to be executed.
Example implementation:
onKeyDown (event) {
const whitelistCommands = ['META+67', 'META+86', 'META+82', 'META+88', 'CTRL+67', 'CTRL+86', 'CTRL+82', 'CTRL+88']
const extractedCommand = this.generateKey(event)
if (indexOf (whitelistCommands, extractedCommand) === -1) {
if (platform.isMac) {
if (event.metaKey && !has(this.shortcutBindings, extractedCommand)) {
event.preventDefault()
event.stopPropagation()
return
}
} else {
if (event.ctrlKey && !has(this.shortcutBindings, extractedCommand)) {
event.preventDefault()
event.stopPropagation()
return
}
}
}
super.onKeyDown(event)
}
As the above implementation will work, even as a workaround, I can't stop myself of thinking about the scalability of the solution and even wonder if there is a better way of addressing this issue.