Skip to content
Merged
54 changes: 49 additions & 5 deletions src/command/commands/update.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,73 @@
import { collectCandidates } from '../../utils/get';
import { Command } from './base';

export class UpdateCommand extends Command {
constructor(element, changes, options) {
super(options.historyId);

this.element = element;
this.elementId = element.id;

this.parent = element.parent;
this.context = element.context;

this.changes = changes;
this.options = options;
this.previousProps = this._createPreviousState(this.changes);
}

execute() {
this.element.apply(this.changes, {
...this.options,
historyId: false,
});
const element = this._resolveElement(false);
if (!element) return;

element.apply(this.changes, { ...this.options, historyId: false });
}

undo() {
this.element.apply(this.previousProps, {
const element = this._resolveElement(true);
if (!element) return;

element.apply(this.previousProps, {
...this.options,
mergeStrategy: 'replace',
historyId: false,
});
}

_resolveElement(isUndo) {
if (this.element && !this.element.destroyed) {
return this.element;
}

const targetId =
isUndo && this.changes?.id ? this.changes.id : this.elementId;
if (this.parent && !this.parent.destroyed) {
const candidates = collectCandidates(
this.parent,
(node) => node.id === targetId,
);
if (candidates[0]) {
this.element = candidates[0];
return candidates[0];
}
}

if (this.context?.viewport && !this.context.viewport.destroyed) {
const candidates = collectCandidates(
this.context.viewport,
(node) => node.id === targetId,
);
if (candidates[0]) {
this.element = candidates[0];
this.parent = this.element.parent;
return candidates[0];
}
}

console.debug(`UpdateCommand: Element with ID ${targetId} not found`);
return null;
}

_createPreviousState(changes) {
const slice = {};
if (!changes) {
Expand Down
4 changes: 4 additions & 0 deletions src/display/mixins/Animationsizeable.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export const AnimationSizeable = (superClass) => {
duration: animationDuration / 1000,
ease: 'power2.inOut',
onUpdate: () => {
if (this.destroyed) {
this.killTweens();
return;
}
this._applyPlacement({
placement: this.props.placement,
margin: this.props.margin,
Expand Down
18 changes: 9 additions & 9 deletions src/display/mixins/Childrenable.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,14 @@ export const Childrenable = (superClass) => {
const MixedClass = class extends superClass {
_applyChildren(relevantChanges, options) {
let { children: childrenChanges } = relevantChanges;
let elements = [...this.children];
const elements = [...this.children];

childrenChanges = validateAndPrepareChanges(
elements,
childrenChanges,
mapDataSchema,
);

if (options.mergeStrategy === 'replace') {
elements.forEach((element) => {
this.removeChild(element);
element.destroy({ children: true });
});
elements = [];
}

for (const childChange of childrenChanges) {
const idx = findIndexByPriority(elements, childChange);
let element = null;
Expand All @@ -40,6 +32,14 @@ export const Childrenable = (superClass) => {
}
element.apply(childChange, options);
}

if (options.mergeStrategy === 'replace') {
elements.forEach((element) => {
if (!element.type) return; // Don't remove children that are not managed by patchmap (e.g. raw PIXI objects)
this.removeChild(element);
element.destroy({ children: true });
});
}
}

_onChildUpdate(childId, changes, mergeStrategy) {
Expand Down
18 changes: 9 additions & 9 deletions src/display/mixins/Componentsable.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,14 @@ export const Componentsable = (superClass) => {
const MixedClass = class extends superClass {
_applyComponents(relevantChanges, options) {
let { components: componentsChanges } = relevantChanges;
let components = [...this.children];
const components = [...this.children];

componentsChanges = validateAndPrepareChanges(
components,
componentsChanges,
componentArraySchema,
);

if (options.mergeStrategy === 'replace') {
components.forEach((component) => {
this.removeChild(component);
component.destroy({ children: true });
});
components = [];
}

for (const componentChange of componentsChanges) {
const idx = findIndexByPriority(components, componentChange);
let component = null;
Expand All @@ -43,6 +35,14 @@ export const Componentsable = (superClass) => {
options,
);
}

if (options.mergeStrategy === 'replace') {
components.forEach((component) => {
if (!component.type) return; // Don't remove components that are not managed by patchmap (e.g. raw PIXI objects)
this.removeChild(component);
component.destroy({ children: true });
});
}
}

_onChildUpdate(childId, changes, mergeStrategy) {
Expand Down