diff --git a/src/taskpane/components/AlignmentButtons.tsx b/src/taskpane/components/AlignmentButtons.tsx index 9cd0e87b..3a84298f 100644 --- a/src/taskpane/components/AlignmentButtons.tsx +++ b/src/taskpane/components/AlignmentButtons.tsx @@ -56,10 +56,11 @@ export const AlignmentButtons: React.FC = () => { return; } - // Loop through all select shapes and align them - for (let i = 0; i < shapes.items.length; i++) { - shapes.items[i].left = 81.1; - } + // Set alignment for all shapes at once + shapes.items.forEach(shape => { + shape.left = 81.1; + }); + // Single sync after all updates await context.sync(); setStatusMessage("Objects aligned to left."); @@ -90,10 +91,11 @@ export const AlignmentButtons: React.FC = () => { return; } - // Loop through all select shapes and align them - for (let i = 0; i < shapes.items.length; i++) { - shapes.items[i].left = 480 - (shapes.items[i].width / 2); - } + // Set alignment for all shapes at once + shapes.items.forEach(shape => { + shape.left = 480 - (shape.width / 2); + }); + // Single sync after all updates await context.sync(); setStatusMessage("Objects aligned to center."); @@ -124,10 +126,11 @@ export const AlignmentButtons: React.FC = () => { return; } - // Loop through all select shapes and align them - for (let i = 0; i < shapes.items.length; i++) { - shapes.items[i].left = 879.75 - shapes.items[i].width; - } + // Set alignment for all shapes at once + shapes.items.forEach(shape => { + shape.left = 879.75 - shape.width; + }); + // Single sync after all updates await context.sync(); setStatusMessage("Objects aligned to right."); @@ -158,10 +161,11 @@ export const AlignmentButtons: React.FC = () => { return; } - // Loop through all select shapes and align them - for (let i = 0; i < shapes.items.length; i++) { - shapes.items[i].top = 136.75; - } + // Set alignment for all shapes at once + shapes.items.forEach(shape => { + shape.top = 136.75; + }); + // Single sync after all updates await context.sync(); setStatusMessage("Objects aligned to top."); @@ -192,10 +196,11 @@ export const AlignmentButtons: React.FC = () => { return; } - // Loop through all select shapes and align them - for (let i = 0; i < shapes.items.length; i++) { - shapes.items[i].top = 321 - (shapes.items[i].height / 2); - } + // Set alignment for all shapes at once + shapes.items.forEach(shape => { + shape.top = 321 - (shape.height / 2); + }); + // Single sync after all updates await context.sync(); setStatusMessage("Objects aligned to middle."); @@ -226,10 +231,11 @@ export const AlignmentButtons: React.FC = () => { return; } - // Loop through all select shapes and align them - for (let i = 0; i < shapes.items.length; i++) { - shapes.items[i].top = 505.25 - shapes.items[i].height; - } + // Set alignment for all shapes at once + shapes.items.forEach(shape => { + shape.top = 505.25 - shape.height; + }); + // Single sync after all updates await context.sync(); setStatusMessage("Objects aligned to bottom."); diff --git a/src/taskpane/components/GridGuidelineManager.tsx b/src/taskpane/components/GridGuidelineManager.tsx index ba8d2fa1..42388383 100644 --- a/src/taskpane/components/GridGuidelineManager.tsx +++ b/src/taskpane/components/GridGuidelineManager.tsx @@ -241,13 +241,17 @@ export const GridGuidelineManager: React.FC = () => { shapes.load("items"); await context.sync(); - // Find shapes that are part of our grid + // Load all shape names at once + const allShapes = shapes.items; + for (let i = 0; i < allShapes.length; i++) { + allShapes[i].load("name"); + } + await context.sync(); + + // Find shapes that are part of our grid and mark them for deletion let removedCount = 0; - for (let i = 0; i < shapes.items.length; i++) { - const shape = shapes.items[i]; - shape.load("name"); - await context.sync(); - + for (let i = 0; i < allShapes.length; i++) { + const shape = allShapes[i]; // Check if this shape is part of our grid if (shape.name && shape.name.startsWith(GRID_PREFIX)) { shape.delete(); @@ -255,6 +259,7 @@ export const GridGuidelineManager: React.FC = () => { } } + // Single sync after all deletions await context.sync(); if (showStatus) { diff --git a/src/taskpane/components/MatchProperties.tsx b/src/taskpane/components/MatchProperties.tsx index 623cfa06..30ecd455 100644 --- a/src/taskpane/components/MatchProperties.tsx +++ b/src/taskpane/components/MatchProperties.tsx @@ -74,10 +74,27 @@ export const MatchProperties: React.FC = () => { } } + // First, load all text frames in a batch + if (hasText) { + // Pre-load textFrame for all target shapes + for (let i = 1; i < shapes.items.length; i++) { + shapes.items[i].load("textFrame"); + } + await context.sync(); + + // For shapes that have textFrames, load their textRanges + for (let i = 1; i < shapes.items.length; i++) { + if (shapes.items[i].textFrame) { + shapes.items[i].textFrame.load("textRange"); + } + } + await context.sync(); + } + + // Now apply properties to all shapes let successCount = 0; let textStyleCount = 0; - - // Loop through remaining shapes and apply properties + for (let i = 1; i < shapes.items.length; i++) { try { const targetShape = shapes.items[i]; @@ -100,7 +117,6 @@ export const MatchProperties: React.FC = () => { targetShape.lineFormat.color = firstShape.lineFormat.color; } - await context.sync(); propertiesApplied = true; } catch (err) { console.error(`Error applying line format to shape ${i}:`, err); @@ -117,56 +133,43 @@ export const MatchProperties: React.FC = () => { targetShape.fill.foregroundColor = firstShape.fill.foregroundColor; } - await context.sync(); propertiesApplied = true; } catch (err) { console.error(`Error applying fill format to shape ${i}:`, err); } // Apply text properties if the source has text - if (hasText) { + if (hasText && targetShape.textFrame && targetShape.textFrame.textRange) { try { - // First check if target shape has text - targetShape.load("textFrame"); - await context.sync(); + const sourceFont = firstShape.textFrame.textRange.font; + const targetFont = targetShape.textFrame.textRange.font; - if (targetShape.textFrame) { - targetShape.textFrame.load("textRange"); - await context.sync(); - - if (targetShape.textFrame.textRange) { - const sourceFont = firstShape.textFrame.textRange.font; - const targetFont = targetShape.textFrame.textRange.font; - - // Apply font properties - if (sourceFont.name !== undefined) { - targetFont.name = sourceFont.name; - } - - if (sourceFont.size !== undefined) { - targetFont.size = sourceFont.size; - } - - if (sourceFont.bold !== undefined) { - targetFont.bold = sourceFont.bold; - } - - if (sourceFont.italic !== undefined) { - targetFont.italic = sourceFont.italic; - } - - if (sourceFont.underline !== undefined) { - targetFont.underline = sourceFont.underline; - } - - if (sourceFont.color !== undefined) { - targetFont.color = sourceFont.color; - } - - await context.sync(); - textStyleCount++; - } + // Apply font properties in batch + if (sourceFont.name !== undefined) { + targetFont.name = sourceFont.name; } + + if (sourceFont.size !== undefined) { + targetFont.size = sourceFont.size; + } + + if (sourceFont.bold !== undefined) { + targetFont.bold = sourceFont.bold; + } + + if (sourceFont.italic !== undefined) { + targetFont.italic = sourceFont.italic; + } + + if (sourceFont.underline !== undefined) { + targetFont.underline = sourceFont.underline; + } + + if (sourceFont.color !== undefined) { + targetFont.color = sourceFont.color; + } + + textStyleCount++; } catch (err) { console.error(`Error applying text format to shape ${i}:`, err); } @@ -180,6 +183,9 @@ export const MatchProperties: React.FC = () => { console.error(`Error updating shape ${i}:`, err); } } + + // Single sync after all property changes + await context.sync(); // Final status message based on what was applied if (successCount > 0) {