How to adjust a GWT frame height to get no scrollbars (100% of body content)?

1,958 views
Skip to first unread message

marian lux

unread,
Jan 15, 2014, 7:51:40 AM1/15/14
to google-we...@googlegroups.com
I want to set the frame-height to the height of the content in my frame. So I can display it in mgwt with normal scrolling behavior.
 
The following code is not working:
in my ViewImpl.java:

constructor:
frame = new Frame(some-url/xyz.html");

frame.getElement().setId("framename");
setFrameSize("framename");

.....
.....

JSNI-method in this class
    public native boolean setFrameSize (String id)
    /*-{
            var newheight;
            var newwidth;
       
            if($doc.getElementById){
                newheight=$doc.getElementById(id).contentWindow.$doc.body.scrollHeight;
                newwidth=$doc.getElementById(id).contentWindow.$doc.body.scrollWidth;
            }
       
            $doc.getElementById(id).height= (newheight) + "px";
            $doc.getElementById(id).width= (newwidth) + "px";
            return true;
    }-*/;

marian lux

unread,
Jan 15, 2014, 10:08:58 AM1/15/14
to google-we...@googlegroups.com
And here is the exception-text I get:

uncaught: Exception caught: Exception caught: Exception caught: Exception caught: (TypeError) @xyz.client.views.experimental.FrameViewGwtImpl::setFrameSize(Ljava/lang/String;)([string: 'framename']): Cannot read property 'contentWindow' of null

Jens

unread,
Jan 15, 2014, 10:58:24 AM1/15/14
to google-we...@googlegroups.com
You must first add the Frame to the document otherwise doc.getElementById() can not find it. You also have to wait until the frame content is fully loaded before reading any size related values.

Finally your setFrameSize() seems not optimal. You call 4x getElementById() instead of just 1x (keep a reference of the found element) and the if() does not protect you from anything as you call $doc.getElementById inside and outside the if().

Finally as a reminder: $doc is a special GWT variable so if your frame content is not a GWT app then calling $doc inside the frame will not work.

-- J.

marian lux

unread,
Jan 15, 2014, 12:10:23 PM1/15/14
to google-we...@googlegroups.com
Thank you! If I understand all correct:

1)
in my ViewImpl-Class in the Consructor I have to create the frame and load the content.
The content (html-url) is from my war-directory:
frame = new Frame(GWT.getHostPageBaseURL() + "ClientData/myhtml.html");
frame.getElement().setId("framename");

=> $doc is right here because it is in my domain?

2)
After that I should wait until the frame content is fully loaded.
=> How can I handle this?? 
For testing I added a Button in my ViewImpl-Class. After clicking(tap) the button, I call the setFrameSize method with the correct id.
optimizeFrameSize("framename");

3)
If the content is loaded I call the setFrameSize()-Method.
    public native boolean setFrameSize (String id)
    /*-{
            var newheight;
            var newwidth;
            var frame = $doc.getElementById(id)
       
            if(frame !=null){
                newheight=frame.contentWindow.$doc.body.scrollHeight;
                newwidth=frame.contentWindow.$doc.body.scrollWidth;
                frame.height= (newheight) + "px";
                frame.width= (newwidth) + "px";
                return true;
            }
            return false;
    }-*/;

(The old code was from internet. I never coded JS before.)


After the three steps I get the following exception-text ("property 'body'"?):
uncaught: Exception caught: Exception caught: (TypeError) @xyz.client.views.experimental.FrameViewGwtImpl::optimizeFrameSize(Ljava/lang/String;)([string: 'framename']): Cannot read property 'body' of undefined

Jens

unread,
Jan 15, 2014, 2:32:42 PM1/15/14
to google-we...@googlegroups.com
1)
in my ViewImpl-Class in the Consructor I have to create the frame and load the content.
The content (html-url) is from my war-directory:
frame = new Frame(GWT.getHostPageBaseURL() + "ClientData/myhtml.html");
frame.getElement().setId("framename");

=> $doc is right here because it is in my domain?

$doc is correct because you are in a GWT app. GWT is executed in an iFrame and if you would only write "document" you would get the iFrame document and not the window document. Same with $wnd. So in a GWT app you always use $wnd and $doc inside JSNI functions to access the top level window and document.
 

2)
After that I should wait until the frame content is fully loaded.
=> How can I handle this?? 

Frame.addLoadHandler(). 

 
3)
If the content is loaded I call the setFrameSize()-Method.
    public native boolean setFrameSize (String id)
    /*-{
            var newheight;
            var newwidth;
            var frame = $doc.getElementById(id)
       
            if(frame !=null){
                newheight=frame.contentWindow.$doc.body.scrollHeight;
                newwidth=frame.contentWindow.$doc.body.scrollWidth;

As already said in my previous reply: $doc is a GWT variable and if your Frame does not show a GWT app then this variable does simply not exist in that Frame. Instead of $doc you then have to use "document": frame.contentWindow.document.body.scrollWidth.


-- J.

marian lux

unread,
Jan 16, 2014, 4:17:13 AM1/16/14
to google-we...@googlegroups.com
Jens, thank you very much!
You helped me a lot! It works fine.

For others, who have the same problem, here is the working code (JSNI method):
public native boolean optimizeFrameSize (String id)
    /*-{
            var newheight;
            var newwidth;
            var frame = $doc.getElementById(id)
       
            if(frame !=null){
                newheight=frame.contentWindow.document.body.scrollHeight;
                newwidth=frame.contentWindow.document.body.scrollWidth;

                frame.height= (newheight) + "px";
                frame.width= (newwidth) + "px";
                return true;
            }
          
            return false;
    }-*/;


Also addLoadHandler works fine!


One more question for the IFrame:
Is there a way to get with an IFrame the same scroll-experience with an HTML-widget?
The reason:
The content of the IFrame is always selectable and so scrolling works only on the left or right side on the screen of a mobile device (I use the IFrame for an mgwt-app).
If the text would be not selectable (but links are touchable) as in HTML-widgets, I would have the same scroll-experience (users can scroll by touching the content with one finger - and not only on right or left side of the screen) on my displayed IFrame.

Wayne Rasmuss

unread,
Jan 16, 2014, 8:18:16 AM1/16/14
to google-we...@googlegroups.com
Admittedly, I didn't look too closely at your use case, but I believe I've accomplished similar things using css with mgwt. You can check out my app at app.carellaborate.com.

One thing that hung my up was in mgwt the scroll panel has to be a direct child of touch panel, or something like that anyway.

If you like the idea of using css instead, I should have more time to help with an example later

marian lux

unread,
Jan 16, 2014, 12:11:43 PM1/16/14
to google-we...@googlegroups.com
Hi Wayne,

thank you! It would be very nice if you could help me with some CSS tweaks.
Your application has a good looking design and it is a good, innovative idea :-)

But I did not see any frames there, so I hope you can help me with my problem:
I want the same scrolling experience on my gwt-frame as with a gwt-html widget (scrolling with one finger on the content if it does not fit the client size - height)

Thank you in advance!

Wayne Rasmuss

unread,
Jan 16, 2014, 12:59:56 PM1/16/14
to google-we...@googlegroups.com
You're right, there's no frames there, but you should be able to make them behave like other content I think.

I saw you are using mgwt. Are you using the mgwt scroll panel? It can probably work either way, but it would help to know.

Can you point me to a live url, or maybe capture the DOM using inspect element in chrome or something so I can see exactly what's going? Providing the GWT classes that are responsible for each element would be helpful too.

marian lux

unread,
Jan 21, 2014, 4:07:13 AM1/21/14
to google-we...@googlegroups.com
It  seems to be a mgwt problem?

I have three attachments:
.) working_mobile_scroll.html
displays a normal html with an iframe and I am able to scroll everywhere on mobile browser (e.g. on Android Google Chrome)

.) FrameViewGwtImpl.java
my View-Class where the gwt-frame-widget is defined

.) Bildschirmfoto ....
a screenshot of the dom when running in development-mode

=> I am always able to scroll with two fingers (touchpad) on desktop browser but one finger scroll on mobile browser only works on my test-html "working_mobile_scroll.html" and not in my mgwt-application.
In my mgwt-application: If i tap inside the frame and want to scroll, nothing happens. Only scrolling outside the frame on left or right side with one finger is working.
Bildschirmfoto vom 2014-01-21 09:51:34.png
FrameViewGwtImpl.java
working_mobile_scroll.html

Wayne Rasmuss

unread,
Jan 21, 2014, 10:25:19 PM1/21/14
to google-we...@googlegroups.com
Well, it's a mixed bag. After investigating more, I would probably recommend just letting the frames scroll themselves like you demonstrated earlier with your sample html file.

That said, I managed to come up with a hack for you that might work, but probably won't for your case. I'm hoping it might get you started on something that does work for you. I've attached a ui builder file, the associated class didn't do anything. So, it should be easy enough for you to just dump it in a new ui builder file. You could also translate it into "regular" code.

There are two problems, I think you've alluded to them both but I'll put them in my own words, maybe an alternate perspective will help. The first problem is iframes have no ability to adjust their size based to fit their content. This means that the mgwt scroll panel can't really scroll them. The only solution I can come up with for this is what is already in this topic. That is, figure out a way to adjust the height of the iframe after the contents have been loaded.

The other problem is once this is done, the iframe will eat all the events it gets. This makes sense because the iframe needs to deal with everything a browser needs to deal with. What I have attached here is a ui builder that overlays an invisible div over the iframe. This means that mgwt is able to receive the events and scroll that page, which happens to mean that it scrolls the iframe with the invisible div. The bad news is, the iframe underneath will not receive any events. In some extremely limited cases this might be okay.

Further research into how to get events to the containing page from the iframe might help.

I'll post any new ideas if the pop into my head. 
FrameScrollerScreen.ui.xml

marian lux

unread,
Jan 22, 2014, 6:37:50 AM1/22/14
to google-we...@googlegroups.com
Thank you Wayne for the "FrameScrollerScreen.ui.xml".


The bad news is, the iframe underneath will not receive any events. In some extremely limited cases this might be okay.

In my use case it is very important that the user can interact (clicking on links) inside the iframe. On the other side, the scrolling inside the iframe is also important because the user should have always the same scrolling-experience (for all views of my application).

I also found this post form daniel (- the creator of mgwt):
https://groups.google.com/d/msg/mgwt/9P73HQc9fig/oDmy6vMjihoJ

Do you know an alternative solution or is there a hack available to handle scrolling an iframe inside a mgwt-scrollpanel (without blocking all events)?

Thank you in advance.
Marian

Wayne Rasmuss

unread,
Jan 22, 2014, 1:03:09 PM1/22/14
to google-we...@googlegroups.com
Yeah, I'm sorry if I gave you false hope. I saw the content of the thread and thought maybe I could help. I've done quite a bit with mgwt scrolling and iframes separately, but putting them together is just problematic. I don't know any hacks to get it to work. I think your only practical options are:

1.) Use the scrolling behavior of the device. You may be able to mitigate the impact on user experience by styling the iframe and/or it's container to make it intuitive to the user when the experience is different in the frame.

2.) Try to get the content of the pages without the header, body tags etc and just inject it into an element. This is essentially how some web frameworks work. You could do this by working developers on the framed site or introducing your own intermediary service that tears apart the page. If you do this, you should get express permission from the site owners. The downside of this approach is your app will have to be a suitable home for the content (the right js css etc.). You should certainly be able to work this out if the site is produced by the same company, but it will be an uphill battle if you're trying to work against arbitrary external sites.

All that said, I wouldn't say I thinks it's completely impossible to get it to work like you want to but I don't see an expedient way that I think is likely to work. One possibility might be intercepting the events from the transparent frame like I made above, processing them for drags and sending the ones that aren't part of a drag to the frame beneath. I'm not at all sure that would ever work reliably on various platforms, but I guess it might be possible.

Sorry I couldn't be more help.

Jens

unread,
Jan 22, 2014, 1:51:27 PM1/22/14
to google-we...@googlegroups.com
.) working_mobile_scroll.html
displays a normal html with an iframe and I am able to scroll everywhere on mobile browser (e.g. on Android Google Chrome)

If that works the way you want it, then its not a GWT Frame issue as the GWT Frame is just a thin wrapper around the <iframe> element. The Frame widget literally has no internal logic.

I think what breaks your experience is the MGWT ScrollPanel. If you remove it temporary from your app then it might work. If that ScrollPanel is your app's main container then an alternative would be to not use a ScrollPanel at all and instead position any header / footer using position:fixed. That way the scrolling is provided by the browser itself instead of the ScrollPanel and you still have a fixed header and footer.

-- J.

marian lux

unread,
Jan 23, 2014, 4:13:33 AM1/23/14
to google-we...@googlegroups.com
My "main" panel my  FrameViewGwtImpl.java is a LayoutPanel. If I remove the scrollpanel  from  FrameViewGwtImpl.java and set the LayoutPanel height to e.g. 1000px, the scrollbars should appear (because this is more than the client-height) like "working_mobile_scroll.html".

Additional info: in my entrypoint I did the following:
MGWTSettings mgwtSettings = new MGWTSettings();
mgwtSettings.setPreventScrolling(false);
MGWT.applySettings(mgwtSettings);

But with this setup no scrollbars are appearing.
Reply all
Reply to author
Forward
0 new messages