Skip to content

Commit

Permalink
Fix applyDelta with block embed
Browse files Browse the repository at this point in the history
  • Loading branch information
luin committed May 24, 2023
1 parent 1a14922 commit ff61c6e
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 28 deletions.
46 changes: 33 additions & 13 deletions core/editor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import cloneDeep from 'lodash.clonedeep';
import isEqual from 'lodash.isequal';
import merge from 'lodash.merge';
import { LeafBlot, Scope } from 'parchment';
import { LeafBlot, EmbedBlot, Scope } from 'parchment';
import Delta, { AttributeMap, Op } from 'quill-delta';
import Block, { BlockEmbed, bubbleFormats } from '../blots/block';
import Break from '../blots/break';
Expand Down Expand Up @@ -30,17 +30,17 @@ class Editor {
normalizedDelta.reduce((index, op) => {
const length = Op.length(op);
let attributes = op.attributes || {};
let addedNewline = false;
let isImplicitNewlinePrepended = false;
let isImplicitNewlineAppended = false;
if (op.insert != null) {
deleteDelta.retain(length);
if (typeof op.insert === 'string') {
const text = op.insert;
// @ts-expect-error TODO: Fix this the next time the file is edited.
addedNewline =
isImplicitNewlineAppended =
!text.endsWith('\n') &&
(scrollLength <= index ||
// @ts-expect-error
this.scroll.descendant(BlockEmbed, index)[0]);
!!this.scroll.descendant(BlockEmbed, index)[0]);
this.scroll.insertAt(index, text);
const [line, offset] = this.scroll.line(index);
let formats = merge({}, bubbleFormats(line));
Expand All @@ -53,12 +53,30 @@ class Editor {
} else if (typeof op.insert === 'object') {
const key = Object.keys(op.insert)[0]; // There should only be one key
if (key == null) return index;
// @ts-expect-error TODO: Fix this the next time the file is edited.
addedNewline =
this.scroll.query(key, Scope.INLINE) != null &&
(scrollLength <= index ||
const isInlineEmbed = this.scroll.query(key, Scope.INLINE) != null;
if (isInlineEmbed) {
if (
scrollLength <= index ||
// @ts-expect-error
this.scroll.descendant(BlockEmbed, index)[0]);
!!this.scroll.descendant(BlockEmbed, index)[0]
) {
isImplicitNewlineAppended = true;
}
} else if (index > 0) {
// @ts-expect-error
const [leaf, offset] = this.scroll.descendant(LeafBlot, index - 1);
if (leaf instanceof TextBlot) {
const text = leaf.value();
if (text[offset] !== '\n') {
isImplicitNewlinePrepended = true;
}
} else if (
leaf instanceof EmbedBlot &&
leaf.statics.scope === Scope.INLINE_BLOT
) {
isImplicitNewlinePrepended = true;
}
}
this.scroll.insertAt(index, key, op.insert[key]);
}
scrollLength += length;
Expand All @@ -74,10 +92,12 @@ class Editor {
Object.keys(attributes).forEach(name => {
this.scroll.formatAt(index, length, name, attributes[name]);
});
const addedLength = addedNewline ? 1 : 0;
scrollLength += addedLength;
const prependedLength = isImplicitNewlinePrepended ? 1 : 0;
const addedLength = isImplicitNewlineAppended ? 1 : 0;
scrollLength += prependedLength + addedLength;
deleteDelta.retain(prependedLength);
deleteDelta.delete(addedLength);
return index + length + addedLength;
return index + length + prependedLength + addedLength;
}, 0);
deleteDelta.reduce((index, op) => {
if (typeof op.delete === 'number') {
Expand Down
95 changes: 80 additions & 15 deletions test/unit/core/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -603,22 +603,87 @@ describe('Editor', function() {
);
});

it('improper block embed insert', function() {
const editor = this.initialize(Editor, '<p>0123</p>');
editor.applyDelta(new Delta().retain(2).insert({ video: '#' }));
expect(this.container).toEqualHTML(
'<p>01</p><iframe src="#" class="ql-video" frameborder="0" allowfullscreen="true"></iframe><p>23</p>',
);
});
describe('block embed', function() {
it('improper block embed insert', function() {
const editor = this.initialize(Editor, '<p>0123</p>');
editor.applyDelta(new Delta().retain(2).insert({ video: '#' }));
expect(this.container).toEqualHTML(
'<p>01</p><iframe src="#" class="ql-video" frameborder="0" allowfullscreen="true"></iframe><p>23</p>',
);
});

it('append formatted block embed', function() {
const editor = this.initialize(Editor, '<p>0123</p><p><br></p>');
editor.applyDelta(
new Delta().retain(5).insert({ video: '#' }, { align: 'right' }),
);
expect(this.container).toEqualHTML(
'<p>0123</p><iframe src="#" class="ql-video ql-align-right" frameborder="0" allowfullscreen="true"></iframe><p><br></p>',
);
describe('insert and delete', function() {
it('prepend', function() {
const editor = this.initialize(Editor, '<p>0123</p>');
editor.applyDelta(new Delta().insert({ video: '#' }).delete(2));
expect(this.container).toEqualHTML(
'<iframe src="#" class="ql-video" frameborder="0" allowfullscreen="true"></iframe><p>23</p>',
);
});


it('insert to the middle of text', function() {
const editor = this.initialize(Editor, `<p>abc</p>`);
editor.applyDelta(
new Delta()
.retain(1)
.insert({ video: '#' })
.delete(2),
);
expect(this.container).toEqualHTML(
'<p>a</p><iframe class="ql-video" frameborder="0" allowfullscreen="true" src="#"></iframe><p><br></p>',
);
});

it('insert after \\n', function() {
const editor = this.initialize(Editor, `<p>a</p><p>cda</p>`);
editor.applyDelta(
new Delta()
.retain(2)
.insert({ video: '#' })
.delete(2),
);
expect(this.container).toEqualHTML(
'<p>a</p><iframe class="ql-video" frameborder="0" allowfullscreen="true" src="#"></iframe><p>a</p>',
);
});

it('insert after an inline embed', function() {
const editor = this.initialize(Editor, `<p><img src="/assets/favicon.png"></p><p>abc</p>`);
editor.applyDelta(
new Delta()
.retain(1)
.insert({ video: '#' })
.delete(2),
);
expect(this.container).toEqualHTML(
'<p><img src="/assets/favicon.png"></p><iframe class="ql-video" frameborder="0" allowfullscreen="true" src="#"></iframe><p>bc</p>',
);
});

it('insert after a block embed', function() {
const editor = this.initialize(Editor, `<iframe class="ql-video" frameborder="0" allowfullscreen="true" src="#"></iframe><p>abc</p>`);
editor.applyDelta(
new Delta()
.retain(1)
.insert({ video: '#' })
.delete(2),
);
expect(this.container).toEqualHTML(
'<iframe class="ql-video" frameborder="0" allowfullscreen="true" src="#"></iframe><iframe class="ql-video" frameborder="0" allowfullscreen="true" src="#"></iframe><p>c</p>',
);
});
});

it('append formatted block embed', function() {
const editor = this.initialize(Editor, '<p>0123</p><p><br></p>');
editor.applyDelta(
new Delta().retain(5).insert({ video: '#' }, { align: 'right' }),
);
expect(this.container).toEqualHTML(
'<p>0123</p><iframe src="#" class="ql-video ql-align-right" frameborder="0" allowfullscreen="true"></iframe><p><br></p>',
);
});
});

it('append', function() {
Expand Down

0 comments on commit ff61c6e

Please sign in to comment.