How can I modify my Chrome extension to display a custom confirmation modal before a file is uploaded?

38 Views Asked by At

I'm developing a Chrome extension and need it to prompt the user with a custom modal window asking for confirmation when they attempt to upload a file. Here's the content.js script I've been working on:

function showModal(element) {
  const modal = document.createElement('div');

  modal.innerHTML = `
    <div style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);display:flex;justify-content:center;align-items:center;z-index:10000;">
      <div style="background:white;padding:20px;border-radius:5px;box-shadow:0 4px 6px rgba(0,0,0,0.1);">
        <p>Are you sure you want to upload the file?</p>
        <button id="confirmUpload">Yes</button>
        <button id="cancelUpload">No</button>
      </div>
    </div>
  `;

  document.body.appendChild(modal);

  // Handling confirmUpload
  document.getElementById('confirmUpload').addEventListener('click', () => {
    document.body.removeChild(modal);
  });

  // Handling confirmUpload
  document.getElementById('cancelUpload').addEventListener('click', () => {
    document.body.removeChild(modal);
    // Deleting the file from the element.files
    const dt = new DataTransfer()
    element.files = dt.files;
  });
}

// React to an event when a user uploads a file to the site 
document.addEventListener('change', (event) => {
    event.preventDefault();
    const element = event.target;
    
    if (element instanceof HTMLInputElement && element.type === 'file') {
        showModal(element);
    }
}, true);

The issue

The main issue I'm encountering is that the file starts uploading immediately upon selection, before the user can respond to the modal. This behavior defeats the purpose of seeking user confirmation.

Why common solutions won't work

  1. Using event.stopPropagation() isn't viable because it would necessitate custom upload logic for each site, which is impractical.
  2. Standard alert/prompt/confirm dialogs aren't suitable either due to their lack of customization options; I intend to include features like file preview in the modal.

Given these constraints, does anyone have suggestions for a workaround or a different strategy to achieve the desired functionality? Or is it perhaps possible to achieve it with a completely different approach?

1

There are 1 best solutions below

0
aramrw On

If you console.log() the event returned by the change eventListener, you can see cancelable is false, that is why your e.preventDefault() is not working.

To get around this, you need to querySelect the specific input element before the user has triggered the change event using a click eventListener. However, this wouldn't work either, since as you said you would need to add logic for every site.

Since you can't trigger a file select from inside a input element's event, you would need to hide the site's file input element, replace it with a custom button, and add logic from inside your custom button's click event to trigger the site's now invisible input element's file select using .click().

const fileInputElement = document.querySelector('input[type="file"]');
if (fileInputElement instanceof HTMLInputElement) {
    fileInputElement.style.display = "none"
}
const myButton = document.getElementById('my-button')


myButton.addEventListener('click', (e) => {

// replace prompt with your modal + return values
    let answer = prompt('do you want to continue')

    if (answer === "yes" && fileInputElement instanceof HTMLInputElement) {
        fileInputElement.click();
    }
})