mirror of
https://github.com/wekan/wekan.git
synced 2026-01-23 17:56:09 +01:00
87 lines
3 KiB
JavaScript
87 lines
3 KiB
JavaScript
// 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;
|
|
|
|
/**
|
|
* 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,
|
|
},
|
|
};
|
|
|
|
const textcomplete = new Textcomplete(editor, strategies, mergedOptions);
|
|
|
|
// 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);
|
|
});
|
|
};
|
|
|
|
EscapeActions.register(
|
|
'textcomplete',
|
|
() => {},
|
|
() => dropdownMenuIsOpened,
|
|
{
|
|
noClickEscapeOn: '.textcomplete-dropdown',
|
|
},
|
|
);
|