Skip to content

Commit

Permalink
add insertContents for scroll and block
Browse files Browse the repository at this point in the history
  • Loading branch information
jhchen authored and luin committed Jun 30, 2023
1 parent 8fa962d commit 0c6c032
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 3 deletions.
27 changes: 26 additions & 1 deletion blots/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
LeafBlot,
Scope,
} from 'parchment';
import Delta from 'quill-delta';
import Delta, { AttributeMap, Op } from 'quill-delta';
import Break from './break';
import Inline from './inline';
import TextBlot from './text';
Expand Down Expand Up @@ -82,6 +82,31 @@ class Block extends BlockBlot {
this.cache = {};
}

// TODO: Either handle \n in deltas or move insertAt splitting responsibility to scroll
insertContents(index: number, delta: Delta) {
delta.reduce((index: number, op: Op) => {
const length = Op.length(op);
let attributes = op.attributes || {};
if (op.insert != null) {
if (typeof op.insert === 'string') {
const text = op.insert;
this.insertAt(index, text);
const [leaf] = this.descendant(LeafBlot, index);
const formats = bubbleFormats(leaf);
attributes = AttributeMap.diff(formats, attributes) || {};
} else if (typeof op.insert === 'object') {
const key = Object.keys(op.insert)[0]; // There should only be one key
if (key == null) return index;
this.insertAt(index, key, op.insert[key]);
}
}
Object.keys(attributes).forEach(name => {
this.formatAt(index, length, name, attributes[name]);
});
return index + length;
}, index);
}

length() {
if (this.cache.length == null) {
this.cache.length = super.length() + NEWLINE_LENGTH;
Expand Down
57 changes: 57 additions & 0 deletions blots/scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Scope,
ScrollBlot,
} from 'parchment';
import Delta, { AttributeMap } from 'quill-delta';
import Emitter, { EmitterSource } from '../core/emitter';
import Block, { BlockEmbed } from './block';
import Break from './break';
Expand All @@ -25,6 +26,20 @@ function isUpdatable(blot: Blot): blot is Blot & UpdatableEmbed {
return typeof (blot as unknown as any).updateContent === 'function';
}

function deltaToLines(delta: Delta) {
const lines: { delta: Delta; attributes: AttributeMap }[] = [];
// eachLine can't tell if we end in newline or not
// add trailing newline to differentiate
// 'hello\nworld' -> ['hello', 'world']
// 'hello\nworld\n' -> ['hello', 'world', '']

// TODO: insert() here modifies original delta
delta.insert('\n').eachLine((lineDelta, attributes) => {
lines.push({ delta: lineDelta, attributes });
});
return lines;
}

class Scroll extends ScrollBlot {
static blotName = 'scroll';
static className = 'ql-editor';
Expand Down Expand Up @@ -137,6 +152,48 @@ class Scroll extends ScrollBlot {
}
}

insertContents(index: number, delta: Delta) {
const [child, offset] = this.children.find(index);
if (child == null) return;
const lines = deltaToLines(delta);
const first = lines.shift();
if (first == null) return;
this.batchStart();
// @ts-ignore
child.insertContents(offset, first.delta);
const last = lines.pop();
let after;
if (last != null) {
after = child.split(offset + first.delta.length());
Object.keys(first.attributes).forEach(name => {
// @ts-ignore
child.format(name, first.attributes[name]);
});
after.insertContents(0, last.delta);
}

lines.forEach(({ delta: lineDelta, attributes }) => {
const blockAttribute = Object.keys(attributes).find(
key =>
this.query(
key,
// eslint-disable-next-line no-bitwise
Scope.BLOCK & Scope.BLOT,
) != null,
);
const block = this.create(
blockAttribute || this.statics.defaultChild.blotName,
blockAttribute ? attributes[blockAttribute] : undefined,
);
// @ts-ignore
block.insertContents(0, lineDelta);
this.insertBefore(block, after);
});

this.batchEnd();
this.optimize();
}

isEnabled() {
return this.domNode.getAttribute('contenteditable') === 'true';
}
Expand Down
6 changes: 6 additions & 0 deletions core/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ class Editor {
.join('');
}

insertContents(index: number, contents: Delta): Delta {
const change = new Delta().retain(index).concat(contents);
this.scroll.insertContents(index, contents);
return this.update(change);
}

insertEmbed(index: number, embed: string, value: unknown): Delta {
this.scroll.insertAt(index, embed, value);
return this.update(new Delta().retain(index).insert({ [embed]: value }));
Expand Down
3 changes: 1 addition & 2 deletions core/quill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,7 @@ class Quill {
const length = this.getLength();
// Quill will set empty editor to \n
const delete1 = this.editor.deleteText(0, length);
// delta always applied before existing content
const applied = this.editor.applyDelta(delta);
const applied = this.editor.insertContents(0, delta);
// Remove extra \n from empty editor initialization
const delete2 = this.editor.deleteText(this.getLength() - 1, 1);
return delete1.compose(applied).compose(delete2);
Expand Down

0 comments on commit 0c6c032

Please sign in to comment.