OK, I've done some test and apparently `notify::title` is queue so even if
you change title twice in a row in WebKit/JS land, GJS will receive all
changes.

This made me able to create a simple JSONChannel class:
https://gist.github.com/WebReflection/7ab0addec037508cc8380a9c37d285f2

I have that class and the following code in a browser.js file

```js

const PageChannel = new JSONChannel('super-secret');
PageChannel
  .on('message', (err, data) => {
    if (err) console.error(err);
    else console.log(data);
  })
  .send('ping');

```

The index page is nothing more than just this:
```html

<!doctype html>
<script src="browser.js"></script>

```

The GJS part, simplified for demo purpose, is basically just this
```js

const secret = 'super-secret';const re = new
RegExp(`^${secret}:js=`);webView.connect('notify::title', (self,
params) => {
  if (re.test(self.title)) {
    const data = JSON.parse(self.title.slice(RegExp['$&'].length));
    print(data);
    self.run_javascript(
      `document.dispatchEvent(        new CustomEvent(
'${secret}:gjs',          {detail: ${JSON.stringify('pong')}}        )
     );`,
      null,
      (self, result, error) => {
        self.run_javascript_finish(result);
      }
    );
  }
});

```


You will see ping followed by pong in the console once you load that
index.html

Please note that document.title changes could be intercepted via
MutationObserver or DOMSubtreeModified on a document with a title element
and/or hacking the title accessor itself or the document, meaning the
"secret" is not really secret but it's a way to setup a unique channel.

There could be a convention to setup a channel automatically adding some
extra logic on both sides (and I'll giv it a try in few minutes) but I hope
you got the proof of concept and it works for your needs.

It's simpler to implement than my hack on location and it works
better/faster.

Regards






On Wed, Nov 1, 2017 at 1:17 PM, Andrea Giammarchi <
andrea.giammar...@gmail.com> wrote:

> I'd be OK if WebKitGTK could at least accept strings and pass them along
> ... wkjscore-result should be part of the core, IMO.
>
>
>
> On Wed, Nov 1, 2017 at 12:28 PM, Sam Jansen <sam.jan...@starleaf.com>
> wrote:
>
>>
>>
>> On 1 November 2017 at 15:23, Andrea Giammarchi <
>> andrea.giammar...@gmail.com> wrote:
>>
>>> so ... it looks really like the exposed API is completely useless as it
>>> is
>>>
>>> ```js
>>> webkit.messageHandlers.gjs.postMessage('hello');
>>> ```
>>>
>>> Returns a
>>>
>>> [boxed instance proxy GIName:WebKit2.JavascriptResult
>>> jsobj@0x7fa08c2e4160 native@0x7fa052081d80]
>>>
>>>
>>> and if you try to get its value it goes bananas with a message like:
>>>
>>> Gjs-WARNING **: JS ERROR: Error: Unable to find module implementing
>>> foreign type JavaScriptCore.Value
>>>
>>>
>>> What's the purpose of register_script_message_handler at all? What am I
>>> missing?
>>>
>>>
>> Andrea, this is the problem Philip raised earlier and I replied to. I use
>> this library to solve the problem: https://github.com/sa
>> ifulbkhan/wkjscore-result
>>
>>   7 import * as WkJsCore from '../../gjs/WkJsCore'
>> ...
>>  85         let contentManager = this.webkit.get_user_content_manager();
>>  86         if (!contentManager.register_scri
>> pt_message_handler('slinternal')) {
>>  87             throw "register_script_message_handler() failed";
>>  88         }
>>  89         contentManager.connect("script-message-received::foobar",
>> (obj, jsResult) => {
>>  90             let wkResult = WkJsCore.Result.new(jsResult);
>>  91             let str = wkResult.process_result_as_string();
>>
>>
>> Unfortunately JavaScriptCore doesn't provide it's own GIR API to access
>> the JS data :(
>>
>>
>>>
>>>
>>> On Wed, Nov 1, 2017 at 11:02 AM, Andrea Giammarchi <
>>> andrea.giammar...@gmail.com> wrote:
>>>
>>>> I've quickly provided a proof of concept but you could have a
>>>> JSONChannel class singleton on the client side that queue each info and
>>>> wait for the GJS side to receive one before sending another.
>>>>
>>>> I might try a real implementation though and see how it works.
>>>>
>>>> however, this is just a work around for the fact you can send messages
>>>> without any content (... and I wonder how that can be useful in any way 
>>>> ...)
>>>>
>>>> Regards
>>>>
>>>> On Wed, Nov 1, 2017 at 10:50 AM, Sam Jansen <sam.jan...@starleaf.com>
>>>> wrote:
>>>>
>>>>>
>>>>>
>>>>> On 1 November 2017 at 11:55, Andrea Giammarchi <
>>>>> andrea.giammar...@gmail.com> wrote:
>>>>>
>>>>>> Actually the `notify::title` with a prefixed "secret-channel" and
>>>>>> serialized JSON looks like the best of them all, for the time being, as 
>>>>>> it
>>>>>> makes it straight forward for both client and server to communicate.
>>>>>>
>>>>>> ```js
>>>>>> // listen to each response
>>>>>> new MutationObserver(m => {
>>>>>>   if (/^secret:response=/.test(document.title)) {
>>>>>>     const data = JSON.parse(document.title.slic
>>>>>> e(RegExp['$&'].length));
>>>>>>     document.title = '';
>>>>>>     console.log(data);
>>>>>>   }
>>>>>> }).observe(
>>>>>>   document.querySelector('title'),
>>>>>>   {childList: true}
>>>>>> );
>>>>>>
>>>>>> // send info using client or simulate server sending in responses
>>>>>> document.title = 'secret:response=' + JSON.stringify({some: 'value'});
>>>>>> ```
>>>>>>
>>>>>> with a proper class/wrap to handle events and send data transparently
>>>>>> it might be a great way to exchange info
>>>>>>
>>>>>>
>>>>> I've just come to the opposite conclusion, though I don't disagree as
>>>>> such...
>>>>>
>>>>> My concern is that setting document.title, and having notify::title
>>>>> called is asynchronous (I believe). So in your JS, if one had:
>>>>>
>>>>> ```
>>>>> document.title = '1'
>>>>> document.title = '2'
>>>>> ```
>>>>>
>>>>> Then by the time notify::title is called, and you inspect your
>>>>> "webkit.title" property, I'd expect you'd only see the '2' value, and
>>>>> (likely) not the '1'.
>>>>>
>>>>> It's possible to solve this by ensuring the GJS side has picked up a
>>>>> message, and e.g. reset the title, I suppose. This feels like an awkward
>>>>> solution to me though.
>>>>>
>>>>>
>>>>>>
>>>>>>
>>>>>> On Wed, Nov 1, 2017 at 5:53 AM, Sam Jansen <sam.jan...@starleaf.com>
>>>>>> wrote:
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On 1 November 2017 at 05:43, <philip.chime...@gmail.com> wrote:
>>>>>>>
>>>>>>>> On Thu, Oct 12, 2017 at 5:23 AM Andrea Giammarchi <
>>>>>>>> andrea.giammar...@gmail.com> wrote:
>>>>>>>>
>>>>>>>>> FWIW I've used the location with a private channel as protocol to
>>>>>>>>> intercept calls to/from the page and GJS.
>>>>>>>>>
>>>>>>>>> https://github.com/WebReflection/jsgtk-twitter/blob/master/a
>>>>>>>>> pp#L162-L175
>>>>>>>>>
>>>>>>>>> The channel is a random string: https://github.com/Web
>>>>>>>>> Reflection/jsgtk-twitter/blob/master/app#L59
>>>>>>>>>
>>>>>>>>> From the page, which is aware of the "secret" channel, I call GJS
>>>>>>>>> actions via location.href = `secret1234:method(${encodeURI
>>>>>>>>> Component(JSON.stringify(value))})`;
>>>>>>>>>
>>>>>>>>> The protocol secret1234 is intercepted and the
>>>>>>>>> `controller.method(JSON.parse(decodeURIComponent(restOfURI)))`
>>>>>>>>> invoked.
>>>>>>>>>
>>>>>>>>> To signal the page everything is fine I use
>>>>>>>>> this.webView.runJavaScript https://github.com/WebReflect
>>>>>>>>> ion/jsgtk-twitter/blob/master/app#L377
>>>>>>>>>
>>>>>>>>> The page has a listener for the `secret1234` event on the main
>>>>>>>>> window, and such listener is instrumented to react accordingly with 
>>>>>>>>> the
>>>>>>>>> CustomEvent .detail payload/info.
>>>>>>>>>
>>>>>>>>> This might look a bit convoluted, and it has JSON serialization as
>>>>>>>>> limitation for the kind of data you want to pass (i.e. I use base64 
>>>>>>>>> encoded
>>>>>>>>> images as source from remotely fetched files enabling somehow CORS for
>>>>>>>>> whatever I want) but it worked well, circumventing the missing
>>>>>>>>> communication channel available in Qt.
>>>>>>>>>
>>>>>>>>> Maybe today there are better ways for doing a similar thing and if
>>>>>>>>> that's the case, please share.
>>>>>>>>>
>>>>>>>>
>>>>>>>> Here is another, fairly new, way to do it. Start out by registering
>>>>>>>> a "script message handler":
>>>>>>>> http://devdocs.baznga.org/webkit240~4.0_api/webkit2.usercont
>>>>>>>> entmanager#method-register_script_message_handler
>>>>>>>>
>>>>>>>> To send a message to the page, use the same thing that Andrea uses:
>>>>>>>> http://devdocs.baznga.org/webkit240~4.0_api/webkit2.webview#
>>>>>>>> method-run_javascript
>>>>>>>>
>>>>>>>> To send a message from the page to the GJS program, use the
>>>>>>>> postMessage() method mentioned in the documentation, and connect to 
>>>>>>>> this
>>>>>>>> signal in your GJS program to receive the message:
>>>>>>>> http://devdocs.baznga.org/webkit240~4.0_api/webkit2.usercont
>>>>>>>> entmanager#signal-script-message-received
>>>>>>>>
>>>>>>>>
>>>>>>> Excellent - I had not noticed this. My first attempt at
>>>>>>> communicating between WebKit2 and GJS was via setting "document.title" 
>>>>>>> and
>>>>>>> having GJS connect to the "notify::title" signal! Not a great approach,
>>>>>>> this looks much better.
>>>>>>>
>>>>>>>
>>>>>>>> Although I just realized that unfortunately the values won't be
>>>>>>>> able to be marshalled into GJS since you need to use the 
>>>>>>>> JavaScriptCore API
>>>>>>>> to get at them. This is a really nice method in C, but in JS you can 
>>>>>>>> only
>>>>>>>> use it to send a message without any content. That is annoying. I 
>>>>>>>> should
>>>>>>>> probably open up an issue about this.
>>>>>>>>
>>>>>>>>
>>>>>>> I just hit upon this problem myself. In researching it, I found it
>>>>>>> is solved (at least well enough for my use-case) with this open source
>>>>>>> library:
>>>>>>>
>>>>>>> https://github.com/saifulbkhan/wkjscore-result
>>>>>>>
>>>>>>> It's awkward having another dependency for me, especially one that
>>>>>>> isn't in a normal Ubuntu/Fedora/etc. package, but otherwise this 
>>>>>>> approach
>>>>>>> worked fine for me.
>>>>>>>
>>>>>>>
>>>>>>>> On Wed, Oct 11, 2017 at 12:57 PM, Adriano Patrizio <
>>>>>>>>> adriano.patri...@hotmail.com> wrote:
>>>>>>>>>
>>>>>>>>>> Thank you for response, this is my problem: have necessity to
>>>>>>>>>> implement methods into my web application webkit2 based and 
>>>>>>>>>> comunicate with
>>>>>>>>>> GJS script (example: filesystem functions to read and write files or 
>>>>>>>>>> window
>>>>>>>>>> managment).
>>>>>>>>>>
>>>>>>>>>
>>>>>>>> Regards,
>>>>>>>> Philip C
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> javascript-list mailing list
>>>>>>>> javascript-list@gnome.org
>>>>>>>> https://mail.gnome.org/mailman/listinfo/javascript-list
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>
_______________________________________________
javascript-list mailing list
javascript-list@gnome.org
https://mail.gnome.org/mailman/listinfo/javascript-list

Reply via email to