Skip to content

Commit

Permalink
Fix a lot of bugs with backspace keypressing inside inline elements
Browse files Browse the repository at this point in the history
  • Loading branch information
xdan committed Feb 7, 2018
1 parent 67ab7e1 commit a8dd266
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 20 deletions.
5 changes: 4 additions & 1 deletion src/modules/Dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import * as consts from '../constants';
import {each, trim} from './Helpers'
import {css, each, trim} from './Helpers'
import {Jodit} from "../Jodit";

export class Dom {
Expand Down Expand Up @@ -210,6 +210,9 @@ export class Dom {
return (!!node && typeof node.nodeName === 'string' && consts.IS_BLOCK.test(node.nodeName));
}

static isInlineBlock(node: Node | null): boolean {
return !!node && node.nodeType === Node.ELEMENT_NODE && ['inline', 'inline-block'].indexOf(css(<HTMLElement>node, 'display').toString()) !== -1;
}
/**
* It's block and it can be split
*
Expand Down
25 changes: 12 additions & 13 deletions src/modules/Selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -547,10 +547,7 @@ export class Select extends Component{
}

range.collapse(false);
sel.removeAllRanges();
sel.addRange(range);

this.jodit.events.fire('changeSelection');
this.selectRange(range);

return fakeNode;
}
Expand Down Expand Up @@ -745,10 +742,7 @@ export class Select extends Component{
}

range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);

this.jodit.events.fire('changeSelection');
this.selectRange(range);

return fakeNode;
}
Expand Down Expand Up @@ -781,12 +775,17 @@ export class Select extends Component{
start = start[inStart ? 'firstChild' : 'lastChild'];
} while (start);

if (last === node && node.nodeType !== Node.TEXT_NODE) {
const fakeNode: Text = this.jodit.editorDocument.createTextNode(consts.INVISIBLE_SPACE);
node.appendChild(fakeNode);
last = fakeNode;
}

range.selectNodeContents(start || last);
range.collapse(inStart);
sel.removeAllRanges();
sel.addRange(range);
this.selectRange(range);

this.jodit.events.fire('changeSelection');
return last;
}

selectRange(range: Range) {
Expand Down Expand Up @@ -814,8 +813,8 @@ export class Select extends Component{
range: Range = this.jodit.editorDocument.createRange();

range[inward ? 'selectNodeContents' : 'selectNode'](node);
sel.removeAllRanges();
sel.addRange(range);

this.selectRange(range);
}


Expand Down
47 changes: 43 additions & 4 deletions src/plugins/backspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,21 @@ export function backspace(editor: Jodit) {

range.setStart(box.node, startOffset);
range.collapse(true);

let nextElement: Node | null = toLeft ? box.node.previousSibling : box.node.nextSibling;
editor.selection.selectRange(range);

let prevElement: Node | null = box.node;
let nextElement: Node | null = null;

do {
if (prevElement) {
nextElement = toLeft ? prevElement.previousSibling : prevElement.nextSibling;
if (!nextElement && prevElement.parentNode && prevElement.parentNode !== editor.editor && Dom.isInlineBlock(prevElement.parentNode)) {
prevElement = prevElement.parentNode;
} else {
break;
}
}
} while(!nextElement);

if (value.length) {
if (toLeft) {
Expand All @@ -80,6 +93,7 @@ export function backspace(editor: Jodit) {
}
range.setStart(box.node, startOffset - 1);
range.collapse(true);
editor.selection.selectRange(range);
return false;
}
} else {
Expand All @@ -90,22 +104,25 @@ export function backspace(editor: Jodit) {
}
range.setStart(box.node, startOffset);
range.collapse(true);
editor.selection.selectRange(range);
return false;
}
}
} else {
range.setStartBefore(box.node);
range.collapse(true);
editor.selection.selectRange(range);

box.node && box.node.parentNode && box.node.parentNode.removeChild(box.node);

box.node = nextElement;
}

if (nextElement) {
if (nextElement.nodeType === Node.ELEMENT_NODE && ['inline', 'inline-block'].indexOf(css(<HTMLElement>nextElement, 'display').toString()) !== -1) {
if (Dom.isInlineBlock(nextElement)) {
nextElement = toLeft ? nextElement.lastChild : nextElement.firstChild;
}

if (nextElement && nextElement.nodeType === Node.TEXT_NODE) {
box.node = nextElement;
return removeChar(box, toLeft, range);
Expand All @@ -118,6 +135,10 @@ export function backspace(editor: Jodit) {
if (event.which === consts.KEY_BACKSPACE || event.keyCode === consts.KEY_DELETE) {
const toLeft: boolean = event.which === consts.KEY_BACKSPACE;

if (!editor.selection.isFocused()) {
!editor.selection.focus();
}

if (!editor.selection.isCollapsed()) {
editor.execCommand('Delete');
return false;
Expand All @@ -129,17 +150,28 @@ export function backspace(editor: Jodit) {
if (!range) {
return false;
}

const fakeNode: Node = editor.ownerDocument.createTextNode(consts.INVISIBLE_SPACE);
const marker: HTMLElement = editor.editorDocument.createElement('span');

try {
range.insertNode(fakeNode);
if (!Dom.isOrContains(editor.editor, fakeNode)) {
return false;
}

let container: HTMLElement | null = <HTMLElement | null>Dom.up(fakeNode, Dom.isBlock, editor.editor);

let workElement: Node | null;
workElement = toLeft ? fakeNode.previousSibling : fakeNode.nextSibling;

while (workElement && Dom.isInlineBlock(workElement) && (!toLeft ? workElement.firstChild : workElement.lastChild)) {
workElement = !toLeft ? workElement.firstChild : workElement.lastChild;
}

if (workElement) {
const box = {node: workElement};

if (removeChar(box, toLeft, range) === false) {
return false;
}
Expand Down Expand Up @@ -174,7 +206,8 @@ export function backspace(editor: Jodit) {
box.parentNode && box.parentNode.insertBefore(prevBox, box);
}

prevBox && editor.selection.setCursorIn(prevBox, !toLeft);

prevBox && editor.selection.setCursorIn(prevBox, !toLeft) && editor.selection.insertNode(marker, false);

if (container) {
removeEmptyBlocks(container);
Expand Down Expand Up @@ -206,9 +239,15 @@ export function backspace(editor: Jodit) {

removeEmptyBlocks(container);


if (marker) {
editor.selection.setCursorBefore(marker);
}

return false;
}
} finally {
marker.parentNode && marker.parentNode.removeChild(marker);
fakeNode.parentNode && fakeNode.parentNode.removeChild(fakeNode);
}

Expand Down
25 changes: 24 additions & 1 deletion test/tests/enterTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,30 @@ describe('Enter behavior Jodit Editor Tests', function() {
'</tbody></table>').to.be.equal(editor.getEditorValue());
});
});
describe('inside some inline element', function () {
describe('in the start', function () {
it('Should move cursor befoer this element and delete char', function () {
var editor = new Jodit(appendTestArea())
editor.setEditorValue('te<strong>stop</strong>st');

var sel = editor.editorWindow.getSelection(),
range = editor.editorDocument.createRange();

range.selectNodeContents(editor.editor.querySelector('strong'));
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);

simulateEvent('keydown', Jodit.KEY_BACKSPACE, editor.editor);

expect('t<strong>stop</strong>st').to.be.equal(editor.getEditorValue());


editor.selection.insertNode(editor.editorDocument.createTextNode(' a '))
expect('t a <strong>stop</strong>st').to.be.equal(editor.getEditorValue());
})
});
});
describe('inside empty P', function () {
it('Should remove empty tag and set cursor in previous element', function () {
var editor = new Jodit(appendTestArea())
Expand Down Expand Up @@ -87,7 +110,7 @@ describe('Enter behavior Jodit Editor Tests', function() {
var sel = editor.editorWindow.getSelection(),
range = editor.editorDocument.createRange();

range.setStart(editor.editor.lastChild, 0);
range.setStartAfter(editor.editor.querySelector('span'));
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
Expand Down
2 changes: 1 addition & 1 deletion test/tests/pluginsTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ describe('Test plugins', function () {

editor.selection.insertHTML('stop');

expect('<p>stop</p><p><img src="https://xdsoft.net/jodit/images/artio.jpg" style="width: 100px; height: 100px;" alt=""></p>').to.be.equal(editor.getEditorValue());
expect('<p>stop</p><p><img alt="" src="https://xdsoft.net/jodit/images/artio.jpg" style="height:100px;width:100px"></p>').to.be.equal(sortAtrtibutes(editor.getEditorValue()));
});
});
});
Expand Down

0 comments on commit a8dd266

Please sign in to comment.