From 8a781653a8b82abc467c648b73d5906d00cd73f0 Mon Sep 17 00:00:00 2001 From: Heiko Joerg Schick Date: Sun, 9 Mar 2025 16:26:05 +0100 Subject: [PATCH] Added initial version of draft watermark functionality --- src/taskpane/components/App.tsx | 2 +- .../components/ConfidentialButtons.tsx | 5 - src/taskpane/components/DraftButtons.tsx | 172 +++++++++++++++++- 3 files changed, 165 insertions(+), 14 deletions(-) diff --git a/src/taskpane/components/App.tsx b/src/taskpane/components/App.tsx index 1b2cdcc5..866149d1 100644 --- a/src/taskpane/components/App.tsx +++ b/src/taskpane/components/App.tsx @@ -178,7 +178,7 @@ const App: React.FC = () => {
- Watermarks + Markings & Watermarks
diff --git a/src/taskpane/components/ConfidentialButtons.tsx b/src/taskpane/components/ConfidentialButtons.tsx index bf2f1d38..ad34c24c 100644 --- a/src/taskpane/components/ConfidentialButtons.tsx +++ b/src/taskpane/components/ConfidentialButtons.tsx @@ -86,11 +86,6 @@ export const ConfidentialButtons: React.FC = () => { textBox.width = textBoxWidth; textBox.height = 25; // Smaller height for footer text - console.log("Starting PowerPoint add-in execution."); - console.log(textBox.left); - console.log(textBox.top); - console.log(textBox.width); - console.log(textBox.height); await context.sync(); // Load textFrame to set text properties diff --git a/src/taskpane/components/DraftButtons.tsx b/src/taskpane/components/DraftButtons.tsx index 313994ab..e906906d 100644 --- a/src/taskpane/components/DraftButtons.tsx +++ b/src/taskpane/components/DraftButtons.tsx @@ -40,10 +40,106 @@ export const DraftButtons: React.FC = () => { setIsProcessing(true); try { await PowerPoint.run(async (context) => { - const shapes = context.presentation.getSelectedShapes(); - // Implementation will go here - setStatusMessage("Added draft watermark to slides."); - setStatusType("success"); + // Get all slides in the presentation + const slides = context.presentation.slides; + slides.load("items"); + await context.sync(); + + // Get a reference slide to determine dimensions + // Since we can't access presentation width/height directly + if (slides.items.length === 0) { + setStatusMessage("No slides found in the presentation."); + setStatusType("warning"); + return; + } + + // Process counter + let processedSlides = 0; + let errorSlides = 0; + + // Process each slide + for (let i = 0; i < slides.items.length; i++) { + try { + const slide = slides.items[i]; + + //const positionFromTop = slideHeight - 23; + + // Create the textbox - make sure it spans the full width of the slide + // This is important for proper centering + const textBox = slide.shapes.addTextBox(""); + + // Make it span most of the width of the slide (90% centered) + // This ensures we have room for the text to be centered + //const textBoxWidth = slideWidth * 1; // 0.9 + textBox.left = 0; // Center it horizontally + textBox.top = 0; + textBox.width = 960; + textBox.height = 540; // Smaller height for footer text + + await context.sync(); + + // Load textFrame to set text properties + textBox.load("textFrame"); + await context.sync(); + + if (textBox.textFrame) { + // Load textRange to set text and properties + textBox.textFrame.load("textRange"); + await context.sync(); + + // Need to load font and paragraphFormat + textBox.textFrame.textRange.load("font,paragraphFormat"); + await context.sync(); + + // Set font properties + try { + // Ensure the font is loaded properly before setting properties + textBox.textFrame.textRange.font.load(); + await context.sync(); + + // Set font properties exactly as in the VBA code + textBox.textFrame.textRange.font.name = "Inter"; + textBox.textFrame.textRange.font.size = 256; + textBox.textFrame.textRange.font.bold = true; + textBox.textFrame.verticalAlignment = "MiddleCentered" + + // Set the color to RGB(218, 19, 53) + // Different APIs may need different color formats + textBox.textFrame.textRange.font.color = "#DA1335"; + + // Set the text + textBox.textFrame.textRange.text = "DRAFT"; + } catch (fontError) { + console.error("Error setting font properties:", fontError); + // Even if we can't set the font properties exactly, continue with default font + } + + // Add a name/tag to the shape for identification + textBox.name = "DraftWatermark"; + + await context.sync(); + processedSlides++; + } + } catch (slideError) { + console.error(`Error processing slide ${i+1}:`, slideError); + errorSlides++; + // Continue to the next slide + continue; + } + } + + // Report results + if (processedSlides > 0) { + setStatusMessage(`Added draft watermark to ${processedSlides} slides.`); + setStatusType("success"); + } else if (errorSlides > 0) { + setStatusMessage(`Failed to add markings. Errors on ${errorSlides} slides.`); + setStatusType("error"); + } else { + setStatusMessage("No slides found to add draft watermark."); + setStatusType("warning"); + } + }); } catch (error) { setStatusMessage(`Error: ${error.message}`); @@ -58,10 +154,70 @@ export const DraftButtons: React.FC = () => { setIsProcessing(true); try { await PowerPoint.run(async (context) => { - const shapes = context.presentation.getSelectedShapes(); - // Implementation will go here - setStatusMessage("Removed draft watermarks from slides."); - setStatusType("success"); + try { + // Get all slides in the presentation + const slides = context.presentation.slides; + slides.load("items"); + await context.sync(); + + if (slides.items.length === 0) { + setStatusMessage("No slides found in the presentation."); + setStatusType("warning"); + return; + } + + // Process counter + let processedSlides = 0; + let errorSlides = 0; + let removedCount = 0; + + // Process each slide + for (let i = 0; i < slides.items.length; i++) { + try { + const slide = slides.items[i]; + + // Load all shapes on the slide + slide.shapes.load("items"); + await context.sync(); + + // Find shapes with name "ConfidentialMarking" + for (let j = 0; j < slide.shapes.items.length; j++) { + const shape = slide.shapes.items[j]; + shape.load("name"); + await context.sync(); + + if (shape.name === "DraftWatermark") { + // Delete the confidential marking shape + shape.delete(); + removedCount++; + } + } + + await context.sync(); + processedSlides++; + } catch (slideError) { + console.error(`Error processing slide ${i+1}:`, slideError); + errorSlides++; + // Continue to the next slide + continue; + } + } + + // Report results + if (removedCount > 0) { + setStatusMessage(`Removed ${removedCount} draft watermark from ${processedSlides} slides.`); + setStatusType("success"); + } else if (errorSlides > 0) { + setStatusMessage(`Failed to remove draft watermarks. Errors on ${errorSlides} slides.`); + setStatusType("error"); + } else { + setStatusMessage("No daft watermark found to remove."); + setStatusType("info"); + } + } catch (innerError) { + console.error("Inner error:", innerError); + throw innerError; // Re-throw to outer catch + } }); } catch (error) { setStatusMessage(`Error: ${error.message}`);