Skip to content

Commit

Permalink
Fix Backspacing in the editor with preadded styling or added styling …
Browse files Browse the repository at this point in the history
…is not retained #1120

Issue: #1120
  • Loading branch information
xdan committed May 11, 2024
1 parent 3b05074 commit d84f0bd
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 37 deletions.
14 changes: 9 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@
});
```

### :bug: Bug Fix

- [Backspacing in the editor with preadded styling or added styling is not retained #1120](https://github.com/xdan/jodit/issues/1120)

## 4.2.13

### :bug: Bug Fix
Expand Down Expand Up @@ -2674,11 +2678,11 @@ Related with https://github.com/xdan/jodit/issues/574. In some cases need to lim
- @property {IUIOption[]} link.selectOptionsClassName=[] The list of the option for the select (to use with
modeClassName="select")
- ex: [
- { value: "", text: "" },
- { value: "val1", text: "text1" },
- { value: "val2", text: "text2" },
- { value: "val3", text: "text3" }
- ]
- { value: "", text: "" },
- { value: "val1", text: "text1" },
- { value: "val2", text: "text2" },
- { value: "val3", text: "text3" }
- ]
PR: https://github.com/xdan/jodit/pull/577 Thanks @s-renier-taonix-fr
##### New option `statusbar: boolean = true`
Expand Down
1 change: 1 addition & 0 deletions public/stand.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ <h1>Jodit Test Document</h1>
const editor = Jodit.make('#editorNative', {
// shadowRoot: root,
// safeMode: true,
// disablePlugins: ['clean-html'],
// iframe: true,
// buttons: ['paragraph', 'align'],
// theme: 'dark',
Expand Down
103 changes: 72 additions & 31 deletions src/plugins/backspace/backspace.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ describe('Backspace/Delete key', function () {

describe('More cases', function () {
[
'<p>test</p><p><strong>p|</strong></p> => <p>test</p><p><strong>|</strong></p>',
'<p>test</p><p><a href="#">p|</a></p> => <p>test</p><p>|<br></p>',
'<p>test</p><p>|pop|</p><p>stop</p> => <p>test</p><p>|<br></p><p>stop</p>',
'<ul><li>test</li><li>|pop|</li><li>stop</li></ul> => <ul><li>test</li><li>|<br></li><li>stop</li></ul>',
'<blockquote>t|est</blockquote><ol><li>test2</li><li>te|st3</li><li><a>test4</a></li></ol> => <blockquote>t|</blockquote><ol><li>st3</li><li><a>test4</a></li></ol>',
Expand Down Expand Up @@ -78,41 +80,46 @@ describe('Backspace/Delete key', function () {
].forEach(function (pars) {
const [key, value, button, options, insert] = pars.split(' => ');

describe(`For key "${key}"`, function () {
it(`Should be ${value}`, async () => {
let jodit = editor;
describe(
`For key "${key}"` +
(options ? ' with options: ' + options : ''),
function () {
it(`Should be ${value}`, async () => {
let jodit = editor;

if (options) {
editor.destruct();
if (options) {
editor.destruct();

jodit = getJodit(
(options && JSON.parse(options)) || {},
area
);
}
jodit = getJodit(
(options && JSON.parse(options)) || {},
area
);
}

jodit.value = key;
setCursorToChar(jodit);
simulateEvent(
'keydown',
button || Jodit.KEY_BACKSPACE,
jodit.editor
);
jodit.value = key;
setCursorToChar(jodit);
simulateEvent(
'keydown',
button || Jodit.KEY_BACKSPACE,
jodit.editor
);

if (insert) {
await jodit.async.requestIdlePromise();
jodit.s.insertNode(jodit.createInside.text(insert));
}

replaceCursorToChar(jodit);
expect(
sortAttributes(jodit.value).replace(
/<span style="background-color:var\(--jd-color-background-default\)">([^<]+?)<\/span>/,
'$1'
)
).equals(value);
});
});
if (insert) {
jodit.s.insertNode(jodit.createInside.text(insert));
}

replaceCursorToChar(jodit);
expect(
sortAttributes(jodit.value).replace(
/<span style="background-color:var\(--jd-color-background-default\)">([^<]+?)<\/span>/,
'$1'
)
).equals(value);
});
}
);
});
});

Expand Down Expand Up @@ -882,8 +889,8 @@ describe('Backspace/Delete key', function () {
});

describe('after last char inside tag', function () {
describe('inside A', function () {
it('Should remove empty tag and set cursor in a previous element', function () {
describe('inside A', () => {
it('Should remove empty tag and set cursor in a previous element', () => {
editor.value = '<p><a href="#test">t|</a></p>';
setCursorToChar(editor);

Expand All @@ -893,6 +900,40 @@ describe('Backspace/Delete key', function () {
});
});

describe('inside STRONG', () => {
beforeEach(async () => {
editor.value = '<p><strong>t|</strong></p>';
setCursorToChar(editor);

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

await editor.async.requestIdlePromise();
});

it('Should stay inside empty tag', async () => {
replaceCursorToChar(editor);
expect(editor.value).equals('<p><strong>|</strong></p>');

// INVISIBLE_SPACE
expect(editor.getNativeEditorValue()).equals(
'<p><strong>\ufeff|</strong></p>'
);
});

describe('After enter text. This strong', () => {
it('Should have only that text', async () => {
editor.s.insertNode(editor.createInside.text(' a '));
await waitingForEvent(editor, 'finishedCleanHTMLWorker');
replaceCursorToChar(editor);
expect(editor.value).equals('<p><strong> a |</strong></p>');
// TODO: May be sometimes. Need fix clean-html.remove-inv-text-nodes
// expect(editor.getNativeEditorValue()).equals(
// '<p><strong> a |</strong></p>'
// );
});
});
});

describe('inside P', function () {
it('Should not remove empty tag', function () {
editor.value = '<p>r</p><p>t</p>';
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/backspace/cases/check-remove-char.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ export function checkRemoveChar(

if (sibling.nodeValue?.length) {
removed = tryRemoveChar(sibling, backspace, step, anotherSibling);

if (
!sibling.nodeValue.length &&
Dom.isInlineBlock(sibling.parentNode)
) {
sibling.nodeValue = INVISIBLE_SPACE;
}
}

if (!sibling.nodeValue?.length) {
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/clean-html/clean-html.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

describe('Clean html plugin', function () {
describe('Exec bold for collapsed range and move cursor in another place', () => {
it('Should remove STRONG element', async () => {
it('Should remove empty STRONG element', async () => {
const editor = getJodit({
cleanHTML: {
timeout: 0
Expand Down
21 changes: 21 additions & 0 deletions test/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,27 @@ function delay(timeout) {
});
}

/**
* Waiting for Jodit event. If event not fired in timeout - resolve
*
* @param {IJodit} editor
* @param {string} event
* @param {number} [timeout]
* @returns {Promise<void>}
*/
function waitingForEvent(editor, event, timeout = 1000) {
return new naturalPromise(resolve => {
editor.e.one(event, resolve);

if (timeout) {
setTimeout(() => {
editor.e.off(event, handler);
resolve();
}, timeout);
}
});
}

function idle() {
return new naturalPromise(resolve => {
typeof requestIdleCallback === 'function'
Expand Down

0 comments on commit d84f0bd

Please sign in to comment.