reflex-frp / reflex-dom

Web applications without callbacks or side-effects. Reflex-DOM brings the power of functional reactive programming (FRP) to the web. Build HTML and other Document Object Model (DOM) data with a pure functional interface.
https://reflex-frp.org
BSD 3-Clause "New" or "Revised" License
358 stars 145 forks source link

Copy text to clipboard always fails on Firefox #351

Open JBetz opened 4 years ago

JBetz commented 4 years ago

The function below always works on Chrome, but never on Firefox. My guess is that Firefox is stricter in its definition of a user-driven event, which is necessary to execute the copy command, and something is getting interleaved by the ghcjs runtime that violates it. It's possible that this is a ghcjs bug, but putting here for now until we've got an example that can prove it.

Note: Only returns true if part of a user interaction. Don't try using the return value to verify browser support before calling a command. https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}

import Data.Text (Text)
import qualified GHCJS.DOM as DOM
import qualified GHCJS.DOM.Document as Document
import qualified GHCJS.DOM.HTMLTextAreaElement as TextArea
import qualified GHCJS.DOM.Node as Node
import qualified GHCJS.DOM.Types as DOM
import Language.Javascript.JSaddle (MonadJSM)
import Reflex.Dom.Core

-- | Copy the given text to the clipboard
performCopyToClipboard
  :: (MonadJSM (Performable m), PerformEvent t m)
  => Event t Text
  -- ^ Text to copy to clipboard. Event must come directly from user
  -- interaction (e.g. domEvent Click), or the copy will not take place.
  -> m (Event t Bool)
  -- ^ Did the copy take place successfully?
performCopyToClipboard copyEvent = performEvent $
  ffor copyEvent $ \copyText -> do
    doc <- DOM.currentDocumentUnchecked
    ta <- DOM.uncheckedCastTo TextArea.HTMLTextAreaElement <$> Document.createElement doc ("textarea" :: Text)
    TextArea.setValue ta copyText
    body <- Document.getBodyUnchecked doc
    _ <- Node.appendChild body ta
    TextArea.select ta
    result <- Document.execCommand doc ("copy" :: Text) False (Nothing :: Maybe Text)
    _ <- Node.removeChild body ta
    return result
alexfmpe commented 4 years ago

This exact code almost always fails to copy to clipboard for me on webkit browsers (Safari/Epiphany). Works 1 out of 20 attempts or so.

3noch commented 4 years ago

Perfect. I have a great solution replicate 20 ....