mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-12 15:44:06 -08:00
fix(editor): Prevent opening NDV search if /
is typed in a contenteditable element (#7968)
## Summary Prevent opening NDV search if `/` is typed in a contenteditable element ... #### How to test the change: 1. Create a workflow with a Code node that has some input and output 2. Run the workflow and then open the Code node 3. Type `/` anywhere in the Code node #### Expected behavior: NDV search should not be opened and focused
This commit is contained in:
parent
7f0126915a
commit
e8a493f718
|
@ -26,7 +26,6 @@ const locale = useI18n();
|
||||||
const inputRef = ref<HTMLInputElement | null>(null);
|
const inputRef = ref<HTMLInputElement | null>(null);
|
||||||
const maxWidth = ref(INITIAL_WIDTH);
|
const maxWidth = ref(INITIAL_WIDTH);
|
||||||
const opened = ref(false);
|
const opened = ref(false);
|
||||||
const focused = ref(false);
|
|
||||||
const placeholder = computed(() =>
|
const placeholder = computed(() =>
|
||||||
props.paneType === 'input'
|
props.paneType === 'input'
|
||||||
? locale.baseText('ndv.search.placeholder.input')
|
? locale.baseText('ndv.search.placeholder.input')
|
||||||
|
@ -34,11 +33,13 @@ const placeholder = computed(() =>
|
||||||
);
|
);
|
||||||
|
|
||||||
const documentKeyHandler = (event: KeyboardEvent) => {
|
const documentKeyHandler = (event: KeyboardEvent) => {
|
||||||
const isTargetAnyFormElement =
|
const isTargetFormElementOrEditable =
|
||||||
event.target instanceof HTMLInputElement ||
|
event.target instanceof HTMLInputElement ||
|
||||||
event.target instanceof HTMLTextAreaElement ||
|
event.target instanceof HTMLTextAreaElement ||
|
||||||
event.target instanceof HTMLSelectElement;
|
event.target instanceof HTMLSelectElement ||
|
||||||
if (event.key === '/' && !focused.value && props.isAreaActive && !isTargetAnyFormElement) {
|
(event.target as HTMLElement)?.getAttribute?.('contentEditable') === 'true';
|
||||||
|
|
||||||
|
if (event.key === '/' && props.isAreaActive && !isTargetFormElementOrEditable) {
|
||||||
inputRef.value?.focus();
|
inputRef.value?.focus();
|
||||||
inputRef.value?.select();
|
inputRef.value?.select();
|
||||||
}
|
}
|
||||||
|
@ -49,13 +50,11 @@ const onSearchUpdate = (value: string) => {
|
||||||
};
|
};
|
||||||
const onFocus = () => {
|
const onFocus = () => {
|
||||||
opened.value = true;
|
opened.value = true;
|
||||||
focused.value = true;
|
|
||||||
maxWidth.value = '30%';
|
maxWidth.value = '30%';
|
||||||
inputRef.value?.select();
|
inputRef.value?.select();
|
||||||
emit('focus');
|
emit('focus');
|
||||||
};
|
};
|
||||||
const onBlur = () => {
|
const onBlur = () => {
|
||||||
focused.value = false;
|
|
||||||
if (!props.modelValue) {
|
if (!props.modelValue) {
|
||||||
opened.value = false;
|
opened.value = false;
|
||||||
maxWidth.value = INITIAL_WIDTH;
|
maxWidth.value = INITIAL_WIDTH;
|
||||||
|
|
|
@ -2,21 +2,14 @@ import userEvent from '@testing-library/user-event';
|
||||||
import { createPinia, setActivePinia } from 'pinia';
|
import { createPinia, setActivePinia } from 'pinia';
|
||||||
import { createComponentRenderer } from '@/__tests__/render';
|
import { createComponentRenderer } from '@/__tests__/render';
|
||||||
import RunDataSearch from '@/components/RunDataSearch.vue';
|
import RunDataSearch from '@/components/RunDataSearch.vue';
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
|
||||||
|
|
||||||
const renderComponent = createComponentRenderer(RunDataSearch);
|
const renderComponent = createComponentRenderer(RunDataSearch);
|
||||||
let pinia: ReturnType<typeof createPinia>;
|
let pinia: ReturnType<typeof createPinia>;
|
||||||
let uiStore: ReturnType<typeof useUIStore>;
|
|
||||||
let settingsStore: ReturnType<typeof useSettingsStore>;
|
|
||||||
|
|
||||||
describe('RunDataSearch', () => {
|
describe('RunDataSearch', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
pinia = createPinia();
|
pinia = createPinia();
|
||||||
setActivePinia(pinia);
|
setActivePinia(pinia);
|
||||||
|
|
||||||
uiStore = useUIStore();
|
|
||||||
settingsStore = useSettingsStore();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be focused on keyboard shortcut when area is not active', async () => {
|
it('should not be focused on keyboard shortcut when area is not active', async () => {
|
||||||
|
@ -66,7 +59,6 @@ describe('RunDataSearch', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should select all text when focused', async () => {
|
it('should select all text when focused', async () => {
|
||||||
vi.spyOn(settingsStore, 'isEnterpriseFeatureEnabled', 'get').mockReturnValue(() => true);
|
|
||||||
const { getByRole, emitted } = renderComponent({
|
const { getByRole, emitted } = renderComponent({
|
||||||
pinia,
|
pinia,
|
||||||
props: {
|
props: {
|
||||||
|
@ -91,4 +83,41 @@ describe('RunDataSearch', () => {
|
||||||
|
|
||||||
expect(isSelected).toBe(true);
|
expect(isSelected).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not be focused on keyboard shortcut when a contenetEditable element is active', async () => {
|
||||||
|
const { getByTestId } = createComponentRenderer({
|
||||||
|
components: {
|
||||||
|
RunDataSearch,
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<div data-test-id="mock-contenteditable" contenteditable="true"></div>
|
||||||
|
<RunDataSearch
|
||||||
|
v-model="modelValue"
|
||||||
|
:isAreaActive="isAreaActive"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
isAreaActive: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})({
|
||||||
|
pinia,
|
||||||
|
});
|
||||||
|
|
||||||
|
const user = userEvent.setup();
|
||||||
|
const contentEditableElement = getByTestId('mock-contenteditable');
|
||||||
|
await user.click(contentEditableElement);
|
||||||
|
expect(document.activeElement).toBe(contentEditableElement);
|
||||||
|
await user.type(contentEditableElement, '/');
|
||||||
|
expect(contentEditableElement.textContent).toBe('/');
|
||||||
|
expect(getByTestId('ndv-search')).not.toHaveFocus();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue