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

Commit 03b072f

Browse files
committed
memory integration
1 parent 3ab4dd2 commit 03b072f

File tree

24 files changed

+372
-128
lines changed

24 files changed

+372
-128
lines changed

packages/core/src/JWEditor.ts

+32
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import { ModeError } from '../../utils/src/errors';
99
import { ContainerNode } from './VNodes/ContainerNode';
1010
import { AtomicNode } from './VNodes/AtomicNode';
1111
import { SeparatorNode } from './VNodes/SeparatorNode';
12+
import { Memory } from './Memory/Memory';
13+
import { makeVersionable } from './Memory/Versionable';
14+
import { VersionableArray } from './Memory/VersionableArray';
1215

1316
export enum Mode {
1417
CONFIGURATION = 'configuration',
@@ -57,6 +60,9 @@ export class JWEditor {
5760
plugins: [],
5861
loadables: {},
5962
};
63+
memory: Memory;
64+
memoryID = 0;
65+
private memoryInfo: { commandNames: string[] };
6066
selection = new VSelection();
6167
loaders: Record<string, Loader> = {};
6268
private mutex = Promise.resolve();
@@ -94,9 +100,18 @@ export class JWEditor {
94100
}
95101
}
96102

103+
// create memory
104+
this.memoryInfo = makeVersionable({ commandNames: [] });
105+
this.memory = new Memory();
106+
this.memory.linkToMemory(this.memoryInfo);
107+
97108
for (const plugin of this.plugins.values()) {
98109
await plugin.start();
99110
}
111+
112+
// create the next memory slice (and freeze the current memory)
113+
this.memoryID++;
114+
this.memory.create(this.memoryID.toString());
100115
}
101116

102117
//--------------------------------------------------------------------------
@@ -277,7 +292,24 @@ export class JWEditor {
277292
commandName: C,
278293
params?: CommandParams<P, C>,
279294
): Promise<void> {
295+
const isFrozen = !this.memoryID || this.memory.isFrozen();
296+
if (isFrozen) {
297+
// switch to the next memory slice (unfreeze the memory)
298+
this.memory.switchTo(this.memoryID.toString());
299+
this.memoryInfo.commandNames = new VersionableArray<string>();
300+
}
301+
this.memoryInfo.commandNames.push(commandName);
302+
303+
// TODO:
304+
// create memory for each plugin who use the command then
305+
// use squashInto(winnerSliceKey, winnerSliceKey, newMasterSliceKey)
280306
await this.dispatcher.dispatch(commandName, params);
307+
308+
if (isFrozen) {
309+
// create the next memory slice (and freeze the current memory)
310+
this.memoryID++;
311+
this.memory.create(this.memoryID.toString());
312+
}
281313
}
282314

283315
/**

packages/core/src/Memory/test/memory.perf.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ describe('test performances', () => {
309309
}
310310
}
311311

312-
console.log(
312+
console.info(
313313
'Time to load ' +
314314
nodesNb +
315315
' nodes and ' +
@@ -323,7 +323,7 @@ describe('test performances', () => {
323323
const d2 = Date.now();
324324
readAll(section);
325325
const dt2 = Date.now() - d2;
326-
console.log(
326+
console.info(
327327
'Time to re-load ' +
328328
nodesNb +
329329
' nodes and ' +
@@ -389,7 +389,7 @@ describe('test performances', () => {
389389
}
390390
const dt = Date.now() - d;
391391

392-
console.log(
392+
console.info(
393393
'Time to create ' +
394394
(ID - nodeInti) +
395395
' nodes and ' +
@@ -408,15 +408,15 @@ describe('test performances', () => {
408408
memory.switchTo('1-2');
409409
memory.switchTo('1-3-1');
410410
const dt = Date.now() - d;
411-
console.log('Time to switch memory', dt);
411+
console.info('Time to switch memory', dt);
412412
expect(dt).to.lessThan(50);
413413
});
414414
it('Should read the nodes the first time in minimum time', () => {
415415
memory.switchTo('1-3-1');
416416
const d = Date.now();
417417
readAll(root);
418418
const dt = Date.now() - d;
419-
console.log('Time to load nodes', dt);
419+
console.info('Time to load nodes', dt);
420420
expect(dt).to.lessThan(250);
421421
});
422422
it('Should read the nodes in minimum time', () => {
@@ -426,15 +426,15 @@ describe('test performances', () => {
426426
const nodes = readAll(root);
427427
const dt = Date.now() - d;
428428
times.push(dt);
429-
console.log('Time to re-load nodes', dt);
429+
console.info('Time to re-load nodes', dt);
430430

431431
for (let k = 0; k < 5; k++) {
432432
const d = Date.now();
433433
// nodes.forEach(read);
434434
readAll(root);
435435
const dt = Date.now() - d;
436436
times.push(dt);
437-
console.log('Time to re-load nodes', dt);
437+
console.info('Time to re-load nodes', dt);
438438
}
439439

440440
let nodesNb = 0;
@@ -447,7 +447,7 @@ describe('test performances', () => {
447447
}
448448
});
449449
const average = Math.round(times.reduce((a, b) => a + b) / times.length);
450-
console.log(
450+
console.info(
451451
're-load ' + nodesNb + ' nodes and ' + chars + ' chars time average',
452452
average,
453453
);

packages/core/src/Memory/test/memory.test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ describe('core', () => {
842842
expect(array.indexOf(-3)).to.equal(3);
843843
});
844844
it('array indexOf value several times', () => {
845-
const array = new VersionableArray(0, 1, 2, 3, 1, 4);
845+
const array = new VersionableArray<number>(0, 1, 2, 3, 1, 4);
846846
const memory = new Memory();
847847
memory.create('test');
848848
memory.switchTo('test');
@@ -1294,7 +1294,7 @@ describe('core', () => {
12941294
});
12951295
it('default value for array', () => {
12961296
const memory = new Memory();
1297-
const array = new VersionableArray(1, 2, 3, 4, 5);
1297+
const array = new VersionableArray<number>(1, 2, 3, 4, 5);
12981298
memory.linkToMemory(array);
12991299
memory.create('a');
13001300
memory.switchTo('a');
@@ -1310,7 +1310,7 @@ describe('core', () => {
13101310
memory.create('test');
13111311
memory.switchTo('test');
13121312

1313-
const array = new VersionableArray(1, 2, 3, 4, 5);
1313+
const array = new VersionableArray<number>(1, 2, 3, 4, 5);
13141314
memory.linkToMemory(array);
13151315
delete array[0];
13161316
array[0] = 1;
@@ -1324,7 +1324,7 @@ describe('core', () => {
13241324
memory.create('test');
13251325
memory.switchTo('test');
13261326

1327-
const array = new VersionableArray(1, 2, 3, 4, 5);
1327+
const array = new VersionableArray<number>(1, 2, 3, 4, 5);
13281328
memory.linkToMemory(array);
13291329

13301330
memory.create('1-1');
@@ -1348,7 +1348,7 @@ describe('core', () => {
13481348
});
13491349
it('array push and pop in same slide memory have a clean memory slice values', () => {
13501350
const memory = new Memory();
1351-
const array = new VersionableArray(1, 2, 3, 4, 5);
1351+
const array = new VersionableArray<number>(1, 2, 3, 4, 5);
13521352
memory.linkToMemory(array);
13531353
memory.create('1');
13541354
memory.switchTo('1');

packages/core/src/Modifier.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { Constructor } from '../../utils/src/utils';
22
import { VNode } from './VNodes/VNode';
3+
import { VersionableObject } from './Memory/VersionableObject';
34

45
interface ModifierConstructor {
56
new <T extends Constructor<Modifier>>(...args: ConstructorParameters<T>): this;
67
}
78
export interface Modifier {
89
constructor: ModifierConstructor & this;
910
}
10-
export class Modifier {
11+
export class Modifier extends VersionableObject {
1112
get name(): string {
1213
return '';
1314
}

packages/core/src/Modifiers.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { Modifier } from './Modifier';
22
import { Constructor, isConstructor } from '../../utils/src/utils';
3+
import { VersionableObject } from './Memory/VersionableObject';
4+
import { VersionableArray } from './Memory/VersionableArray';
35

4-
export class Modifiers {
5-
_contents: Modifier[] = [];
6+
export class Modifiers extends VersionableObject {
7+
_contents: Modifier[] = new VersionableArray();
68
constructor(...modifiers: Array<Modifier | Constructor<Modifier>>) {
9+
super();
710
const clonedModifiers = modifiers.map(mod => {
811
return mod instanceof Modifier ? mod.clone() : mod;
912
});

packages/core/src/VNodes/AbstractNode.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import { Constructor, nodeLength } from '../../../utils/src/utils';
33
import { ContainerNode } from './ContainerNode';
44
import { AtomicNode } from './AtomicNode';
55
import { Modifiers } from '../Modifiers';
6+
import { VersionableObject } from './../Memory/VersionableObject';
7+
import { markAsDiffRoot } from './../Memory/Memory';
68

79
let id = 0;
8-
export abstract class AbstractNode {
9-
readonly id = id;
10+
export abstract class AbstractNode extends VersionableObject {
11+
readonly id = ++id;
1012
editable = true;
1113
tangible = true;
1214
breakable = true;
@@ -25,7 +27,8 @@ export abstract class AbstractNode {
2527
}
2628

2729
constructor() {
28-
id++;
30+
super();
31+
markAsDiffRoot(this);
2932
}
3033

3134
get name(): string {

packages/core/src/VNodes/ContainerNode.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { AbstractNode } from './AbstractNode';
22
import { VNode, Predicate, isLeaf } from './VNode';
33
import { ChildError } from '../../../utils/src/errors';
4+
import { VersionableArray } from '../Memory/VersionableArray';
45

56
export class ContainerNode extends AbstractNode {
6-
readonly childVNodes: VNode[] = [];
7+
readonly childVNodes: VNode[] = new VersionableArray<VNode>();
78

89
//--------------------------------------------------------------------------
910
// Browsing children.

packages/core/test/ContextManager.test.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -284,16 +284,19 @@ describe('core', () => {
284284
contentBefore:
285285
'<div><div><p>cd</p></div></div>' +
286286
'<ul><li></li><li style="list-style: none;"><ul><li><p>c</p></li></ul></li><li><div>[]</div></li></ul>',
287-
stepFunction: (editor: BasicEditor) => {
287+
stepFunction: async (editor: BasicEditor) => {
288288
const callback = (): void => {};
289289
const check = (context: CheckingContext): boolean => !!context;
290290
const checkSpy1 = sinon.spy(check);
291291
const checkSpy2 = sinon.spy(check);
292292
const newSelection = new VSelection();
293-
294-
const domEngine = editor.plugins.get(Layout).engines.dom;
295-
const editable = domEngine.components.get('editable')[0];
296-
newSelection.setAt(editable);
293+
await editor.execCommand('TestWrapWithCommandForMemorySecurity', {
294+
callback: () => {
295+
const domEngine = editor.plugins.get(Layout).engines.dom;
296+
const editable = domEngine.components.get('editable')[0];
297+
newSelection.setAt(editable);
298+
},
299+
});
297300
const commands: CommandImplementation[] = [
298301
{
299302
title: 'paragraph',
+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/* eslint-disable max-nested-callbacks */
2+
import { expect } from 'chai';
3+
import { BasicEditor } from '../../../bundles/BasicEditor';
4+
import { DomEditable } from '../../plugin-dom-editable/src/DomEditable';
5+
import { DomLayout } from '../../plugin-dom-layout/src/DomLayout';
6+
import { Layout } from '../../plugin-layout/src/Layout';
7+
import { DomLayoutEngine } from '../../plugin-dom-layout/src/ui/DomLayoutEngine';
8+
9+
describe('test performances', () => {
10+
describe('stores', () => {
11+
describe('Memory / VDocument', () => {
12+
let wrapper: HTMLElement;
13+
let editor: BasicEditor;
14+
15+
beforeEach(async () => {
16+
wrapper = document.createElement('test-wrapper');
17+
wrapper.style.display = 'block';
18+
document.body.appendChild(wrapper);
19+
const root = document.createElement('div');
20+
root.innerHTML = `<h1>Jabberwocky</h1>
21+
<h3>by Lewis Carroll</h3>
22+
<p><i>’Twas brillig, and the slithy toves<br/>
23+
Did gyre and gimble in the wabe:<br/>
24+
All mimsy were the borogoves,<br/>
25+
And the mome raths outgrabe.<br/>
26+
<br/>
27+
“Beware the Jabberwock, my son!<br/>
28+
The jaws that bite, the claws that catch!<br/>
29+
Beware the Jubjub bird, and shun<br/>
30+
The frumious Bandersnatch!”<br/>
31+
<br/>
32+
He took his vorpal sword in hand;<br/>
33+
Long time the manxome foe he sought—<br/>
34+
So rested he by the Tumtum tree<br/>
35+
And stood awhile in thought.<br/>
36+
<br/>
37+
And, as in uffish thought he stood,<br/>
38+
The Jabberwock, with eyes of flame,<br/>
39+
Came whiffling through the tulgey wood,<br/>
40+
And burbled as it came!<br/>
41+
<br/>
42+
One, two! One, two! And through and through<br/>
43+
The vorpal blade went snicker-snack!<br/>
44+
He left it dead, and with its head<br/>
45+
He went galumphing back.<br/>
46+
<br/>
47+
“And hast thou slain the Jabberwock?<br/>
48+
Come to my arms, my beamish boy!<br/>
49+
O frabjous day! Callooh! Callay!”<br/>
50+
He chortled in his joy.<br/>
51+
<br/>
52+
’Twas brillig, and the slithy toves<br/>
53+
Did gyre and gimble in the wabe:<br/>
54+
All mimsy were the borogoves,<br/>
55+
And the mome raths outgrabe.<br/></i></p>`;
56+
wrapper.appendChild(root);
57+
58+
editor = new BasicEditor();
59+
editor.configure(DomLayout, { location: [root, 'replace'] });
60+
editor.configure(DomEditable, { source: root });
61+
await editor.start();
62+
});
63+
afterEach(async () => {
64+
editor.stop();
65+
document.body.removeChild(wrapper);
66+
});
67+
68+
it('should split a paragraph in two', async () => {
69+
// Parse the editable in the internal format of the editor.
70+
const memory = editor.memory;
71+
const domEngine = editor.plugins.get(Layout).engines.dom as DomLayoutEngine;
72+
const editable = domEngine.components.get('editable')[0];
73+
memory.linkToMemory(editable);
74+
editor.selection.setAt(editable.children[2].children[500]);
75+
memory.create('0').switchTo('0');
76+
77+
expect(editable.children.length).to.equal(3);
78+
memory.create('test').switchTo('test');
79+
await editor.execCommand('insertParagraphBreak');
80+
expect(editable.children.length).to.equal(4);
81+
82+
const t1 = [];
83+
const t2 = [];
84+
for (let k = 1; k < 25; k++) {
85+
let d = Date.now();
86+
memory
87+
.switchTo('0')
88+
.create(k.toString())
89+
.switchTo(k.toString());
90+
t1.push(Date.now() - d);
91+
92+
d = Date.now();
93+
await editor.execCommand('insertParagraphBreak');
94+
t2.push(Date.now() - d);
95+
}
96+
97+
// We remove the first load because it does not represent time in
98+
// use. In fact, time is much longer because the functions and
99+
// object are not yet loaded. The loading test is done separately.
100+
t1.shift();
101+
t2.shift();
102+
103+
const averageInsert = Math.round(t2.reduce((a, b) => a + b) / t2.length);
104+
expect(averageInsert).to.lessThan(30, 'Time to compute the insert paragraph');
105+
106+
const averageSwitch = Math.round(t1.reduce((a, b) => a + b) / t1.length);
107+
expect(averageSwitch).to.lessThan(1, 'Time to switch the memory');
108+
});
109+
});
110+
});
111+
});

0 commit comments

Comments
 (0)