diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-12 03:08:44 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-12 03:08:44 +0300 |
commit | 0f5dcf55e543e2cb30697d4c8ea8ce509cf25375 (patch) | |
tree | 213f71f90ed2f6d356a90b0d09e8dbf5d14e816e /app/assets/javascripts/behaviors | |
parent | a66475b6beb46d77b9ff3fe30453be2d52779048 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/behaviors')
-rw-r--r-- | app/assets/javascripts/behaviors/shortcuts/shortcuts.js | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js index f820396d05b..8a8b61a57cd 100644 --- a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js +++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js @@ -2,6 +2,7 @@ import $ from 'jquery'; import Cookies from 'js-cookie'; import Mousetrap from 'mousetrap'; import Vue from 'vue'; +import { flatten } from 'lodash'; import { disableShortcuts, shouldDisableShortcuts } from './shortcuts_toggle'; import ShortcutsToggle from './shortcuts_toggle.vue'; import axios from '../../lib/utils/axios_utils'; @@ -27,6 +28,39 @@ function initToggleButton() { }); } +/** + * The key used to save and fetch the local Mousetrap instance + * attached to a `<textarea>` element using `jQuery.data` + */ +const LOCAL_MOUSETRAP_DATA_KEY = 'local-mousetrap-instance'; + +/** + * Gets a mapping of toolbar button => keyboard shortcuts + * associated to the given markdown editor `<textarea>` element + * + * @param {HTMLTextAreaElement} $textarea The jQuery-wrapped `<textarea>` + * element to extract keyboard shortcuts from + * + * @returns A Map with keys that are jQuery-wrapped toolbar buttons + * (i.e. `$toolbarBtn`) and values that are arrays of string + * keyboard shortcuts (e.g. `['command+k', 'ctrl+k]`). + */ +function getToolbarBtnToShortcutsMap($textarea) { + const $allToolbarBtns = $textarea.closest('.md-area').find('.js-md'); + const map = new Map(); + + $allToolbarBtns.each(function attachToolbarBtnHandler() { + const $toolbarBtn = $(this); + const keyboardShortcuts = $toolbarBtn.data('md-shortcuts'); + + if (keyboardShortcuts?.length) { + map.set($toolbarBtn, keyboardShortcuts); + } + }); + + return map; +} + export default class Shortcuts { constructor() { this.onToggleHelp = this.onToggleHelp.bind(this); @@ -144,4 +178,62 @@ export default class Shortcuts { e.preventDefault(); } } + + /** + * Initializes markdown editor shortcuts on the provided `<textarea>` element + * + * @param {JQuery} $textarea The jQuery-wrapped `<textarea>` element + * where markdown shortcuts should be enabled + * @param {Function} handler The handler to call when a + * keyboard shortcut is pressed inside the markdown `<textarea>` + */ + static initMarkdownEditorShortcuts($textarea, handler) { + const toolbarBtnToShortcutsMap = getToolbarBtnToShortcutsMap($textarea); + + const localMousetrap = new Mousetrap($textarea[0]); + + // Save a reference to the local mousetrap instance on the <textarea> + // so that it can be retrieved when unbinding shortcut handlers + $textarea.data(LOCAL_MOUSETRAP_DATA_KEY, localMousetrap); + + toolbarBtnToShortcutsMap.forEach((keyboardShortcuts, $toolbarBtn) => { + localMousetrap.bind(keyboardShortcuts, e => { + e.preventDefault(); + + handler($toolbarBtn); + }); + }); + + // Get an array of all shortcut strings that have been added above + const allShortcuts = flatten([...toolbarBtnToShortcutsMap.values()]); + + const originalStopCallback = Mousetrap.prototype.stopCallback; + localMousetrap.stopCallback = function newStopCallback(e, element, combo) { + if (allShortcuts.includes(combo)) { + return false; + } + + return originalStopCallback.call(this, e, element, combo); + }; + } + + /** + * Removes markdown editor shortcut handlers originally attached + * with `initMarkdownEditorShortcuts`. + * + * Note: it is safe to call this function even if `initMarkdownEditorShortcuts` + * has _not_ yet been called on the given `<textarea>`. + * + * @param {JQuery} $textarea The jQuery-wrapped `<textarea>` + * to remove shortcut handlers from + */ + static removeMarkdownEditorShortcuts($textarea) { + const localMousetrap = $textarea.data(LOCAL_MOUSETRAP_DATA_KEY); + + if (localMousetrap) { + getToolbarBtnToShortcutsMap($textarea).forEach(keyboardShortcuts => { + localMousetrap.unbind(keyboardShortcuts); + }); + } + } } |