skip to Main Content

I am creating a Chrome extension that allows users to download images from the current webpage with a single click.

However, I encounter issues on some websites, such as Medium, where clicking the "Enable Image Download" button and then clicking an image results in the webpage navigating to the image URL instead of downloading the image.

How can I modify my code to prevent this behavior and ensure that images are downloaded when clicked?

Here is my current code:

// Check if chrome.scripting is available
if (chrome.scripting) {
  chrome.scripting.executeScript({
    target: { tabId: tabId },
    func: enableImageDownload
  }, (results) => {
    if (chrome.runtime.lastError) {
      console.error('Script injection failed: ' + chrome.runtime.lastError.message);
    } else {
      console.log('Script injection succeeded');
    }
  });
} else {
  console.error('chrome.scripting is not available');
}
});

// Function to handle image click and download
function enableImageDownload() {
  console.log('enableImageDownload function called'); // Debugging message
  
  // Add click event listener to all images on the page
  document.querySelectorAll('img').forEach(img => {
    img.style.border = "2px solid red"; // Add red border to highlight the image
    img.style.cursor = "pointer"; // Change cursor to pointer
  
    img.addEventListener("click", function handleClick(event) {
      console.log("Image clicked"); // Debugging message
  
      // Prevent default behavior
      event.preventDefault();
      event.stopPropagation();
  
      // Remove click event listener after the first click
      img.removeEventListener("click", handleClick);
  
      // Reset image border and cursor
      img.style.border = "";
      img.style.cursor = "";
  
      // Create anchor element to trigger download
      const a = document.createElement("a");
      a.href = img.src;
      a.download = img.src.split('/').pop().split('?')[0]; // Extract file name
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      console.log("Image download triggered"); // Debugging message
    });
  });
}


Additional Details:
I am using Chrome’s scripting API to inject the script that enables image downloading.
The script works correctly on most websites, but fails on sites like Medium where clicking an image navigates to the image URL.
I have tried using event.preventDefault() and event.stopPropagation(), but the issue persists.
What modifications are needed to ensure that images are downloaded correctly on all websites?

2

Answers


  1. You need to get at the parent link – this SHOULD have worked but does not work on the Medium page – they likely have event handlers on the containers too.

    if (link && link.parentNode) link.parentNode.replaceChild(img, link);
    
    document.querySelectorAll('img').forEach(img => {
      img.style.border = "2px solid red"; // Add red border to highlight the image
      img.style.cursor = "pointer"; // Change cursor to pointer
      const link = img.closest('a');
      if (link && link.parentNode) link.parentNode.replaceChild(img, link);
      img.addEventListener("click", function handleClick(event) {
        console.log("Image clicked"); // Debugging message
    
        // Prevent default behavior
        event.preventDefault();
        event.stopPropagation();
    
        // Remove click event listener after the first click
        img.removeEventListener("click", handleClick);
    
        // Reset image border and cursor
        img.style.border = "";
        img.style.cursor = "";
    
        // Create anchor element to trigger download
        const a = document.createElement("a");
        a.href = img.src;
        a.download = img.src.split('/').pop().split('?')[0]; // Extract file name
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        console.log("Image download triggered"); // Debugging message
      });
    });
    

    So instead extract the images and give them their own div

    I will give you this code, it opens the image in a new tab, instead of downloading, but so does your original code. It could have something to do with the browser or some oversight.

    const clickDownload = (event) => {
      const tgt = event.target;
      if (!tgt.matches('.download')) return;
      if (tgt.matches('.downloaded')) return;
      const src = tgt.src;
      console.log("Image clicked"); // Debugging message
      tgt.classList.add('downloaded')
      // Reset image border and cursor
      tgt.style.border = "";
      const a = document.createElement("a");
      a.href = src;
      a.download = src.split('/').pop().split('?')[0]; // Extract file name
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
    };
    const div = document.createElement('div');
    div.addEventListener('click', clickDownload);
    document.querySelectorAll('img').forEach(img => {
      const cloneImg = document.createElement('img');
      img.hidden = true;
      cloneImg.style.border = "2px solid red"; // Add red border to highlight the image
      cloneImg.style.margin = '3px';
      cloneImg.src = img.src;
      cloneImg.classList.add('download');
      div.appendChild(cloneImg);
    });
    document.body.appendChild(div);
    <a href="..."><img src="https://placehold.co/100x200" /></a>
    <a href="..."><img src="https://placehold.co/200x100" /></a>
    Login or Signup to reply.
  2. To ensure that images are downloaded when clicked and prevent the default behavior of navigating to the image URL, you can modify your code to include event.preventDefault() and event.stopPropagation() more effectively. Additionally, ensuring that these functions are correctly applied within the click event handler should solve the issue.

    Here is your revised code:

    // Check if chrome.scripting is available
    if (chrome.scripting) {
      chrome.scripting.executeScript({
        target: { tabId: tabId },
        func: enableImageDownload
      }, (results) => {
        if (chrome.runtime.lastError) {
          console.error('Script injection failed: ' + chrome.runtime.lastError.message);
        } else {
          console.log('Script injection succeeded');
        }
      });
    } else {
      console.error('chrome.scripting is not available');
    }
    
    // Function to handle image click and download
    function enableImageDownload() {
      console.log('enableImageDownload function called'); // Debugging message
    
      // Add click event listener to all images on the page
      document.querySelectorAll('img').forEach(img => {
        img.style.border = "2px solid red"; // Add red border to highlight the image
        img.style.cursor = "pointer"; // Change cursor to pointer
    
        img.addEventListener("click", function handleClick(event) {
          console.log("Image clicked"); // Debugging message
    
          // Prevent default behavior
          event.preventDefault();
          event.stopPropagation();
    
          // Remove click event listener after the first click
          img.removeEventListener("click", handleClick);
    
          // Reset image border and cursor
          img.style.border = "";
          img.style.cursor = "";
    
          // Create anchor element to trigger download
          const a = document.createElement("a");
          a.href = img.src;
          a.download = img.src.split('/').pop().split('?')[0]; // Extract file name
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
          console.log("Image download triggered"); // Debugging message
        }, true); // Use capture phase to ensure event is handled first
      });
    }
    

    Changes Made:
    Prevent Default Behavior: Ensured event.preventDefault() and event.stopPropagation() are called immediately when the image is clicked.
    Capture Phase: Added true as the third argument to addEventListener to use the capture phase. This ensures the event listener handles the click event before it bubbles up to other elements that might override the behavior.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search