From 5c0008fba620aa8437691626bd375e489e183785 Mon Sep 17 00:00:00 2001 From: MarsLuay <70299537+MarsLuay@users.noreply.github.com> Date: Sun, 6 Sep 2026 04:39:21 +0000 Subject: [PATCH] perf: Optimize shape selection DOM updates by avoiding full slide queries Avoid querying the entire slide's group shapes when applying or clearing selection classes in `NativePowerPointView`. The code now primarily targets elements that already have the class to remove it, and explicitly looks up shapes by index in `selectedShapeIndices` to apply it. --- src/powerpoint/ui/NativePowerPointView.ts | 34 +++++++++++++---------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/powerpoint/ui/NativePowerPointView.ts b/src/powerpoint/ui/NativePowerPointView.ts index 00fded3..12570a1 100644 --- a/src/powerpoint/ui/NativePowerPointView.ts +++ b/src/powerpoint/ui/NativePowerPointView.ts @@ -4713,7 +4713,7 @@ export class NativePowerPointView extends FileView { this.selectedShapeIndex = shapeIndex; this.selectedShapeIndices = new Set([shapeIndex]); this.removeMultiSelectionBoxes(); - this.svgEl.querySelectorAll('g[data-ooxml-shape-idx]').forEach((shape) => { + this.svgEl?.querySelectorAll('.native-powerpoint-shape-selected').forEach((shape) => { shape.removeClass('native-powerpoint-shape-selected'); }); @@ -4748,7 +4748,7 @@ export class NativePowerPointView extends FileView { this.selectedShapeIndex = shapeIndex; this.selectedShapeIndices = new Set([shapeIndex]); this.removeMultiSelectionBoxes(); - this.svgEl.querySelectorAll('g[data-ooxml-shape-idx]').forEach((shape) => { + this.svgEl?.querySelectorAll('.native-powerpoint-shape-selected').forEach((shape) => { shape.removeClass('native-powerpoint-shape-selected'); }); @@ -4824,14 +4824,16 @@ export class NativePowerPointView extends FileView { } private applySelectionClasses(): void { - this.svgEl?.querySelectorAll('g[data-ooxml-shape-idx]').forEach((shape) => { - const index = getShapeIndex(shape); - if (index !== null && this.selectedShapeIndices.has(index)) { + if (!this.svgEl) return; + this.svgEl.querySelectorAll('.native-powerpoint-shape-selected').forEach((shape) => { + shape.removeClass('native-powerpoint-shape-selected'); + }); + for (const index of this.selectedShapeIndices) { + const shape = this.svgEl.querySelector(`g[data-ooxml-shape-idx="${index}"]`); + if (shape) { shape.addClass('native-powerpoint-shape-selected'); - } else { - shape.removeClass('native-powerpoint-shape-selected'); } - }); + } } private clearSelection(options: { skipTextCommit?: boolean } = {}): void { @@ -4849,7 +4851,7 @@ export class NativePowerPointView extends FileView { this.selectedShapeIndex = null; this.selectedShapeIndices.clear(); this.selectedTransform = null; - this.svgEl?.querySelectorAll('g[data-ooxml-shape-idx]').forEach((shape) => { + this.svgEl?.querySelectorAll('.native-powerpoint-shape-selected').forEach((shape) => { shape.removeClass('native-powerpoint-shape-selected'); }); this.removeSelectionOverlay(); @@ -12288,14 +12290,16 @@ export class NativePowerPointView extends FileView { } private previewSelectionClasses(indices: Set): void { - this.svgEl?.querySelectorAll('g[data-ooxml-shape-idx]').forEach((shape) => { - const index = getShapeIndex(shape); - if (index !== null && indices.has(index)) { + if (!this.svgEl) return; + this.svgEl.querySelectorAll('.native-powerpoint-shape-selected').forEach((shape) => { + shape.removeClass('native-powerpoint-shape-selected'); + }); + for (const index of indices) { + const shape = this.svgEl.querySelector(`g[data-ooxml-shape-idx="${index}"]`); + if (shape) { shape.addClass('native-powerpoint-shape-selected'); - } else { - shape.removeClass('native-powerpoint-shape-selected'); } - }); + } } private beginMarquee(event: PointerEvent, additive: boolean): void {