fix(sticky): prevent crash on editor re-entry during sticky lifecycle
Clear editor state before scene callbacks to prevent blur timer or startEditing re-entry from calling updateFromData on a destroyed sprite. Guard all display object access with .destroyed checks.
This commit is contained in:
@@ -201,52 +201,12 @@ export class TextEditor {
|
|||||||
const item = this._item;
|
const item = this._item;
|
||||||
if (!ta || !item) return;
|
if (!ta || !item) return;
|
||||||
|
|
||||||
if (save) {
|
const onChange = this._onChange;
|
||||||
|
const originalText = this._originalText;
|
||||||
const newText = ta.value;
|
const newText = ta.value;
|
||||||
|
|
||||||
if (item.type === 'sticky' && item.displayObject instanceof StickySprite) {
|
// Clear editor state before mutating scene objects or invoking callbacks.
|
||||||
const data = item.data as StickyObject;
|
// This prevents blur/startEditing re-entry from acting on a destroyed item.
|
||||||
data.text = newText;
|
|
||||||
item.displayObject.updateFromData(data);
|
|
||||||
data.h = item.displayObject.computedHeight;
|
|
||||||
item.displayObject.showText(true);
|
|
||||||
this._onChange?.();
|
|
||||||
} else if (item.type === 'text') {
|
|
||||||
const pixiText = item.displayObject;
|
|
||||||
if (pixiText instanceof Text) {
|
|
||||||
const data = item.data as TextObject;
|
|
||||||
data.text = newText;
|
|
||||||
pixiText.text = newText;
|
|
||||||
pixiText.visible = true;
|
|
||||||
const bounds = pixiText.getLocalBounds();
|
|
||||||
data.w = bounds.width;
|
|
||||||
data.h = bounds.height;
|
|
||||||
this._onChange?.();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Cancel — restore original
|
|
||||||
if (item.type === 'sticky' && item.displayObject instanceof StickySprite) {
|
|
||||||
const data = item.data as StickyObject;
|
|
||||||
data.text = this._originalText;
|
|
||||||
item.displayObject.updateFromData(data);
|
|
||||||
data.h = item.displayObject.computedHeight;
|
|
||||||
item.displayObject.showText(true);
|
|
||||||
} else if (item.type === 'text') {
|
|
||||||
const pixiText = item.displayObject;
|
|
||||||
if (pixiText instanceof Text) {
|
|
||||||
const data = item.data as TextObject;
|
|
||||||
data.text = this._originalText;
|
|
||||||
pixiText.text = this._originalText;
|
|
||||||
pixiText.visible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Always notify on cancel too — the tool callback needs this
|
|
||||||
// to clean up empty newly-created items (sticky or text).
|
|
||||||
this._onChange?.();
|
|
||||||
}
|
|
||||||
|
|
||||||
// DOM cleanup
|
|
||||||
ta.remove();
|
ta.remove();
|
||||||
this._textarea = null;
|
this._textarea = null;
|
||||||
this._item = null;
|
this._item = null;
|
||||||
@@ -254,5 +214,56 @@ export class TextEditor {
|
|||||||
this._container = null;
|
this._container = null;
|
||||||
this._onChange = null;
|
this._onChange = null;
|
||||||
this._originalText = '';
|
this._originalText = '';
|
||||||
|
|
||||||
|
if (save) {
|
||||||
|
if (
|
||||||
|
item.type === 'sticky' &&
|
||||||
|
item.displayObject instanceof StickySprite &&
|
||||||
|
!item.displayObject.destroyed
|
||||||
|
) {
|
||||||
|
const data = item.data as StickyObject;
|
||||||
|
data.text = newText;
|
||||||
|
item.displayObject.updateFromData(data);
|
||||||
|
data.h = item.displayObject.computedHeight;
|
||||||
|
item.displayObject.showText(true);
|
||||||
|
onChange?.();
|
||||||
|
} else if (item.type === 'text') {
|
||||||
|
const pixiText = item.displayObject;
|
||||||
|
if (pixiText instanceof Text && !pixiText.destroyed) {
|
||||||
|
const data = item.data as TextObject;
|
||||||
|
data.text = newText;
|
||||||
|
pixiText.text = newText;
|
||||||
|
pixiText.visible = true;
|
||||||
|
const bounds = pixiText.getLocalBounds();
|
||||||
|
data.w = bounds.width;
|
||||||
|
data.h = bounds.height;
|
||||||
|
onChange?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Cancel — restore original
|
||||||
|
if (
|
||||||
|
item.type === 'sticky' &&
|
||||||
|
item.displayObject instanceof StickySprite &&
|
||||||
|
!item.displayObject.destroyed
|
||||||
|
) {
|
||||||
|
const data = item.data as StickyObject;
|
||||||
|
data.text = originalText;
|
||||||
|
item.displayObject.updateFromData(data);
|
||||||
|
data.h = item.displayObject.computedHeight;
|
||||||
|
item.displayObject.showText(true);
|
||||||
|
} else if (item.type === 'text') {
|
||||||
|
const pixiText = item.displayObject;
|
||||||
|
if (pixiText instanceof Text && !pixiText.destroyed) {
|
||||||
|
const data = item.data as TextObject;
|
||||||
|
data.text = originalText;
|
||||||
|
pixiText.text = originalText;
|
||||||
|
pixiText.visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Always notify on cancel too — the tool callback needs this
|
||||||
|
// to clean up empty newly-created items (sticky or text).
|
||||||
|
onChange?.();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user