OSX - WebDialog blank initially?
-
That's interesting. So it appear to be a timing issue with the load event. Strange though, the console appear to use the same loading method.
I'll try out moving that load event and also see if using the DOMReady event.
I've not really used TestUp until now. Found that blank initial window really annoying, and the code is so complex that it wasn't easy to work out what is going on.
Thanks.
-
That worked! Though I wonder why.
-
@tt_su said:
That worked! Though I wonder why.
I've seen this on several other WebDialogs on the Mac as well. Here's my theory as to the reason (feel free to poke holes, I'd love to get to the bottom of this):
First of all, I believe this happens on TestUp but not on the developer console because TestUp's HTML is a blank page that just defines javascript functions and provides a divGui element for them to target. All of the visible content of the page is created by subsequent calls from SU Ruby to javascript functions on the page. In contrast, developer console's HTML creates and lays out all of its divs. Until SU Ruby runs, the TestUp page really is blank.
The reason you see the blank page is that WebKit interprets the onload event to mean that all parts of the page have been loaded and it is ready to display. WebKit does not expect the onload event callback function to load additional content to the page via something like skp: protocol (after all, what does "loaded" mean if the onload callback can load additional pages?). So when bodyLoad() returns immediately (due to the well-worn asynchronous aspect of javascript and the skp: protocol on Mac), WebKit displays the still-blank page before Ruby has had time to do anything with it. Evidently, WebKit does not subsequently notice that the Ruby calls generate new page elements, so it does not spontaneously do a repaint. The user has to do something such as right-click to cause a repaint, and then the new content shows. Perhaps there is a javascript function that could force a repaint at the conclusion of the Ruby?
When the bodyLoad() call is moved to an ordinary script at the bottom of the body, it seems that WebKit detects the invocation of an additional content load and pauses to let it happen before painting the page. The pause gives Ruby a chance to call the javascript that populates the page. This part of the theory still bothers me a bit, because of all the other cases in which WebKit not waiting for an skp: causes WebDialog bugs. Maybe the difference is that in this case the call is within the context of the initial page load? But then how does WebKit know that Ruby is finished and the page is ready to paint?
Thoughts?
Steve -
Hmm.. I don't know. I use similar method for my own WebDialogs, but I always use jQuery and use the .ready() event which triggers when the DOM is ready - which should trigger even before onload because onload triggers when all external resources such as images and scripts are loaded. (Not a big deal with local resources, but when downloading from the web makes a big difference.) And I've never seen that behaviour then.
The initial TestUp HTML isn't completely empty, it has the basic framework for the UI element - the CSS styles should have applied it's style to that.
I think someone mentioned that it was working fine before, (and it does work fine under Windows), so I somewhat suspect there's some change in WebKit's onload event that cause some unexpected mistrigger - in terms of kicking in the redraw for the window - maybe some optimization gone wrong...
If only we had a simple bare bone example, that would make it easier to compare. It's difficult with TestUp to change one thing and not break everything.
-
I did a quick test of hooking up bodyLoad() to DOMContentLoaded
// Added this snippet to the end of TestUp's script in the head. document.addEventListener( "DOMContentLoaded", function(){ bodyLoad(); }, false );
That worked perfectly. So it does appear to be an issue with the onload event under OSX.
Mind you that DOMContentLoaded isn't working so great with older browsers and it's a bit complicated to make it work cross browser. Another reason for projects to use jQuery or similar to take care of this stuff. For now I'll just make TestUp call bodyLoad() from the bottom of the page.
-
@tt_su said:
The initial TestUp HTML isn't completely empty, it has the basic framework for the UI element - the CSS styles should have applied it's style to that.
Was the HTML changed? The version I downloaded last winter has this body (after moving bodyLoad()):
<body> <a href="javascript:;" id="btnRunTests" onclick="run();return false;"> </a> <input id="runList" type="hidden" /> <span id="headsUpDisplay"></span> <div id="divGui"></div> <script type="text/javascript"> bodyLoad() </script> </body>
There's nothing visible there. Even the <a> is whitespace! CSS can't insert content into elements!
@tt_su said:
I think someone mentioned that it was working fine before, (and it does work fine under Windows), so I somewhat suspect there's some change in WebKit's onload event that cause some unexpected mistrigger - in terms of kicking in the redraw for the window - maybe some optimization gone wrong…
It never worked for me until I moved bodyLoad() per the above snippet. The difference in Windows is without doubt due to its different handling of skp: and synchronous javascript. The bodyLoad() callback will complete before return from the event handler. Has Apple distributed a new version of WebKit? I know there was an update to Safari, but the WebKit accessed by other apps is not the same as Safari.
@tt_su said:
If only we had a simple bare bone example, that would make it easier to compare. It's difficult with TestUp to change one thing and not break everything.
Agreed! TestUp is very complex, not a good sample to experiment with!
-
martin wrote about it ages ago
http://www.martinrinehart.com/models/rubies/ruby2javascript_javascript2ruby.html#gotchas
and with 'TestUp' it has never worked on mac, the moving bodyLoad() to the end, was a refinement when this didn't work...
# This blurring forces an update so the mac displays TestUp # immediately after loading its content. if @is_mac @webdlg.show_modal @webdlg.execute_script('window.focus()') end end
john
-
@slbaumgartner said:
Was the HTML changed? The version I downloaded last winter has this body (after moving bodyLoad()):
That A element is the Run button. Elements doesn't have to have content to render, one can set the size and style of elements regardless. And in any case, the colour of the BODY element should have rendered.
@slbaumgartner said:
Has Apple distributed a new version of WebKit? I know there was an update to Safari, but the WebKit accessed by other apps is not the same as Safari.
I'm not sure about Safari Update vs WekBit update, but I do know that one update, whatever it was, some while ago broke WebDialog.set_html for a while.
-
@driven said:
martin wrote about it ages ago
http://www.martinrinehart.com/models/rubies/ruby2javascript_javascript2ruby.html#gotchas
and with 'TestUp' it has never worked on mac, the moving bodyLoad() to the end, was a refinement when this didn't work...
# This blurring forces an update so the mac displays TestUp > # immediately after loading its content. > if @is_mac > > @webdlg.show_modal > @webdlg.execute_script('window.focus()') > end > end
john
After re-reading Martin's blog and trying a few things, I noticed (on the Mac):
- TestUp creates a WebDialog and saves it in @webdlg. It uses this instance variable in all its Ruby callbacks,
discarding the dialog argument passed back from javascript. For example:
@webdlg.add_action_callback('gui_ready') do |dlg, param| gui_ready end
when the action_callback "guy_ready" is fired from javascript, it is relayed to the (no-argument) Ruby method of the same name, which uses @webdlg instead of the dlg argument. If Martin is correct, this will cause problems because the @webdlg obtained from the constructor is not yet fully wired to the page; one should always use the argument passed back in the action callback. He speculates that, in particular, the instance obtained from the constructor is not really ready to run when the onload fires. But once the page is loaded and running, actions initiated on it work fine against @webdlg. Also note that the developer console always uses the argument passed to its action callbacks, even though it retains the original dialog in an instance variable.
- you get the white screen only if bodyLoad() is called from the onload event. If you don't call it at all, per TT's assertion you get the background images loaded via CSS - though for lack of bodyLoad() the right-hand part of the screen is empty. Finally, if you call bodyLoad() in an explicit script at the bottom of the body, all is well.
- TestUp creates a WebDialog and saves it in @webdlg. It uses this instance variable in all its Ruby callbacks,
-
I saw Martin's writeup, but I don't think he got it all right.
In TestUp's case the @webdlg variable returns the same instance as the dlg argument from the callback. There is no difference to them. When you have stored the webdialog in an instance variable the webdialog argument isn't needed. (Saying that, you could create a Proc you reuse to multiple instances of an webdialog - in which case that argument is useful.)
In terms of the webdialog being ready - when you call webdialog.show you cannot interact with the content of the webdialog immediately. You have to wait for the full DOM to be ready - this is why we need to make a callback from the webdialog back to ruby and perform the rest of the work there - such as populating the webdialog with values or reading from it. I think this is what Martin was talking about.
When an HTML document is created the various events we can use is:
- Script call from the bottom of the document. (the event would trigger right before the closing HTML tag is done.)
- DOMContentReady which triggers when the HTML DOM three is processed and fully ready, but images and external CSS might not be ready.
- body.onload that triggers when everything is ready and loaded. This would be triggered last.
So since DOMContentReady works, which triggers before body.onload, then it is very strange that body.onload cause this blank window. Which also means it's not the async nature of OSX's callbacks. Maybe DOM modifications during body.onload mistriggers some events within WebKit - the onload event triggers, but maybe DOM modifications interfere with the event that cause WebKit to redraw.
And given that it works under IE it appear to be an WebKit bug related to the onload event. Because there is nothing that should say, logically, that it shouldn't work. When events that triggers earlier works, then why would the late onload not trigger?
It could even be a WebKit issue only seen when used as WebDialog. Who knows.
-
@tt_su said:
So since DOMContentReady works, which triggers before body.onload, then it is very strange that body.onload cause this blank window. Which also means it's not the async nature of OSX's callbacks. Maybe DOM modifications during body.onload mistriggers some events within WebKit - the onload event triggers, but maybe DOM modifications interfere with the event that cause WebKit to redraw.
And given that it works under IE it appear to be an WebKit bug related to the onload event. Because there is nothing that should say, logically, that it shouldn't work. When events that triggers earlier works, then why would the late onload not trigger?
It could even be a WebKit issue only seen when used as WebDialog. Who knows.
I agree with your reasoning. onload is supposed to be called after the DOM is fully parsed and all page resources have been fetched. It make no sense that bodyLoad() would work in the DOMContentReady callback and then fail later in onload unless the problem is something specific to how the onload event is processed.
I did some browsing around in the WebKit source. It will take me some time to understand how events in general, and onload in particular, are handled. But I found comments in the change logs about special traps involving the onload event. If I understand, certain web pages do dirty things in their onload handlers that caused a crash when the DOM was rendered, so long ago WebKit added patches to avoid the crash.
I wondered if setting window.location.href in the onload handler would trigger one of these traps, so I tried an onload handler that set href to an http: URL. It worked fine - displayed the specified page instead of TestUp. That inclines me to agree with your final suggestion - it would seem to be some interaction between the implementation of the skp: protocol and the onload event processing.
Anyway, the bottom line is don't call Ruby from the onload handler!!
-
New chapter for the Lost Manual.
Advertisement