mirror of
https://github.com/codex-team/editor.js
synced 2024-06-27 01:40:22 +02:00
cd29c52e51
* slash to open toolbox, tab for navigation * tab, focus improvements - remove "focused" block state - tab navigation respects inputs - allow to focus contentless blocks * fix tests * tests for Slash * tab tests * test for tabbing out of editor * tests fixed * review fixes
371 lines
8.4 KiB
TypeScript
371 lines
8.4 KiB
TypeScript
import ToolMock from '../../../fixtures/tools/ToolMock';
|
|
|
|
/**
|
|
* Mock of tool that contains two inputs
|
|
*/
|
|
class ToolWithTwoInputs extends ToolMock {
|
|
/**
|
|
* Create element with two inputs
|
|
*/
|
|
public render(): HTMLElement {
|
|
const wrapper = document.createElement('div');
|
|
const input1 = document.createElement('div');
|
|
const input2 = document.createElement('div');
|
|
|
|
input1.contentEditable = 'true';
|
|
input2.contentEditable = 'true';
|
|
|
|
wrapper.setAttribute('data-cy', 'tool-with-two-inputs');
|
|
|
|
wrapper.appendChild(input1);
|
|
wrapper.appendChild(input2);
|
|
|
|
return wrapper;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mock of tool without inputs
|
|
*/
|
|
class ContentlessTool extends ToolMock {
|
|
public static contentless = true;
|
|
/**
|
|
* Create element without inputs
|
|
*/
|
|
public render(): HTMLElement {
|
|
const wrapper = document.createElement('div');
|
|
|
|
wrapper.setAttribute('data-cy', 'contentless-tool');
|
|
|
|
wrapper.textContent = '***';
|
|
|
|
return wrapper;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Time to wait for caret to finish moving
|
|
*/
|
|
const CARET_MOVE_TIME = 100;
|
|
|
|
describe('Tab keydown', function () {
|
|
it('should focus next Block if Block contains only one input', () => {
|
|
cy.createEditor({
|
|
data: {
|
|
blocks: [
|
|
{
|
|
type: 'paragraph',
|
|
data: {
|
|
text: 'first paragraph',
|
|
},
|
|
},
|
|
{
|
|
type: 'paragraph',
|
|
data: {
|
|
text: 'second paragraph',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
.find('.ce-paragraph')
|
|
.first()
|
|
.click()
|
|
.trigger('keydown', { keyCode: 9 })
|
|
.wait(CARET_MOVE_TIME);
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
.find('.ce-paragraph')
|
|
.last()
|
|
.then(($secondBlock) => {
|
|
const editorWindow = $secondBlock.get(0).ownerDocument.defaultView;
|
|
const selection = editorWindow.getSelection();
|
|
|
|
const range = selection.getRangeAt(0);
|
|
|
|
/**
|
|
* Check that second block contains range
|
|
*/
|
|
expect(range.startContainer.parentElement).to.equal($secondBlock.get(0));
|
|
});
|
|
});
|
|
|
|
it('should focus next input if Block contains several inputs', () => {
|
|
cy.createEditor({
|
|
tools: {
|
|
toolWithTwoInputs: {
|
|
class: ToolWithTwoInputs,
|
|
},
|
|
},
|
|
data: {
|
|
blocks: [
|
|
{
|
|
type: 'toolWithTwoInputs',
|
|
data: {},
|
|
},
|
|
{
|
|
type: 'paragraph',
|
|
data: {
|
|
text: 'second paragraph',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
cy.get('[data-cy=tool-with-two-inputs]')
|
|
.find('[contenteditable=true]')
|
|
.first()
|
|
.click()
|
|
.trigger('keydown', { keyCode: 9 })
|
|
.wait(CARET_MOVE_TIME);
|
|
|
|
cy.get('[data-cy=tool-with-two-inputs]')
|
|
.find('[contenteditable=true]')
|
|
.last()
|
|
.then(($secondInput) => {
|
|
const editorWindow = $secondInput.get(0).ownerDocument.defaultView;
|
|
const selection = editorWindow.getSelection();
|
|
|
|
const range = selection.getRangeAt(0);
|
|
|
|
/**
|
|
* Check that second block contains range
|
|
*/
|
|
expect(range.startContainer).to.equal($secondInput.get(0));
|
|
});
|
|
});
|
|
|
|
it('should highlight next Block if it does not contain any inputs (contentless Block)', () => {
|
|
cy.createEditor({
|
|
tools: {
|
|
contentlessTool: {
|
|
class: ContentlessTool,
|
|
},
|
|
},
|
|
data: {
|
|
blocks: [
|
|
{
|
|
type: 'paragraph',
|
|
data: {
|
|
text: 'second paragraph',
|
|
},
|
|
},
|
|
{
|
|
type: 'contentlessTool',
|
|
data: {},
|
|
},
|
|
{
|
|
type: 'paragraph',
|
|
data: {
|
|
text: 'third paragraph',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
.find('.ce-paragraph')
|
|
.first()
|
|
.click()
|
|
.trigger('keydown', { keyCode: 9 })
|
|
.wait(CARET_MOVE_TIME);
|
|
|
|
cy.get('[data-cy=contentless-tool]')
|
|
.parents('.ce-block')
|
|
.should('have.class', 'ce-block--selected');
|
|
});
|
|
|
|
it('should focus next input after Editor when pressed in last Block', () => {
|
|
cy.createEditor({});
|
|
|
|
/**
|
|
* Add regular input after Editor
|
|
*/
|
|
cy.window()
|
|
.then((window) => {
|
|
const input = window.document.createElement('input');
|
|
|
|
input.setAttribute('data-cy', 'regular-input');
|
|
|
|
window.document.body.appendChild(input);
|
|
});
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
.find('.ce-paragraph')
|
|
.click()
|
|
.tab();
|
|
|
|
cy.get('[data-cy=regular-input]')
|
|
.should('have.focus');
|
|
});
|
|
});
|
|
|
|
describe('Shift+Tab keydown', function () {
|
|
it('should focus previous Block if Block contains only one input', () => {
|
|
cy.createEditor({
|
|
data: {
|
|
blocks: [
|
|
{
|
|
type: 'paragraph',
|
|
data: {
|
|
text: 'first paragraph',
|
|
},
|
|
},
|
|
{
|
|
type: 'paragraph',
|
|
data: {
|
|
text: 'second paragraph',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
.find('.ce-paragraph')
|
|
.last()
|
|
.click()
|
|
.trigger('keydown', {
|
|
keyCode: 9,
|
|
shiftKey: true,
|
|
})
|
|
.wait(CARET_MOVE_TIME);
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
.find('.ce-paragraph')
|
|
.first()
|
|
.then(($firstBlock) => {
|
|
const editorWindow = $firstBlock.get(0).ownerDocument.defaultView;
|
|
const selection = editorWindow.getSelection();
|
|
|
|
const range = selection.getRangeAt(0);
|
|
|
|
/**
|
|
* Check that second block contains range
|
|
*/
|
|
expect(range.startContainer.parentElement).to.equal($firstBlock.get(0));
|
|
});
|
|
});
|
|
|
|
it('should focus previous input if Block contains several inputs', () => {
|
|
cy.createEditor({
|
|
tools: {
|
|
toolWithTwoInputs: {
|
|
class: ToolWithTwoInputs,
|
|
},
|
|
},
|
|
data: {
|
|
blocks: [
|
|
{
|
|
type: 'paragraph',
|
|
data: {
|
|
text: 'second paragraph',
|
|
},
|
|
},
|
|
{
|
|
type: 'toolWithTwoInputs',
|
|
data: {},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
cy.get('[data-cy=tool-with-two-inputs]')
|
|
.find('[contenteditable=true]')
|
|
.last()
|
|
.click()
|
|
.trigger('keydown', {
|
|
keyCode: 9,
|
|
shiftKey: true,
|
|
})
|
|
.wait(CARET_MOVE_TIME);
|
|
|
|
cy.get('[data-cy=tool-with-two-inputs]')
|
|
.find('[contenteditable=true]')
|
|
.first()
|
|
.then(($firstInput) => {
|
|
const editorWindow = $firstInput.get(0).ownerDocument.defaultView;
|
|
const selection = editorWindow.getSelection();
|
|
|
|
const range = selection.getRangeAt(0);
|
|
|
|
/**
|
|
* Check that second block contains range
|
|
*/
|
|
expect(range.startContainer).to.equal($firstInput.get(0));
|
|
});
|
|
});
|
|
|
|
it('should highlight previous Block if it does not contain any inputs (contentless Block)', () => {
|
|
cy.createEditor({
|
|
tools: {
|
|
contentlessTool: {
|
|
class: ContentlessTool,
|
|
},
|
|
},
|
|
data: {
|
|
blocks: [
|
|
{
|
|
type: 'paragraph',
|
|
data: {
|
|
text: 'second paragraph',
|
|
},
|
|
},
|
|
{
|
|
type: 'contentlessTool',
|
|
data: {},
|
|
},
|
|
{
|
|
type: 'paragraph',
|
|
data: {
|
|
text: 'third paragraph',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
.find('.ce-paragraph')
|
|
.last()
|
|
.click()
|
|
.trigger('keydown', {
|
|
keyCode: 9,
|
|
shiftKey: true,
|
|
})
|
|
.wait(CARET_MOVE_TIME);
|
|
|
|
cy.get('[data-cy=contentless-tool]')
|
|
.parents('.ce-block')
|
|
.should('have.class', 'ce-block--selected');
|
|
});
|
|
|
|
it('should focus previous input before Editor when pressed in first Block', () => {
|
|
cy.createEditor({});
|
|
|
|
/**
|
|
* Add regular input before Editor
|
|
*/
|
|
cy.window()
|
|
.then((window) => {
|
|
const input = window.document.createElement('input');
|
|
|
|
input.setAttribute('data-cy', 'regular-input');
|
|
|
|
window.document.body.insertBefore(input, window.document.body.firstChild);
|
|
});
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
.find('.ce-paragraph')
|
|
.click()
|
|
.tab({ shift: true });
|
|
|
|
cy.get('[data-cy=regular-input]')
|
|
.should('have.focus');
|
|
});
|
|
});
|