From 93ac475e5c37d2ed7039ac7fbb2a962cfe1d3d2a Mon Sep 17 00:00:00 2001 From: adarsh-iiit Date: Sat, 9 Aug 2025 19:50:10 +0530 Subject: [PATCH 01/10] created image context menu file --- src/image-context-menu.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/image-context-menu.js diff --git a/src/image-context-menu.js b/src/image-context-menu.js new file mode 100644 index 00000000..e69de29b From 9a5eb8a3b038a20c5d53ca4c5c4eba4453329e18 Mon Sep 17 00:00:00 2001 From: adarsh-iiit Date: Sat, 9 Aug 2025 19:50:43 +0530 Subject: [PATCH 02/10] basic imports --- src/image-context-menu.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/image-context-menu.js b/src/image-context-menu.js index e69de29b..04f1d2e0 100644 --- a/src/image-context-menu.js +++ b/src/image-context-menu.js @@ -0,0 +1,18 @@ +/** + * Image Context Menu Module + * Provides download and copy functionality for images in context menus + * Now with native notifications & download progress bar + */ + +import { MenuItem, clipboard, dialog, nativeImage, Notification } from "electron"; +import fs from "fs"; +import path from "path"; +import https from "https"; +import http from "http"; +import { fileURLToPath } from "url"; + +// Emulate __filename and __dirname for better error logging +const __filename = fileURLToPath(import.meta.url); +const MODULE_PATH = __filename; // full path to this file + + From 7b71826c7dfbd0722f43b050711589d1e1d3ee71 Mon Sep 17 00:00:00 2001 From: adarsh-iiit Date: Sat, 9 Aug 2025 19:51:20 +0530 Subject: [PATCH 03/10] custom error logging func --- src/image-context-menu.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/image-context-menu.js b/src/image-context-menu.js index 04f1d2e0..f9785ff3 100644 --- a/src/image-context-menu.js +++ b/src/image-context-menu.js @@ -16,3 +16,32 @@ const __filename = fileURLToPath(import.meta.url); const MODULE_PATH = __filename; // full path to this file + + + +// Simplified error logging helper for better debog for peer developers : coding style of adarshtech251 +function logError(functionName, error, shortMessage = '') { + let lineNumber = 'unknown'; + if (error && error.stack) { + const stackLines = error.stack.split('\n'); + for (const line of stackLines) { + if (line.includes(MODULE_PATH)) { + const match = line.match(/:(\d+):\d+/); + if (match) { + lineNumber = match[1]; + break; + } + } + } + } + const message = shortMessage || (error instanceof Error ? error.message : String(error)); + + console.error('\n\n\n------------------------------------------------'); + console.error(`Section:[${functionName}] \n${message}`); + console.error(`error at file --- ${MODULE_PATH}:${lineNumber}`); + console.error('------------------------------------------------\n\n\n'); + + //// file location , actual error , short custom mssg , also line that is causing this exception + + +} \ No newline at end of file From f74a049154ae63abb8d413f7bd45cb63b11a040b Mon Sep 17 00:00:00 2001 From: adarsh-iiit Date: Sat, 9 Aug 2025 19:51:54 +0530 Subject: [PATCH 04/10] get file name from url func --- src/image-context-menu.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/image-context-menu.js b/src/image-context-menu.js index f9785ff3..eacc1073 100644 --- a/src/image-context-menu.js +++ b/src/image-context-menu.js @@ -44,4 +44,31 @@ function logError(functionName, error, shortMessage = '') { //// file location , actual error , short custom mssg , also line that is causing this exception -} \ No newline at end of file +} + + + + + +// Get filename from URL or generate default ////// this function is used for giving a name to the image that we are going to download +function getImageFileName(url, altText = '') { + try { + if (altText && altText.length > 2 && !altText.toLowerCase().includes('image')) { + const sanitized = altText.replace(/[<>:"/\\|?*]/g, '').trim().substring(0, 50); + if (sanitized) return sanitized + '.jpg'; + } + try { + const urlObj = new URL(url); + const filename = path.basename(urlObj.pathname); + if (filename && filename.includes('.') && filename !== 'iu') { + return filename; + } + } catch (urlError) { + logError('getImageFileName', urlError, `Failed to parse URL`); + } + return `image_${Date.now()}.jpg`; + } catch (error) { + logError('getImageFileName', error, `Filename generation error`); + return `image_${Date.now()}.jpg`; + } +} From 9eba28d66b3fb93fefc130d085a42f9e0fd7dc6f Mon Sep 17 00:00:00 2001 From: adarsh-iiit Date: Sat, 9 Aug 2025 19:52:22 +0530 Subject: [PATCH 05/10] download image url --- src/image-context-menu.js | 66 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/image-context-menu.js b/src/image-context-menu.js index eacc1073..2f5dd352 100644 --- a/src/image-context-menu.js +++ b/src/image-context-menu.js @@ -72,3 +72,69 @@ function getImageFileName(url, altText = '') { return `image_${Date.now()}.jpg`; } } + + + + + + + + + +// Download image with progress bar +function downloadImageWithProgress(url, filePath, browserWindow) { + return new Promise((resolve, reject) => { + try { + const protocol = url.startsWith('https:') ? https : http; + + protocol.get(url, (response) => { + if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) { + return downloadImageWithProgress(response.headers.location, filePath, browserWindow) + .then(resolve).catch(reject); + } + if (response.statusCode !== 200) { + const error = new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`); + logError('downloadImageWithProgress', error, `Failed HTTP response`); + return reject(error); + } + + const total = parseInt(response.headers['content-length'], 10) || 0; + let downloaded = 0; + + const fileStream = fs.createWriteStream(filePath); + response.pipe(fileStream); + + response.on('data', (chunk) => { + downloaded += chunk.length; + if (total) { + const progress = downloaded / total; + browserWindow.setProgressBar(progress); + } + }); + + fileStream.on('finish', () => { + browserWindow.setProgressBar(-1); // remove progress bar + fileStream.close(); + resolve(); + }); + + fileStream.on('error', (streamError) => { + browserWindow.setProgressBar(-1); + fs.unlink(filePath, () => {}); + logError('downloadImageWithProgress', streamError, `File stream error`); + reject(streamError); + }); + + }).on('error', (requestError) => { + browserWindow.setProgressBar(-1); + logError('downloadImageWithProgress', requestError, `HTTP request failed`); + reject(requestError); + }); + + } catch (error) { + logError('downloadImageWithProgress', error, `Unexpected error`); + reject(error); + } + }); +} + From b10b992e3b67e3ead4d9270a2d902032df089b57 Mon Sep 17 00:00:00 2001 From: adarsh-iiit Date: Sat, 9 Aug 2025 19:53:04 +0530 Subject: [PATCH 06/10] copy image func and download func --- src/image-context-menu.js | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/image-context-menu.js b/src/image-context-menu.js index 2f5dd352..847e6fe4 100644 --- a/src/image-context-menu.js +++ b/src/image-context-menu.js @@ -138,3 +138,54 @@ function downloadImageWithProgress(url, filePath, browserWindow) { }); } + + + + +// Copy image to clipboard +function copyImageToClipboard(url) { + return new Promise((resolve, reject) => { + try { + const protocol = url.startsWith('https:') ? https : http; + protocol.get(url, (response) => { + if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) { + return copyImageToClipboard(response.headers.location).then(resolve).catch(reject); + } + if (response.statusCode !== 200) { + const error = new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`); + logError('copyImageToClipboard', error, `Failed HTTP response`); + return reject(error); + } + + const chunks = []; + response.on('data', (chunk) => chunks.push(chunk)); + + response.on('end', () => { + const buffer = Buffer.concat(chunks); + const image = nativeImage.createFromBuffer(buffer); + if (image.isEmpty()) { + const error = new Error('Empty image buffer'); + logError('copyImageToClipboard', error, `Image creation failed`); + return reject(error); + } + clipboard.writeImage(image); + resolve(); + }); + + response.on('error', (responseError) => { + logError('copyImageToClipboard', responseError, `Response stream error`); + reject(responseError); + }); + + }).on('error', (requestError) => { + logError('copyImageToClipboard', requestError, `HTTP request failed`); + reject(requestError); + }); + + } catch (error) { + logError('copyImageToClipboard', error, `Unexpected error`); + reject(error); + } + }); +} + From 99d8a48d24b78f2edc050a743b4fb99ceb031ba7 Mon Sep 17 00:00:00 2001 From: adarsh-iiit Date: Sat, 9 Aug 2025 19:53:56 +0530 Subject: [PATCH 07/10] adding buttons to copy and download image in context menu --- src/image-context-menu.js | 73 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/src/image-context-menu.js b/src/image-context-menu.js index 847e6fe4..8fc6b35e 100644 --- a/src/image-context-menu.js +++ b/src/image-context-menu.js @@ -189,3 +189,76 @@ function copyImageToClipboard(url) { }); } + + + + + + +// Creates image-related context menu items +export function createImageMenuItems(params, browserWindow) { + if (!params.srcURL) return []; + + return [ + new MenuItem({ + label: "Download Image", + click: async () => { + try { + const suggestedFilename = getImageFileName(params.srcURL, params.altText); + const result = await dialog.showSaveDialog(browserWindow, { + title: 'Save Image', + defaultPath: suggestedFilename, + filters: [ + { name: 'Images', extensions: ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'svg'] }, + { name: 'All Files', extensions: ['*'] } + ] + }); + + if (!result.canceled && result.filePath) { + try { + await downloadImageWithProgress(params.srcURL, result.filePath, browserWindow); + console.log(`[${MODULE_PATH}:Download Image] Success: ${result.filePath}`); + showSuccessNotification('Download Complete', `Image saved to: ${result.filePath}`); + } catch (downloadError) { + logError('Download Image MenuItem', downloadError, `Download failed`); + } + } + } catch (dialogError) { + logError('Download Image MenuItem', dialogError, `Dialog error`); + } + }, + }), + + new MenuItem({ + label: "Copy Image", + click: async () => { + try { + await copyImageToClipboard(params.srcURL); + console.log(`[${MODULE_PATH}:Copy Image] Success: Image copied to clipboard`); + showSuccessNotification('Image Copied', 'The image has been copied to the clipboard.'); + } catch (copyError) { + logError('Copy Image MenuItem', copyError, `Failed to copy image`); + try { + clipboard.writeText(params.srcURL); + console.log(`[${MODULE_PATH}:Copy Image] Fallback: Image URL copied to clipboard`); + showSuccessNotification('Image URL Copied', 'The image URL has been copied.'); + } catch (fallbackError) { + logError('Copy Image MenuItem Fallback', fallbackError, `Failed to copy URL`); + } + } + }, + }), + + new MenuItem({ + label: "Copy Image Address", + click: () => { + try { + clipboard.writeText(params.srcURL); + showSuccessNotification('Image URL Copied', 'The image URL has been copied.'); + } catch (clipboardError) { + logError('Copy Image Address MenuItem', clipboardError, `Failed to copy URL`); + } + }, + }) + ]; +} From 1af460925d95dcb456278034b012cc6c629e342e Mon Sep 17 00:00:00 2001 From: adarsh-iiit Date: Sat, 9 Aug 2025 19:54:29 +0530 Subject: [PATCH 08/10] this func will add this sub meny to actual menu --- src/image-context-menu.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/image-context-menu.js b/src/image-context-menu.js index 8fc6b35e..98e96739 100644 --- a/src/image-context-menu.js +++ b/src/image-context-menu.js @@ -262,3 +262,14 @@ export function createImageMenuItems(params, browserWindow) { }) ]; } + + + + + +// * Adds image menu items to an existing menu + +export function addImageMenuItems(menu, params, browserWindow) { + const imageMenuItems = createImageMenuItems(params, browserWindow); + imageMenuItems.forEach(item => menu.append(item)); +} From 9b04205959eca5983de97fd89ce6e052d653763a Mon Sep 17 00:00:00 2001 From: adarsh-iiit Date: Sat, 9 Aug 2025 19:55:06 +0530 Subject: [PATCH 09/10] this func will show native success notification upon successful download or copy --- src/image-context-menu.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/image-context-menu.js b/src/image-context-menu.js index 98e96739..0727c62f 100644 --- a/src/image-context-menu.js +++ b/src/image-context-menu.js @@ -266,6 +266,21 @@ export function createImageMenuItems(params, browserWindow) { +// Helper: Show native success notification after copy and download of image +function showSuccessNotification(title, body) { + try { + new Notification({ + title, + body, + silent: false + }).show(); + } catch (error) { + logError('showSuccessNotification', error, `Notification failed`); + } +} + + + // * Adds image menu items to an existing menu From cf739b57df1bba13b9e698b5b2ca219750fa5cdb Mon Sep 17 00:00:00 2001 From: adarsh-iiit Date: Sat, 9 Aug 2025 19:56:44 +0530 Subject: [PATCH 10/10] added the func call filoe , the func call will add features in main context menu --- src/context-menu.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/context-menu.js b/src/context-menu.js index f9d226fd..7462e074 100644 --- a/src/context-menu.js +++ b/src/context-menu.js @@ -1,5 +1,7 @@ import { Menu, MenuItem, clipboard } from "electron"; import WindowManager from "./window-manager.js"; +import {addImageMenuItems} from './image-context-menu.js' + const isMac = process.platform === "darwin"; @@ -157,6 +159,15 @@ export function attachContextMenus(browserWindow, windowManager) { }) ); + + //////////////////////// by adarshtech251 //////////////////////// + // ← ADDED IMAGE MENU ITEMS HERE (ONLY NEW CODE IN THIS FILE) + addImageMenuItems(menu, params, browserWindow); + ///////////////////////////////////////////////////////////////// + + + + // Link handling if (params.linkURL) { menu.append(