WebBrowser vs IFrame

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

WebBrowser vs IFrame

Bilbosax
I have come to the final part of my app development that I have feared the
most.  I will have a lot of questions about this because I am so in the
dark, so here it goes.

I need a Google Map in my Royale project.  In Flex, this was done with an
ANE or in the older days with StageWebView.  You create an HTML document
that contains the structure for the map as well as the Javascript functions
that can add or delete markers, add or delete info windows, center the map,
etc.  The HTML file is then set as the url for the stagewebview, and you
have yourself a map.  A simple HTML version looks like this:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
   
  </head>
  <body>
    <div id="map"></div>
   
   
  </body>
</html>

The challenge was communicating between the javascript in the StageWebView,
and the actionscript in Flex.  To talk with the javascript, you would simply
invoke the javascript protocol in your url, and it would call the function
after the word "javascript:" like this:

webView.loadUrl("javascript:addMarker('39.0679459','-86.148456','$350,000')");

Talking to Actionscript from Javascript was a little tricker.  StageWebView
throws an event called "locationChanging", so you could basically change the
location in javascript and throw in a string containing your information to
parse out and call your function in actionscript.  So in javascript, you
would have:

function sendLatLng() {
    location.href = "?lat=" + lat  +"&lng=" + lng;
}

and you would catch it in actionscript like this:

webView.addEventListener(LocationChangeEvent.LOCATION_CHANGING,
locationChanging);

function locationChanging(e:LocationChangeEvent):void {
    e.preventDefault();
    var query:String = e.location.split("?")[1];
    var vars:URLVariables = new URLVariables(query);
    trace(vars.lat, var.lng);
}


So I have run into a wall using the two components available in Royale to
make a similar setup, WebBrowser and IFrame.  Both are great, but only seem
to allow one way communication.  WebBrowser has a "locactionChange" event,
so I can use it to talk to actionscript the way that I was doing with
StageWebView, but adding "javascript" to the front of the url property does
not allow actionscript to call javascript functions.

IFrame on the otherhand does allow you to add "javascript" to the front of
the src property, so you can call javascript functions from actionscript,
but it does not have a "locationChange" event, so I can't send strings from
javascript to actionscript.

So I'm stuck.  One component allows me to talk from actionscript to
javascript, and the other from javascript to actionscript.  But neither does
both.  I'm kinda amateurish at creating my own classes, but I've tried to
wrap my head around trying to use @Externs, but the HTML file has to exist
inside of a webview or iframe component, so I feel trapped within the walls
of those constructs to get information into or out of those components.

Am I missing something obvious?  Is there any way that "locationChange"
could easily be added to the IFrame component, or adding the "javascript:"
protocol to the url property of the WebBrowser?




--
Sent from: http://apache-royale-users.20374.n8.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: WebBrowser vs IFrame

Harbs
The way you communicate between iframes and their parent windows in Javascript is by using postMessage.[1]

We don’t have any code which wraps that, but there’s no reason why you can’t use the postMessage APIs directly. You’d do something like this:
window["top"]["postMessage"]("foobaz",'*');
window.parent["postMessage"]("foobaz", '*');

or to send a message to the iframe:

myIframe.element.contentWindow["postMessage"]("foobaz",'*’);

To use the message you need to add an event listener to the window that the message is posted to. Messages must be content which can be serialized. You can also optionally pass a Transferable[2], but I never have actually tried that.

HTH,
Harbs

[1]https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
[2]https://developer.mozilla.org/en-US/docs/Web/API/Transferable

> On Feb 22, 2021, at 3:39 AM, Bilbosax <[hidden email]> wrote:
>
> I have come to the final part of my app development that I have feared the
> most.  I will have a lot of questions about this because I am so in the
> dark, so here it goes.
>
> I need a Google Map in my Royale project.  In Flex, this was done with an
> ANE or in the older days with StageWebView.  You create an HTML document
> that contains the structure for the map as well as the Javascript functions
> that can add or delete markers, add or delete info windows, center the map,
> etc.  The HTML file is then set as the url for the stagewebview, and you
> have yourself a map.  A simple HTML version looks like this:
>
> <!DOCTYPE html>
> <html>
>  <head>
>    <meta name="viewport" content="initial-scale=1.0">
>    <meta charset="utf-8">
>
>  </head>
>  <body>
>    <div id="map"></div>
>
>
>  </body>
> </html>
>
> The challenge was communicating between the javascript in the StageWebView,
> and the actionscript in Flex.  To talk with the javascript, you would simply
> invoke the javascript protocol in your url, and it would call the function
> after the word "javascript:" like this:
>
> webView.loadUrl("javascript:addMarker('39.0679459','-86.148456','$350,000')");
>
> Talking to Actionscript from Javascript was a little tricker.  StageWebView
> throws an event called "locationChanging", so you could basically change the
> location in javascript and throw in a string containing your information to
> parse out and call your function in actionscript.  So in javascript, you
> would have:
>
> function sendLatLng() {
>    location.href = "?lat=" + lat  +"&lng=" + lng;
> }
>
> and you would catch it in actionscript like this:
>
> webView.addEventListener(LocationChangeEvent.LOCATION_CHANGING,
> locationChanging);
>
> function locationChanging(e:LocationChangeEvent):void {
>    e.preventDefault();
>    var query:String = e.location.split("?")[1];
>    var vars:URLVariables = new URLVariables(query);
>    trace(vars.lat, var.lng);
> }
>
>
> So I have run into a wall using the two components available in Royale to
> make a similar setup, WebBrowser and IFrame.  Both are great, but only seem
> to allow one way communication.  WebBrowser has a "locactionChange" event,
> so I can use it to talk to actionscript the way that I was doing with
> StageWebView, but adding "javascript" to the front of the url property does
> not allow actionscript to call javascript functions.
>
> IFrame on the otherhand does allow you to add "javascript" to the front of
> the src property, so you can call javascript functions from actionscript,
> but it does not have a "locationChange" event, so I can't send strings from
> javascript to actionscript.
>
> So I'm stuck.  One component allows me to talk from actionscript to
> javascript, and the other from javascript to actionscript.  But neither does
> both.  I'm kinda amateurish at creating my own classes, but I've tried to
> wrap my head around trying to use @Externs, but the HTML file has to exist
> inside of a webview or iframe component, so I feel trapped within the walls
> of those constructs to get information into or out of those components.
>
> Am I missing something obvious?  Is there any way that "locationChange"
> could easily be added to the IFrame component, or adding the "javascript:"
> protocol to the url property of the WebBrowser?
>
>
>
>
> --
> Sent from: http://apache-royale-users.20374.n8.nabble.com/

Reply | Threaded
Open this post in threaded view
|

Re: WebBrowser vs IFrame

Bilbosax
@Harbs, thanks for responding.  Please be patient because I am very new to
this.  I have a couple of questions about this approach because it does not
make sense to me.  I am not trying to communicate between different iframes,
I am trying to get simple data OUT of an iframe, and back into my
actionscript.  On the asdocs for IFrame, there is no mention of the event
"message" in IFrame, and I can't get it to work.  Inside of the IFrame html
file, I have tried all three of these:

        window["top"]["postMessage"]("foobaz",'*');
        window.parent["postMessage"]("foobaz", '*');
        postMessage("foobaz", '*');

In Actionscript, I have the following:

        map.addEventListener("message", mapsEventHandler);

        public function mapsEventHandler(event:Event):void {
            trace("I Heard The Message");
        }

        <html:Iframe localId="map" width="100%" height="100%"/>

In it's simplest form, if the IFrame component was able to hear the
postMessage from the actionscript side, it should have traced out "I Heard
The Message".  I know you are good at this stuff, what am I missing?



--
Sent from: http://apache-royale-users.20374.n8.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: WebBrowser vs IFrame

Harbs
The issue is that you’re attaching the event listener to the component or the element.

postMessage is always fired on a Window object and you need to listen to the Window you are posting the message to.

If you are in an iframe, window.parent is the immediate parent Window which holds the iframe. window.top is the top-most window in the heirarchy (significant when you have nested iframes).

As long as you post to and attach the event listener to the correct Window object, you should be fine with going both into and out of an iframe.

Assuming you have only a single level of nesting of your iframes, you would use

myIframe.element.contentWindow.parent["postMessage"]("foobaz",'*’); to send a message out and in your code you would use window.addEventListener(“message”,myHandler);

To go in, you’d use myIframe.element.contentWindow.["postMessage"]("foobaz",'*’); and myIframe.element.contentWindow.addEventListener(“message”,myOtherHandler); Although presumably, you’d be in the inner iframe code and it would just be “window”.

HTH,
Harbs

> On Feb 22, 2021, at 9:14 PM, Bilbosax <[hidden email]> wrote:
>
> @Harbs, thanks for responding.  Please be patient because I am very new to
> this.  I have a couple of questions about this approach because it does not
> make sense to me.  I am not trying to communicate between different iframes,
> I am trying to get simple data OUT of an iframe, and back into my
> actionscript.  On the asdocs for IFrame, there is no mention of the event
> "message" in IFrame, and I can't get it to work.  Inside of the IFrame html
> file, I have tried all three of these:
>
>        window["top"]["postMessage"]("foobaz",'*');
>        window.parent["postMessage"]("foobaz", '*');
>        postMessage("foobaz", '*');
>
> In Actionscript, I have the following:
>
>        map.addEventListener("message", mapsEventHandler);
>
>        public function mapsEventHandler(event:Event):void {
>            trace("I Heard The Message");
>        }
>
>        <html:Iframe localId="map" width="100%" height="100%"/>
>
> In it's simplest form, if the IFrame component was able to hear the
> postMessage from the actionscript side, it should have traced out "I Heard
> The Message".  I know you are good at this stuff, what am I missing?
>
>
>
> --
> Sent from: http://apache-royale-users.20374.n8.nabble.com/

Reply | Threaded
Open this post in threaded view
|

Re: WebBrowser vs IFrame

Bilbosax
Harbs, this worked brilliantly!  My problem is solved.  Thank you for your
feedback.

With Royale, I think I need to stop thinking so much like a Flex developer
and realize that this all HTML/Javascript/CSS in the end.  I am just so used
to the constructs of Flex after all of these years.  Probably need to read
up on web design because I was not grasping that "window" was even an object
in Flex.

Just in case anyone else has run into this issue, it turns out that there is
a wrapper for Google Maps in Royale that I was unaware of and is not well
documented.  You can find it in the examples under the name of MapSearch
which uses the Google Map APIs.

Thanks, I feel relieved.  Now to see what kind of data I can actually pass
this way.



--
Sent from: http://apache-royale-users.20374.n8.nabble.com/
Reply | Threaded
Open this post in threaded view
|

Re: WebBrowser vs IFrame

Piotr Zarzycki
Bill,

This is the case exactly! I catch myself many times with the Flex way of thinking, but HTML/JS world is very different. :) 

Thanks,
Piotr

wt., 23 lut 2021 o 19:53 Bilbosax <[hidden email]> napisał(a):
Harbs, this worked brilliantly!  My problem is solved.  Thank you for your
feedback.

With Royale, I think I need to stop thinking so much like a Flex developer
and realize that this all HTML/Javascript/CSS in the end.  I am just so used
to the constructs of Flex after all of these years.  Probably need to read
up on web design because I was not grasping that "window" was even an object
in Flex.

Just in case anyone else has run into this issue, it turns out that there is
a wrapper for Google Maps in Royale that I was unaware of and is not well
documented.  You can find it in the examples under the name of MapSearch
which uses the Google Map APIs.

Thanks, I feel relieved.  Now to see what kind of data I can actually pass
this way.



--
Sent from: http://apache-royale-users.20374.n8.nabble.com/


--

Piotr Zarzycki