highlightjs-copy icon indicating copy to clipboard operation
highlightjs-copy copied to clipboard

Add Clipboard copy fallback (#35)

Open foxfire52 opened this issue 1 year ago • 4 comments

Fix issue #35

foxfire52 avatar Oct 26 '24 20:10 foxfire52

Deploy Preview for highlightjs-copy canceled.

Name Link
Latest commit 9700459165bde9c75e0e550b65ee8509760d474f
Latest deploy log https://app.netlify.com/sites/highlightjs-copy/deploys/672dff6f9713af0008eacc2e

netlify[bot] avatar Oct 26 '24 20:10 netlify[bot]

@foxfire52 Thanks for the contribution. I'm not sure how I feel about the using the fallback in the catch block. Something like this makes more logical sense to me

// The fallback return a promise, similar to the native `writeText()`. 
let fallback_clipboard = async function(text) {
  return new Promise((resolve, reject) => {
    // ...
    try {
      document.execCommand('copy');
      resolve();
    } catch (e) {
      reject();
    }
  });
}

button.onclick = async () => {
  //...
  
  // Early return if navigator.clipboard isn't available
  if (!navigator.clipboard) {
    console.warn('navigator.clipboard: Clipboard API unavailable. Falling back to document.execCommand');
    await fallback_clipboard(newText);
  } else {
    await navigator.clipboard.writeText(newText);
  }

  //...
}

arronhunt avatar Nov 01 '24 19:11 arronhunt

@arronhunt Thank you for the valuable feedback.

The fallback is async now, so it returns a Promise by default. I feel we should avoid throw/reject() in the fallback, handling document.exec failure with console logging or true/false return value should be enough.

That try/catch wrapping writeText() is important since navigator.clipboard.writeText() can throw a DOMException MDN writeText(). While your code seems to handle the initial issue, it will fail on a writeText() exception.

As examples this could happen if:

  1. There's a OS Api failure (likely rare)
  2. The web page using the plugin is inside a cross-origin iframe with no clipboard-write permission (e.g. iframe attribute allow="clipboard-write *"). On clicking a Copy button inside the page, writeText() will trigger NotAllowedError: Failed to execute 'writeText' on 'Clipboard': The Clipboard API has been blocked because of a permissions policy applied to the current document. See https://goo.gl/EuHzyv for more details. Note that the fallback function can correctly execute in this case only if writeText() exception is caught.
  3. Other browser related failures as shown in Clipboard W3C Specification and clipboard-write check specification.

The proposed Pull Request covers with a fallback two distinct failure points: !navigator.clipboard and a writeText() DOMException. I apologize if that wasn't clear.

If necessary I can provide a test case for the iframe problem.

I would like to hear your opinion on writeText handling before proceeding further.

Thank you for your time.

foxfire52 avatar Nov 08 '24 12:11 foxfire52

I have successfully tested this pull request. Now there are no more problems.

reilldesign avatar Feb 11 '25 09:02 reilldesign