Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@gupsammy
Copy link
Owner

Summary

Add multiple content extraction modes to EzyCopy extension: copy extracted content to clipboard, download local images with organized storage, and support text selection extraction. Redesigned popup UI with persistent toggle states and improved content-script architecture.

Changes

  • Redesigned popup UI with branding, visual refinements, and persistent toggle settings
  • Added copy-to-clipboard functionality with conditional output modes (markdown vs plain text)
  • Implemented local image download support with organized subfolder storage during markdown conversion
  • Added text selection extraction capability alongside full page content
  • Refactored content-script to consolidate clipboard and file output logic
  • Migrated file picker to background service worker (Manifest V3 compliance)
  • Created new lib/platform.js utility module for platform-specific operations

Commits

  • 77b9a90 - feat(ui): redesign popup with branding and persistent toggle
  • da33d0d - feat(images): add local image download support with organized subfolder storage
  • e903afd - refactor: replace file picker with background service worker for markdown save
  • 4bbe6e9 - feat(clipboard): add copy-to-clipboard setting with conditional output modes
  • a1427e0 - feat(selection): support text selection extraction
  • 14e1bb9 - refactor(content-script): consolidate clipboard and file output logic

Files Changed

  • popup.html - Redesigned UI layout with improved controls
  • popup.js - Enhanced with persistent settings and toggle state management
  • popup.css - New stylesheet with branding and styling (182+ lines)
  • background.js - Service worker with file picker delegation (206+ lines)
  • content-script.js - Refactored with consolidated output modes (203+ lines)
  • lib/ezycopy.js - Extended extraction logic for images and selections (189+ lines)
  • lib/platform.js - New utility module for platform-specific operations (102+ lines)
  • manifest.json - Version bump

@claude
Copy link
Contributor

claude bot commented Nov 28, 2025

Claude finished @gupsammy's task —— View job


PR Review Complete ✅

I've reviewed this PR with a focus on critical issues that would break functionality or prevent Chrome Web Store approval.

Checklist:

  • Read project structure and guidelines
  • Review manifest.json changes
  • Review background.js service worker implementation
  • Review content-script.js refactoring
  • Review lib/ezycopy.js extraction logic
  • Review lib/platform.js utility module
  • Review popup UI changes (HTML/CSS/JS)
  • Check for critical issues (crashes, API misuse, security)
  • Post final review

Issues Found

I found 1 critical bug that will crash the extension and 2 issues worth addressing:

🔴 CRITICAL: Missing script injection in popup.js (line 99)

The popup button doesn't inject lib/platform.js but content-script.js needs it. This will cause "rewriteImagePaths is not defined" errors when using the popup button. See inline comment for fix.

🟡 Function duplication (content-script.js line 7)

rewriteImagePaths() is defined in both content-script.js and lib/platform.js. The content-script version will override the platform.js version. Clean this up by removing one.

🟡 Listener leak risk (background.js line 129)

Download listeners may not be cleaned up properly if timeouts occur. Consider more robust cleanup.


Overall Assessment

The architecture looks solid for a Manifest V3 extension:

  • ✅ Proper service worker usage (no persistent background page)
  • ✅ Correct permissions (downloads, storage, scripting)
  • ✅ Message passing implemented correctly
  • ✅ Selection extraction logic is clean
  • ✅ No XSS vulnerabilities (using DOMParser safely)
  • ✅ UI/UX improvements look good

Recommendation: Fix the critical popup.js injection bug, then this is good to ship. The other issues are minor quality improvements.

"lib/turndown.js",
"lib/turndown-plugin-gfm.js",
"lib/ezycopy.js",
"content-script.js",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing lib/platform.js injection

The popup button click doesn't inject lib/platform.js, but the content-script.js uses functions from it (like rewriteImagePaths). This will cause a crash when using the popup button.

Suggested change
"content-script.js",
files: [
"lib/readability.js",
"lib/turndown.js",
"lib/turndown-plugin-gfm.js",
"lib/ezycopy.js",
"lib/platform.js",
"content-script.js",
],

/**
* Rewrite image URLs in markdown with local file paths
*/
function rewriteImagePaths(markdown, urlToPathMap) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function is duplicated

rewriteImagePaths() is defined here AND in lib/platform.js (lines 89-102). Since the platform.js version is injected, this duplicate will override it. Either remove this duplicate or don't inject platform.js.

background.js Outdated
chrome.downloads.onChanged.addListener(listener);

// Timeout after 30 seconds
setTimeout(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential listener leak

If downloads are interrupted or timeout happens, listeners may remain attached. Consider storing listener refs and cleaning them up properly, or use { once: true } pattern where possible.

@gupsammy
Copy link
Owner Author

@claude plan and resolve all.

@claude
Copy link
Contributor

claude bot commented Nov 28, 2025

Claude finished @gupsammy's task —— View job


Issues Resolved ✅

All three issues from my previous review have been fixed and pushed to the PR branch.

Task List:

  • Read relevant source files
  • Fix popup.js - add lib/platform.js to injection list (CRITICAL)
  • Fix content-script.js - remove duplicate rewriteImagePaths()
  • Fix background.js - improve listener cleanup
  • Commit and push changes

Changes Made

🔴 Fixed Critical Bug: popup.js:99

Added lib/platform.js to the script injection list. This prevents "rewriteImagePaths is not defined" errors when using the popup button.

files: [
  "lib/readability.js",
  "lib/turndown.js",
  "lib/turndown-plugin-gfm.js",
  "lib/ezycopy.js",
  "lib/platform.js",  // ← Added
  "content-script.js",
],

🟡 Fixed Function Duplication: content-script.js:7

Removed the duplicate rewriteImagePaths() function. The extension now uses the canonical version from lib/platform.js, which is injected by both popup.js and background.js.

🟡 Fixed Listener Leak Risk: background.js:129

Improved cleanup by clearing the timeout when downloads complete or are interrupted. This prevents memory leaks if timeouts occur.

let timeoutId = null;
const listener = (delta) => {
  if (delta.state && delta.state.current === 'complete') {
    clearTimeout(timeoutId);  // ← Added
    chrome.downloads.onChanged.removeListener(listener);
    // ...
  }
  // ...
};
timeoutId = setTimeout(() => { /* ... */ }, 30000);

Testing Recommendation

The critical bug fix ensures both trigger methods (popup button and right-click menu) inject the same scripts. Please test:

  1. Extract content via popup button with "Download Images" enabled
  2. Extract content via right-click menu with "Download Images" enabled
  3. Verify images are downloaded and paths are rewritten correctly in both cases

| View commit

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

background.js Outdated
Comment on lines 3 to 6
const DEFAULT_SETTINGS = {
copyToClipboard: true,
downloadMarkdown: false,
downloadImagesLocally: false

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Default disables markdown download by default

The default settings now set downloadMarkdown to false even though the context menu still says “Save as Markdown” and the content-script only writes a file when that flag is true. On a fresh install, using the context menu or popup without first opening the settings will only copy to clipboard and never save a .md, which is a regression from the previous behavior that always saved to disk. Consider enabling markdown downloads by default or updating the UX copy to match the new behavior.

Useful? React with 👍 / 👎.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude update the ux copy to match the new behaviour

Copy link
Contributor

@claude claude bot Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude finished @gupsammy's task —— View job


UX Copy Updated ✅

I've updated the context menu text to match the new default behavior where the extension copies to clipboard by default.

Changes Made

Context menu text (background.js:17):

  • ❌ Old: "EzyCopy - Save as Markdown"
  • ✅ New: "EzyCopy - Extract Content"

The new text is neutral and accurate for both output modes (clipboard copy and file download), avoiding confusion when downloadMarkdown is disabled by default.

Popup UI labels - No changes needed. The existing toggle labels are already clear:

  • "Copy to clipboard" → "Copy markdown to clipboard"
  • "Download .md" → "Save markdown file to disk"
  • "Download images locally" → "Save images with the markdown file"

Summary

The context menu no longer promises to "Save as Markdown" when it might only copy to clipboard. Users can now configure their preferred output method(s) via the popup toggles, and the context menu works consistently regardless of settings.


Commit: f13b13f

@claude
Copy link
Contributor

claude bot commented Nov 28, 2025

Claude finished @gupsammy's task —— View job


Final PR Review ✅

I've reviewed the latest merge commit and verified all previous fixes remain intact. This PR is ready to ship.

Review Checklist

  • Check latest merge commit changes
  • Verify previous fixes are intact
  • Scan for critical/high severity issues
  • Post final assessment

What Changed in Latest Merge

The merge commit a74570a brought in CI workflow improvements from main. No code changes to the extension itself.


Verification Complete

All three previously identified issues remain fixed:

  • popup.js:99 - lib/platform.js properly injected
  • content-script.js - Duplicate rewriteImagePaths() removed
  • background.js:108,123 - Timeout cleanup added with clearTimeout()

Security & Quality Check

I performed a comprehensive scan focusing on CRITICAL and HIGH severity issues:

Manifest V3 Compliance

  • Service worker properly configured (not persistent background page)
  • Correct permissions: storage, downloads, scripting, activeTab, contextMenus
  • Host permissions properly scoped

Security

  • No XSS vulnerabilities (DOMParser usage is safe - doesn't execute scripts)
  • UTF-8 encoding handled correctly in base64 markdown downloads
  • No script injection vulnerabilities
  • Image path regex properly escapes special characters

Message Passing

  • All async handlers return true to keep channel open
  • No race conditions detected
  • Proper error handling in content-script (catches AbortError for user cancellation)

Script Injection

  • Both trigger paths (popup + context menu) inject identical script sets
  • Proper execution order maintained
  • No timing issues (executeScript properly awaited)

API Usage

  • Clipboard API: Standard navigator.clipboard.writeText() usage
  • Downloads API: Proper listener cleanup with timeout protection
  • Storage API: Correct async/await patterns

Architecture Assessment

The refactoring is well-executed:

  • Clean separation between platform utilities (lib/platform.js) and extraction logic (lib/ezycopy.js)
  • Consolidated output logic in content-script (clipboard + file operations)
  • Service worker properly delegates file picker operations
  • Persistent settings stored correctly

No critical or high severity issues found.

This extension will function correctly and should pass Chrome Web Store review.


gupsammy and others added 8 commits November 28, 2025 16:19
- Add professional header with inline SVG logo and "EzyCopy" branding
- Create separate popup.css with refined color system (#2E7D32 primary green)
- Implement pure CSS toggle switch for "Download images locally" feature
- Add chrome.storage.local persistence for toggle state across sessions
- Restructure popup layout (header, action, status, settings sections)
- Update showFeedback() toast notifications with slide animations
- Add color-mapped icons (checkmark for success, X for error) to toasts
- Improve status display with semantic CSS classes (extracting, success, error, cancelled)
- Add "storage" permission to manifest.json for persistent user settings
- Use safe DOM methods for toast content to prevent XSS vulnerabilities

Design improvements:
- 320px popup width with 8px grid spacing system
- System fonts for native Chrome feel
- Accessible toggle using hidden checkbox + styled label pattern
- Smooth animations (0.2s transitions, slide-in/out effects)
- Light theme (#FAFAFA background) with professional green accents
- Helper text below toggle label for feature description
…er storage

Implement complete image download workflow:
- New platform.js utilities for image handling and path generation
- Background service worker handles image downloads via Chrome downloads API
- Content extraction now collects image metadata (URL, alt text)
- Image URLs in markdown are rewritten to local file paths
- Images organized in EzyCopy/images/{page-subfolder}/ structure
- Added settings support for downloadImagesLocally toggle
- Updated manifest permissions to include downloads

The feature maintains backward compatibility - users can keep the
existing remote URL behavior with a toggle in settings.
…down save

Replace the browser's file picker (showSaveFilePicker) with direct background
service worker handling to save markdown files to Downloads/EzyCopy folder.
This simplifies the save flow and provides consistent file organization for
both image and non-image download modes.

- Update content-script.js to send downloadMarkdown message to background
- Update popup.js with same refactored save pattern
- Remove try-catch for AbortError as picker is no longer used
- Standardize success message to 'Saved to Downloads/EzyCopy!'
…t modes

- Add copyToClipboard and downloadMarkdown settings to control output destination
- Enforce at least one output method is active to prevent disabling all outputs
- Simplify popup UI: remove header, make hero button larger, improve button styling
- Nested image download toggle only visible when markdown download is enabled
- Settings immediately persisted to storage and UI synced on toggle changes
- Add getSelectionHtml() to detect and extract selected text
- Both extractContent() and extractContentWithImages() now check for selection first
- Selected text converted to markdown with page title and source link
- Return isSelection flag to indicate if extraction was from selection
- Selection extraction is tried before full-page Readability extraction
- Unify clipboard and markdown file save in single code path
- Add buildSuccessMessage() to generate contextual feedback
- Extract content once, then conditionally copy/save based on settings
- Show progress toast for image downloads (blue spinner icon)
- Auto-dismiss success toasts after 3 seconds, keep progress toasts visible
- Remove duplicate image rewriting logic (now only in content-script)
- Support isSelection flag from extraction functions for personalized messages
… improve cleanup

- Add lib/platform.js to popup.js injection list (fixes missing rewriteImagePaths)
- Remove duplicate rewriteImagePaths() from content-script.js (use platform.js version)
- Improve listener cleanup in background.js with clearTimeout

Co-authored-by: Samarth Gupta <[email protected]>
Changed context menu from 'Save as Markdown' to 'Extract Content'
to accurately reflect that the extension now copies to clipboard by
default (downloadMarkdown: false). The new text is neutral and works
for both clipboard and file download modes.

Co-authored-by: Samarth Gupta <[email protected]>
@gupsammy gupsammy force-pushed the feat/clipboard-images-selection branch from a74570a to a68cccf Compare November 28, 2025 10:49
@claude
Copy link
Contributor

claude bot commented Nov 28, 2025

Claude finished @gupsammy's task —— View job


Latest Changes Review ✅

I've reviewed the commits since my last review and verified all fixes are intact.

Review Checklist

  • Check latest commits since last review
  • Verify previous fixes are intact
  • Scan for critical/high severity issues
  • Post final assessment

Summary

Latest commits:

  • a68cccf - UX fix: Updated context menu text to "Extract Content" (neutral, works for both clipboard/file modes)
  • 58a9bf3 - My previous fixes: platform.js injection, duplicate removal, listener cleanup

Status: Ready to merge

All three issues from my initial review have been resolved:

  1. Critical bug fixed: lib/platform.js is now injected in popup.js:99
  2. Duplicate removed: rewriteImagePaths() only exists in lib/platform.js (content-script.js uses it at line 66)
  3. Cleanup improved: Download listeners now call clearTimeout() in background.js:108,123

No new issues found. The extension follows Manifest V3 requirements correctly:

  • Service worker (not persistent background page) ✅
  • Correct permissions (downloads, storage, scripting) ✅
  • Message passing implemented properly ✅
  • No XSS vulnerabilities ✅

Testing Recommendation

Both trigger methods (popup button + right-click menu) now inject identical scripts. Test both with "Download Images" enabled to verify images download and paths rewrite correctly.


Refactor content extraction logic to separate concerns: extraction returns
structured data (title, body, metadata) and a new formatContent() function
handles output-specific formatting (clipboard vs download). Add IIFE wrapper
to platform.js to prevent redeclaration. Reorganize settings with experimental
section for selective copy and local image downloads. Update UI to reflect
new settings hierarchy with conditional visibility for image options.

Generated with Claude Code

Co-Authored-By: Claude <[email protected]>
@claude
Copy link
Contributor

claude bot commented Nov 28, 2025

Claude finished @gupsammy's task —— View job


Latest Refactoring Review ✅

I've reviewed commit e790327 which restructures content formatting and image handling. All previous fixes remain intact, and no critical or high severity issues found.

Review Checklist

  • Check latest commits since last review
  • Verify previous fixes are intact
  • Scan for critical/high severity issues
  • Post final assessment

What Changed in Latest Commit

Commit e790327: Refactor extraction logic (449 additions, 314 deletions across 7 files)

Architecture improvements:

  1. Separation of concerns - extractContent() now returns structured data (title, body, byline, sourceUrl, html, isSelection) instead of pre-formatted markdown
  2. New formatContent() function - Handles output-specific formatting with two modes:
    • 'clipboard' - Lean output (title + body only)
    • 'download' - Full metadata (source, author, timestamps)
  3. IIFE wrapper for platform.js - Prevents redeclaration errors when scripts are injected multiple times (lines 1-3)
  4. Settings reorganization - Moved selectiveCopy and downloadImagesLocally to experimental namespace
  5. Conditional UI visibility - Download images toggle only visible when BOTH downloadMarkdown AND includeImages are enabled

Previous Fixes Verified ✅

All three issues from my initial review remain fixed:

  1. popup.js:135 - lib/platform.js properly injected
  2. content-script.js - Duplicate rewriteImagePaths() removed (uses platform.js version)
  3. background.js:122,137 - Timeout cleanup with clearTimeout() implemented

Security & Code Quality Assessment

Critical Issues: None ✅

High Severity Issues: None ✅

Code Quality:

  • ✅ Clean refactoring - separation of extraction vs formatting logic
  • ✅ IIFE wrapper prevents redeclaration crashes
  • ✅ Settings migration properly handles nested experimental object
  • ✅ Image stripping logic correctly removes all markdown image syntax
  • ✅ No XSS vulnerabilities introduced
  • ✅ Proper error handling maintained in content-script

Settings Structure:

{
  copyToClipboard: true,
  downloadMarkdown: true,
  includeImages: true,
  experimental: {
    selectiveCopy: false,        // NEW location
    downloadImagesLocally: false // NEW location
  }
}

UI Improvements:

  • Experimental features properly grouped under EXPERIMENTAL badge
  • Download images toggle conditionally hidden when not applicable (popup.js:59-65)
  • Clean enforcement logic ensures at least one output method is active

Architecture Validation

The refactoring improves maintainability significantly:

Before:

extractContent()  returns { content: "# Title\n\nSource...\n\nBody", isSelection }

After:

extractContent({ selectiveCopy })  returns { title, body, byline, sourceUrl, html, isSelection }
formatContent(extraction, 'clipboard', settings)  "# Title\n\nBody"
formatContent(extraction, 'download', settings)  "# Title\n\nSource...\n\nBody"

This design allows different output targets to format content independently without duplicating extraction logic.


Final Assessment

Status: Ready to merge

This is a high-quality refactoring that:

  • Improves code organization and maintainability
  • Fixes a potential redeclaration bug (IIFE wrapper)
  • Enhances UX with conditional toggle visibility
  • Maintains all security properties
  • Passes all Manifest V3 requirements

No issues found - all changes are improvements. The extension is production-ready.


@gupsammy gupsammy merged commit 6906b09 into main Nov 28, 2025
1 check passed
@gupsammy gupsammy deleted the feat/clipboard-images-selection branch November 28, 2025 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants