mirror of
https://github.com/wekan/wekan.git
synced 2026-02-14 20:18:07 +01:00
Replace mousetrap
This commit is contained in:
parent
a528a411da
commit
c795dfe96b
7 changed files with 236 additions and 147 deletions
|
|
@ -1,54 +1,80 @@
|
|||
// We “inherit” the jquery-textcomplete plugin to integrate with our
|
||||
// EscapeActions system. You should always use `escapeableTextComplete` instead
|
||||
// of the vanilla `textcomplete`.
|
||||
// We use @textcomplete packages to integrate with our EscapeActions system.
|
||||
// You should always use `createEscapeableTextComplete` or the jQuery extension
|
||||
// `escapeableTextComplete` instead of the vanilla textcomplete.
|
||||
import { Textcomplete } from '@textcomplete/core';
|
||||
import { TextareaEditor } from '@textcomplete/textarea';
|
||||
import { ContenteditableEditor } from '@textcomplete/contenteditable';
|
||||
|
||||
let dropdownMenuIsOpened = false;
|
||||
|
||||
$.fn.escapeableTextComplete = function(strategies, options, ...otherArgs) {
|
||||
// When the autocomplete menu is shown we want both a press of both `Tab`
|
||||
// or `Enter` to validation the auto-completion. We also need to stop the
|
||||
// event propagation to prevent EscapeActions side effect, for instance the
|
||||
// minicard submission (on `Enter`) or going on the next column (on `Tab`).
|
||||
options = {
|
||||
onKeydown(evt, commands) {
|
||||
if (evt.keyCode === 9 || evt.keyCode === 13) {
|
||||
evt.stopPropagation();
|
||||
return commands.KEY_ENTER;
|
||||
}
|
||||
return null;
|
||||
/**
|
||||
* Create an escapeable textcomplete instance for a textarea or contenteditable element
|
||||
* @param {HTMLTextAreaElement|HTMLElement} element - The target element
|
||||
* @param {Array} strategies - Array of strategy objects
|
||||
* @param {Object} options - Additional options
|
||||
* @returns {Textcomplete} The textcomplete instance
|
||||
*/
|
||||
export function createEscapeableTextComplete(element, strategies, options = {}) {
|
||||
// Determine the appropriate editor based on element type
|
||||
const isContentEditable = element.isContentEditable || element.contentEditable === 'true';
|
||||
const Editor = isContentEditable ? ContenteditableEditor : TextareaEditor;
|
||||
|
||||
const editor = new Editor(element);
|
||||
|
||||
// Merge default options
|
||||
const mergedOptions = {
|
||||
dropdown: {
|
||||
className: 'textcomplete-dropdown',
|
||||
maxCount: 10,
|
||||
placement: 'bottom',
|
||||
...options.dropdown,
|
||||
},
|
||||
...options,
|
||||
};
|
||||
|
||||
// Proxy to the vanilla jQuery component
|
||||
this.textcomplete(strategies, options, ...otherArgs);
|
||||
const textcomplete = new Textcomplete(editor, strategies, mergedOptions);
|
||||
|
||||
// Since commit d474017 jquery-textComplete automatically closes a potential
|
||||
// opened dropdown menu when the user press Escape. This behavior conflicts
|
||||
// with our EscapeActions system, but it's too complicated and hacky to
|
||||
// monkey-pach textComplete to disable it -- I tried. Instead we listen to
|
||||
// 'open' and 'hide' events, and create a ghost escapeAction when the dropdown
|
||||
// is opened (and rely on textComplete to execute the actual action).
|
||||
this.on({
|
||||
'textComplete:show'() {
|
||||
dropdownMenuIsOpened = true;
|
||||
},
|
||||
'textComplete:select'() {
|
||||
EscapeActions.preventNextClick();
|
||||
},
|
||||
'textComplete:hide'() {
|
||||
Tracker.afterFlush(() => {
|
||||
// XXX Hack. We unfortunately need to set a setTimeout here to make the
|
||||
// `noClickEscapeOn` work bellow, otherwise clicking on a autocomplete
|
||||
// item will close both the autocomplete menu (as expected) but also the
|
||||
// next item in the stack (for example the minicard editor) which we
|
||||
// don't want.
|
||||
setTimeout(() => {
|
||||
dropdownMenuIsOpened = false;
|
||||
}, 100);
|
||||
});
|
||||
},
|
||||
// When the autocomplete menu is shown we want both a press of both `Tab`
|
||||
// or `Enter` to validate the auto-completion. We also need to stop the
|
||||
// event propagation to prevent EscapeActions side effect, for instance the
|
||||
// minicard submission (on `Enter`) or going on the next column (on `Tab`).
|
||||
element.addEventListener('keydown', (evt) => {
|
||||
if (dropdownMenuIsOpened && (evt.keyCode === 9 || evt.keyCode === 13)) {
|
||||
evt.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
// Track dropdown state for EscapeActions integration
|
||||
// Since @textcomplete automatically closes when Escape is pressed, we
|
||||
// integrate with our EscapeActions system by tracking open/close state.
|
||||
textcomplete.on('show', () => {
|
||||
dropdownMenuIsOpened = true;
|
||||
});
|
||||
|
||||
textcomplete.on('selected', () => {
|
||||
EscapeActions.preventNextClick();
|
||||
});
|
||||
|
||||
textcomplete.on('hidden', () => {
|
||||
Tracker.afterFlush(() => {
|
||||
// XXX Hack. We unfortunately need to set a setTimeout here to make the
|
||||
// `noClickEscapeOn` work below, otherwise clicking on a autocomplete
|
||||
// item will close both the autocomplete menu (as expected) but also the
|
||||
// next item in the stack (for example the minicard editor) which we
|
||||
// don't want.
|
||||
setTimeout(() => {
|
||||
dropdownMenuIsOpened = false;
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
return textcomplete;
|
||||
}
|
||||
|
||||
// jQuery extension for backward compatibility
|
||||
$.fn.escapeableTextComplete = function(strategies, options = {}) {
|
||||
return this.each(function() {
|
||||
createEscapeableTextComplete(this, strategies, options);
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
EscapeActions.register(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue