Skip to content

Commit

Permalink
fix(core): handle move nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
pubuzhixing8 committed Dec 6, 2021
1 parent bdaf3ab commit 85fe389
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 30 deletions.
29 changes: 29 additions & 0 deletions packages/src/testing/create-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,33 @@ export function createDefaultDocument() {
children: [{ text: 'This is editable text!' }]
}
];
}

export function createMutipleParagraph() {
return [
{
type: 'paragraph',
children: [{ text: '0' }]
},
{
type: 'paragraph',
children: [{ text: '1' }]
},
{
type: 'paragraph',
children: [{ text: '2' }]
},
{
type: 'paragraph',
children: [{ text: '3' }]
},
{
type: 'paragraph',
children: [{ text: '4' }]
},
{
type: 'paragraph',
children: [{ text: '5' }]
}
];
}
65 changes: 65 additions & 0 deletions packages/src/view/container.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing';
import { createMutipleParagraph } from '../testing/create-document';
import { AdvancedEditableComponent, TestingLeafComponent, configureBasicEditableTestingModule } from '../testing';
import { Editor, Transforms, Node } from 'slate';
import { AngularEditor } from 'slate-angular';

describe('ViewContainer Class', () => {
let component: AdvancedEditableComponent;
let fixture: ComponentFixture<AdvancedEditableComponent>;
let editor: Editor;

beforeEach(fakeAsync(() => {
configureBasicEditableTestingModule([AdvancedEditableComponent, TestingLeafComponent], [TestingLeafComponent]);
fixture = TestBed.createComponent(AdvancedEditableComponent);
component = fixture.componentInstance;
component.value = createMutipleParagraph();
editor = component.editor;
}));

describe('move nodes', () => {
it('move node from [0] to [1]', fakeAsync(() => {
fixture.detectChanges();
flush();
fixture.detectChanges();
const parent = AngularEditor.toDOMNode(editor, editor);
Transforms.moveNodes(editor, { at: [0], to: [1] });
fixture.detectChanges();
flush();
fixture.detectChanges();
expect(Node.string(editor.children[0])).toEqual('1');
const newP0 = parent.children.item(0) as HTMLElement;
const newP1 = parent.children.item(1) as HTMLElement;
expect(newP0.textContent).toEqual('1');
expect(newP1.textContent).toEqual('0');
}));
it('move node from [2] to [5]', fakeAsync(() => {
fixture.detectChanges();
flush();
fixture.detectChanges();
const parent = AngularEditor.toDOMNode(editor, editor);
Transforms.moveNodes(editor, { at: [2], to: [5] });
fixture.detectChanges();
flush();
fixture.detectChanges();
const newP5 = parent.children.item(5) as HTMLElement;
const newP3 = parent.children.item(3) as HTMLElement;
expect(newP5.textContent).toEqual('2');
expect(newP3.textContent).toEqual('4');
}));
it('move node from [5] to [2]', fakeAsync(() => {
fixture.detectChanges();
flush();
fixture.detectChanges();
const parent = AngularEditor.toDOMNode(editor, editor);
Transforms.moveNodes(editor, { at: [5], to: [2] });
fixture.detectChanges();
flush();
fixture.detectChanges();
const newP2 = parent.children.item(2) as HTMLElement;
const newP5 = parent.children.item(5) as HTMLElement;
expect(newP2.textContent).toEqual('5');
expect(newP5.textContent).toEqual('4');
}));
});
});
67 changes: 37 additions & 30 deletions packages/src/view/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,47 +25,22 @@ export abstract class ViewContainer<T extends ViewContainerItem> implements Afte
// first diff
differ.diff(this.childrenComponent);
const parentElement: HTMLElement = this.elementRef.nativeElement.parentElement;
let firstChildComponent = this.childrenComponent.first;
if (this.childrenComponent.length > 0) {
parentElement.insertBefore(this.createFragment(), this.elementRef.nativeElement);
this.elementRef.nativeElement.remove();
}
this.childrenComponent.changes.subscribe((value) => {
const iterableChanges = differ.diff(this.childrenComponent);
if (iterableChanges) {
iterableChanges.forEachAddedItem((record: IterableChangeRecord<T>) => {
// first insert
if (this.elementRef.nativeElement.parentElement && this.elementRef.nativeElement.parentElement === parentElement) {
const fragment = document.createDocumentFragment();
fragment.append(...record.item.rootNodes);
parentElement.insertBefore(fragment, this.elementRef.nativeElement);
this.elementRef.nativeElement.remove();
iterableChanges.forEachOperation((record: IterableChangeRecord<T>, previousIndex: Number, currentIndex: number) => {
// removed
if (currentIndex === null) {
return;
}
// insert at start location
if (record.currentIndex === 0 && firstChildComponent) {
const fragment = document.createDocumentFragment();
fragment.append(...record.item.rootNodes);
parentElement.prepend(fragment);
} else {
// insert afterend of previous component end
let previousRootNode = this.getPreviousRootNode(record.currentIndex);
if (previousRootNode) {
record.item.rootNodes.forEach((rootNode) => {
previousRootNode.insertAdjacentElement('afterend', rootNode);
previousRootNode = rootNode;
});
} else {
this.viewContext.editor.onError({
code: SlateErrorCode.NotFoundPreviousRootNodeError,
name: 'not found previous rootNode',
nativeError: null
})
}
}
// added or moved
this.handleContainerItemChange(record, parentElement);
});
}
firstChildComponent = this.childrenComponent.first;
});
}

Expand All @@ -89,4 +64,36 @@ export abstract class ViewContainer<T extends ViewContainerItem> implements Afte
})
return fragment;
}

handleContainerItemChange(record: IterableChangeRecord<T>, parentElement: HTMLElement) {
// first insert
if (this.elementRef.nativeElement.parentElement && this.elementRef.nativeElement.parentElement === parentElement) {
const fragment = document.createDocumentFragment();
fragment.append(...record.item.rootNodes);
parentElement.insertBefore(fragment, this.elementRef.nativeElement);
this.elementRef.nativeElement.remove();
return;
}
// insert at start location
if (record.currentIndex === 0) {
const fragment = document.createDocumentFragment();
fragment.append(...record.item.rootNodes);
parentElement.prepend(fragment);
} else {
// insert afterend of previous component end
let previousRootNode = this.getPreviousRootNode(record.currentIndex);
if (previousRootNode) {
record.item.rootNodes.forEach((rootNode) => {
previousRootNode.insertAdjacentElement('afterend', rootNode);
previousRootNode = rootNode;
});
} else {
this.viewContext.editor.onError({
code: SlateErrorCode.NotFoundPreviousRootNodeError,
name: 'not found previous rootNode',
nativeError: null
})
}
}
}
}

0 comments on commit 85fe389

Please sign in to comment.