Tuesday, October 15, 2019

Is it possible to use the new Clipboard API in a GWT app? It depends on document.hasFocus being true.

Ok, there are a few moving parts to this. Keeping it as short as possible, this is the new Clipboard API:


Support is extremely limited at the moment, but for now I'd be happy to get something working in Chrome:


Here's Google's live sample page:


For obvious reasons, there's a lot of paranoid security around JavaScript access to the clipboard. This is the specific detail I'm running into:


These APIs throw a security exception if document.hasFocus() is false. And I'm not seeing any way to honour that rule in a GWT app. In my production app, and in a tiny standalone GWT app I just generated for testing purposes, document.hasFocus() is always false ($doc.hasFocus() is true).

For testing purposes, I generated the GWT StockWatcher demo app:


Then I added some UI hooks for clipboard testing elements in StockWatcher.html:

    <h1>Web Application Starter Project</h1>


    <table align="center">

      <tr>

        <td colspan="2" style="font-weight:bold;">Please enter your name:</td>        

      </tr>

      <tr>

        <td id="nameFieldContainer"></td>

        <td id="sendButtonContainer"></td>

      </tr>

      <tr>

        <td colspan="2" style="color:red;" id="errorLabelContainer"></td>

      </tr>

      <tr>

        <td id="readTextField"></td>

        <td id="readTextButton"></td>

      </tr>      

      <tr>

        <td id="writeTextField"></td>

        <td id="writeTextButton"></td>

      </tr>

    </table>


And minimal testing UI in StockWatcher.java onModuleLoad:

        TextBox readText = new TextBox();

        readText.setText("readText");

        Button readTextButton = new Button("readText");


        TextBox writeText = new TextBox();

        writeText.setText("writeText");

        Button writeTextButton = new Button("writeText");

        

        RootPanel.get("readTextField").add(readText);

        RootPanel.get("readTextButton").add(readTextButton);

        

        RootPanel.get("writeTextField").add(writeText);

        RootPanel.get("writeTextButton").add(writeTextButton);


        readTextButton.addClickHandler(new ClickHandler()

        {

            public void onClick(ClickEvent event)

            {

                readText();

            }

        });

        

        writeTextButton.addClickHandler(new ClickHandler()

        {

            public void onClick(ClickEvent event)

            {

                writeText(writeText.getText());

            }

        });


And corresponding JSNI functions to attempt to invoke the Clipboard API:

   

    public native void readText()

    /*-{

        try

        {

            if (navigator.clipboard)

            {

                console.log('navigator.clipboard.readText()');

                console.log('document.hasFocus()='+document.hasFocus());

                console.log('$doc.hasFocus()='+$doc.hasFocus());

                var promise = navigator.clipboard.readText();

                var resolve = function(text) {

                    console.log(text);

                };

                var reject = function(reason) {

                    console.log('navigator.clipboard.readText failed: '+reason);

                };

                promise["catch"](reject);

                promise.then(resolve,reject)["catch"](reject);

            }

            else

            {

                console.log('This browser does not support navigator.clipboard.');

            }

        }

        catch (e)

        {

            console.error(e,e.stack);

        }

    }-*/;

    


    public native void writeText(String p_text)

    /*-{

        try

        {

            var _this = this;

            if (navigator.clipboard)

            {

                console.log('navigator.clipboard.writeText()');

                console.log('document.hasFocus()='+document.hasFocus());

                console.log('$doc.hasFocus()='+$doc.hasFocus());

                var promise = navigator.clipboard.writeText(p_text);

                var resolve = function(text) {

                    console.log('navigator.clipboard.writeText '+text);

                };

                var reject = function(reason) {

                    console.log('navigator.clipboard.writeText failed: '+reason);

                };

                promise["catch"](reject);

                promise.then(resolve,reject)["catch"](reject);

            }

            else

            {

                console.log('This browser does not support navigator.clipboard.');

            }

        }

        catch (e)

        {

            console.error(e,e.stack);

        }

    }-*/;


And I'm stuck on the same security error noted in that StackOverflow question, but with no obvious way to satisfy that requirement:

navigator.clipboard.readText()

document.hasFocus()=false

$doc.hasFocus()=true

navigator.clipboard.readText failed: NotAllowedError: Document is not focused.


navigator.clipboard.writeText()

document.hasFocus()=false

$doc.hasFocus()=true

navigator.clipboard.writeText failed: NotAllowedError: Document is not focused.



Is there any way to make this work in GWT?

--
You received this message because you are subscribed to the Google Groups "GWT Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit/5bda8f2f-bd40-4e8b-ba0f-9d445cae3000%40googlegroups.com.

No comments:

Post a Comment