Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit d17a8f6

Browse files
committed
[IMP] *: improved performance of plugins using memory
1 parent c544c12 commit d17a8f6

File tree

56 files changed

+281
-158
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+281
-158
lines changed

packages/core/src/VNodes/AbstractNode.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { VNode, RelativePosition, Predicate, Typeguard, isLeaf } from './VNode';
1+
import { VNode, RelativePosition, Predicate, isLeaf } from './VNode';
22
import {
33
Constructor,
44
nodeLength,
@@ -143,20 +143,6 @@ export abstract class AbstractNode extends EventMixin {
143143
get length(): number {
144144
return this.children().length;
145145
}
146-
/**
147-
* Return whether this node is an instance of the given VNode class.
148-
*
149-
* @param predicate The subclass of VNode to test this node against.
150-
*/
151-
is<T extends VNode>(predicate: Constructor<T> | Typeguard<T>): this is T;
152-
is(predicate: Predicate): false;
153-
is(predicate: Predicate): boolean {
154-
if (AbstractNode.isConstructor(predicate)) {
155-
return this instanceof predicate;
156-
} else {
157-
return predicate(this as VNode);
158-
}
159-
}
160146
/**
161147
* Test this node against the given predicate.
162148
*
@@ -730,6 +716,7 @@ export abstract class AbstractNode extends EventMixin {
730716
return __repr;
731717
}
732718
}
719+
733720
export interface AbstractNode {
734721
constructor: new <T extends Constructor<VNode>>(...args: ConstructorParameters<T>) => this;
735722
}

packages/core/src/VNodes/ContainerNode.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@ export class ContainerNode extends AbstractNode {
1616
children<T extends VNode>(predicate?: Predicate<T>): T[];
1717
children(predicate?: Predicate): VNode[];
1818
children(predicate?: Predicate): VNode[] {
19-
return this.childVNodes.filter(child => {
20-
return child.tangible && child.test(predicate);
19+
const children: VNode[] = [];
20+
this.childVNodes.forEach(child => {
21+
if (child.tangible && (!predicate || child.test(predicate))) {
22+
children.push(child);
23+
}
2124
});
25+
return children;
2226
}
2327
/**
2428
* See {@link AbstractNode.hasChildren}.
2529
*/
2630
hasChildren(): boolean {
27-
return this.children().length > 0;
31+
return !!this.childVNodes.find(child => child.tangible);
2832
}
2933
/**
3034
* See {@link AbstractNode.nthChild}.
@@ -39,7 +43,7 @@ export class ContainerNode extends AbstractNode {
3943
firstChild(predicate?: Predicate): VNode;
4044
firstChild(predicate?: Predicate): VNode {
4145
let child = this.childVNodes[0];
42-
while (child && !(child.tangible && child.test(predicate))) {
46+
while (child && !(child.tangible && (!predicate || child.test(predicate)))) {
4347
child = child.nextSibling();
4448
}
4549
return child;
@@ -51,7 +55,7 @@ export class ContainerNode extends AbstractNode {
5155
lastChild(predicate?: Predicate): VNode;
5256
lastChild(predicate?: Predicate): VNode {
5357
let child = this.childVNodes[this.childVNodes.length - 1];
54-
while (child && !(child.tangible && child.test(predicate))) {
58+
while (child && !(child.tangible && (!predicate || child.test(predicate)))) {
5559
child = child.previousSibling();
5660
}
5761
return child;
@@ -63,7 +67,7 @@ export class ContainerNode extends AbstractNode {
6367
firstLeaf(predicate?: Predicate): VNode;
6468
firstLeaf(predicate?: Predicate): VNode {
6569
const isValidLeaf = (node: VNode): boolean => {
66-
return isLeaf(node) && node.test(predicate);
70+
return isLeaf(node) && (!predicate || node.test(predicate));
6771
};
6872
if (isValidLeaf(this)) {
6973
return this;
@@ -78,7 +82,7 @@ export class ContainerNode extends AbstractNode {
7882
lastLeaf(predicate?: Predicate): VNode;
7983
lastLeaf(predicate?: Predicate): VNode {
8084
const isValidLeaf = (node: VNode): boolean => {
81-
return isLeaf(node) && node.test(predicate);
85+
return isLeaf(node) && (!predicate || node.test(predicate));
8286
};
8387
if (isValidLeaf(this)) {
8488
return this;
@@ -93,7 +97,7 @@ export class ContainerNode extends AbstractNode {
9397
firstDescendant(predicate?: Predicate): VNode;
9498
firstDescendant(predicate?: Predicate): VNode {
9599
let firstDescendant = this.firstChild();
96-
while (firstDescendant && !firstDescendant.test(predicate)) {
100+
while (firstDescendant && predicate && !firstDescendant.test(predicate)) {
97101
firstDescendant = this._descendantAfter(firstDescendant);
98102
}
99103
return firstDescendant;
@@ -108,7 +112,7 @@ export class ContainerNode extends AbstractNode {
108112
while (lastDescendant && lastDescendant.hasChildren()) {
109113
lastDescendant = lastDescendant.lastChild();
110114
}
111-
while (lastDescendant && !lastDescendant.test(predicate)) {
115+
while (lastDescendant && predicate && !lastDescendant.test(predicate)) {
112116
lastDescendant = this._descendantBefore(lastDescendant);
113117
}
114118
return lastDescendant;
@@ -123,7 +127,7 @@ export class ContainerNode extends AbstractNode {
123127
const stack = [...this.childVNodes];
124128
while (stack.length) {
125129
const node = stack.shift();
126-
if (node.tangible && node.test(predicate)) {
130+
if (node.tangible && (!predicate || node.test(predicate))) {
127131
descendants.push(node);
128132
}
129133
if (node instanceof ContainerNode) {
@@ -226,9 +230,11 @@ export class ContainerNode extends AbstractNode {
226230
return this;
227231
}
228232
const duplicate = this.clone();
229-
const index = child.parent.childVNodes.indexOf(child);
230-
while (this.childVNodes.length > index) {
231-
duplicate.append(this.childVNodes[index]);
233+
const index = this.childVNodes.indexOf(child);
234+
const children = this.childVNodes.splice(index);
235+
duplicate.childVNodes.push(...children);
236+
for (const child of children) {
237+
child.parent = duplicate;
232238
}
233239
this.after(duplicate);
234240
return duplicate;

packages/core/src/VRange.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ export class VRange {
240240
} else if (position === RelativePosition.AFTER) {
241241
reference = reference.lastLeaf();
242242
}
243-
if (reference.is(ContainerNode) && !reference.hasChildren()) {
243+
if (reference instanceof ContainerNode && !reference.hasChildren()) {
244244
reference.prepend(this.start);
245245
} else if (position === RelativePosition.AFTER && reference !== this.end) {
246246
// We check that `reference` isn't `this.end` to avoid a backward
@@ -266,7 +266,7 @@ export class VRange {
266266
} else if (position === RelativePosition.AFTER) {
267267
reference = reference.lastLeaf();
268268
}
269-
if (reference.is(ContainerNode) && !reference.hasChildren()) {
269+
if (reference instanceof ContainerNode && !reference.hasChildren()) {
270270
reference.append(this.end);
271271
} else if (position === RelativePosition.BEFORE && reference !== this.start) {
272272
// We check that `reference` isn't `this.start` to avoid a backward
@@ -366,7 +366,7 @@ export class VRange {
366366
empty(): void {
367367
const removableNodes = this.selectedNodes(node => {
368368
// TODO: Replace Table check with complex table selection support.
369-
return this.mode.is(node, RuleProperty.EDITABLE) && !node.is(TableCellNode);
369+
return this.mode.is(node, RuleProperty.EDITABLE) && !(node instanceof TableCellNode);
370370
});
371371
// Remove selected nodes without touching the start range's ancestors.
372372
const startAncestors = this.start.ancestors();

packages/plugin-blockquote/src/BlockquoteXmlDomParser.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ export class BlockquoteXmlDomParser extends AbstractParser<Node> {
1313

1414
async parse(item: Element): Promise<BlockquoteNode[]> {
1515
const blockquote = new BlockquoteNode();
16-
blockquote.modifiers.append(this.engine.parseAttributes(item));
16+
const attributes = this.engine.parseAttributes(item);
17+
if (attributes.length) {
18+
blockquote.modifiers.append(attributes);
19+
}
1720
const nodes = await this.engine.parse(...item.childNodes);
1821
blockquote.append(...nodes);
1922
return [blockquote];

packages/plugin-bold/src/BoldXmlDomParser.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ export class BoldXmlDomParser extends FormatXmlDomParser {
1515
*/
1616
async parse(item: Element): Promise<VNode[]> {
1717
const bold = new BoldFormat(nodeName(item) as 'B' | 'STRONG');
18-
bold.modifiers.append(this.engine.parseAttributes(item));
18+
const attributes = this.engine.parseAttributes(item);
19+
if (attributes.length) {
20+
bold.modifiers.append(attributes);
21+
}
1922
const children = await this.engine.parse(...item.childNodes);
2023
this.applyFormat(bold, children);
2124

packages/plugin-char/src/Char.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,18 @@ export class Char<T extends JWPluginConfig = JWPluginConfig> extends JWPlugin<T>
5050
let modifiers = inline.getCurrentModifiers(range);
5151
// Ony preserved modifiers are applied at the start of a container.
5252
const previousSibling = range.start.previousSibling();
53-
if (!previousSibling) {
54-
modifiers = new Modifiers(...modifiers.filter(mod => mod.preserve));
53+
if (!previousSibling && modifiers) {
54+
const preservedModifiers = modifiers.filter(mod => mod.preserve);
55+
if (preservedModifiers.length) {
56+
modifiers = new Modifiers(...preservedModifiers);
57+
} else {
58+
modifiers = null;
59+
}
5560
}
5661
if (params.formats) {
62+
if (!modifiers) {
63+
modifiers = new Modifiers();
64+
}
5765
modifiers.set(...params.formats.map(format => format.clone()));
5866
}
5967
const style = inline.getCurrentStyle(range);
@@ -64,17 +72,20 @@ export class Char<T extends JWPluginConfig = JWPluginConfig> extends JWPlugin<T>
6472
// Split the text into CHAR nodes and insert them at the range.
6573
const characters = text.split('');
6674
const charNodes = characters.map(char => {
67-
return new CharNode({ char: char, modifiers: modifiers.clone() });
75+
if (modifiers) {
76+
return new CharNode({ char: char, modifiers: modifiers.clone() });
77+
} else {
78+
return new CharNode({ char: char });
79+
}
6880
});
6981
charNodes.forEach(charNode => {
70-
if (style.length) {
82+
if (style?.length) {
7183
charNode.modifiers.get(Attributes).style = style;
7284
}
7385
range.start.before(charNode);
7486
});
7587
if (params.select && charNodes.length) {
7688
this.editor.selection.select(charNodes[0], charNodes[charNodes.length - 1]);
7789
}
78-
inline.resetCache();
7990
}
8091
}

packages/plugin-char/src/CharDomObjectRenderer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ export class CharDomObjectRenderer extends NodeRenderer<DomObject> {
4343
// Render block edge spaces as non-breakable space (otherwise browsers
4444
// won't render them).
4545
const previous = charNodes[0].previousSibling();
46-
if (!previous || !previous.is(InlineNode)) {
46+
if (!previous || !(previous instanceof InlineNode)) {
4747
texts[0] = texts[0].replace(/^ /g, '\u00A0');
4848
}
4949
const next = charNodes[charNodes.length - 1].nextSibling();
50-
if (!next || !next.is(InlineNode)) {
50+
if (!next || !(next instanceof InlineNode)) {
5151
texts[texts.length - 1] = texts[texts.length - 1].replace(/^ /g, '\u00A0');
5252
}
5353
const textObject = { text: texts.join('') };

packages/plugin-color/src/Color.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export class Color<T extends ColorConfig = ColorConfig> extends JWPlugin<T> {
109109
// Uncolor the children and their formats as well.
110110
for (const child of node.children()) {
111111
child.modifiers.find(Attributes)?.style.remove(this.styleName);
112-
if (child.is(InlineNode)) {
112+
if (child instanceof InlineNode) {
113113
for (const format of child.modifiers.filter(Format)) {
114114
format.modifiers.find(Attributes)?.style.remove(this.styleName);
115115
}

packages/plugin-devtools/src/components/InfoComponent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ export class InfoComponent extends OwlComponent<{}> {
5050
propRepr(vNode: VNode, propName: string): string {
5151
let prop = vNode[propName];
5252
if (propName === 'atomic') {
53-
if (vNode.is(AtomicNode)) {
53+
if (vNode instanceof AtomicNode) {
5454
return 'true';
55-
} else if (vNode.is(ContainerNode)) {
55+
} else if (vNode instanceof ContainerNode) {
5656
return 'false';
5757
} else {
5858
return '?';

packages/plugin-devtools/src/components/InspectorComponent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ export class InspectorComponent extends OwlComponent<InspectorComponentProps> {
222222
nodes = this.domEngine.getNodes(node);
223223
node = node.parentNode;
224224
}
225-
if (nodes.length && nodes[0].is(CharNode) && nodes[caretPosition.offset]) {
225+
if (nodes[0] instanceof CharNode && nodes[caretPosition.offset]) {
226226
return [nodes[caretPosition.offset]];
227227
}
228228
return nodes;

0 commit comments

Comments
 (0)