Closed GoogleCodeExporter closed 9 years ago
Also, semi-related to issue #162, I think the reliance on a document.write
('script...deferred...') type of IE DomContentLoaded emulation is bound to
cause
problems if swfobject is dynamically added to a page that is already loaded, as
document.write() commands have been known to overwrite some or all of the
existing
DOM in certain circumstances.
I think the onScroll type trick is clever and has some good possibilities to it.
Original comment by get...@gmail.com
on 5 Sep 2008 at 4:38
Another negative argument:
http://code.google.com/p/swfobject/issues/detail?id=209
Original comment by bobbyvandersluis
on 4 Nov 2008 at 9:39
In SWFObject 2.2 alpha 1 we have implemented a new method to simulate
DomContentLoaded event in Internet Explorer. It is based on Diego Perini's
solution [
http://javascript.nwbox.com/IEContentLoaded/ ], which has also be included in
libraries like jQuery.
Advantage of this approach is:
- inline detection instead of relying on an ugly detection method that includes
document.write and an invalid path
Possible disadvantage of this approach is:
- when you include the library in an iframe it will only fire on onload of the
loaded
document
Original comment by bobbyvandersluis
on 18 Nov 2008 at 4:37
Hey Bobby...nice addition to cover MS faults.
A small suggestion for the IEContentLoaded addition you recently made:
// Internet Explorer on Windows
if (ua.ie && ua.win) {
document.attachEvent('onreadystatechange',
function() {
if (document.readyState == 'complete') {
document.detachEvent('onreadystatechange', arguments.callee);
callDomLoadFunctions();
}
}
);
// not inside an iframe
if (win == top) {
timer = setInterval(function() {
try {
doc.documentElement.doScroll("left");
} catch(e) {
return;
}
callDomLoadFunctions();
}, 10);
}
}
The 'onreadystatechange' is needed to ensure IE fires events in correct order,
also
when pages do not contain binary assets or those assets are very small or
cached.
The idea is that both the "doScroll" and "onreadystatechange" events will fire,
we
just serve the first to come and forget the other. Depending on the properties
of the
loaded page the order in which the two will fire is not predictable, but is not
so
important for the task of the DOMContentLoaded issue.
What instead is very important is that IEContentLoaded should always precede
"onload"
event. Without the "onreadystatechange" event you can not ensure/enforce this
order
100% of the time.
Also, you have to make sure "callDomLoadFunctions()" is only called once by
using a flag.
It is necessary to move the "callDomLoadFunction()" out of the try/catch block,
elsewhere some javascript error my remain hidden to developers (trapped in the
try).
Hope it helps overcome that nasty IE bug. It works for IE8 too and is important
since
that is still an open issue for Microsoft (after many years).
One last thing... the original solution used setTimeout, don't know is
setInterval
can introduce notable behavior differences or leaks on IE. You just know where
to
look in case this happen in your tests.
Feel free to contact me should you have any questions or suggestions about it.
Thank you for using it and spread the word.
--
Diego Perini
Original comment by diego.pe...@gmail.com
on 25 Nov 2008 at 8:21
Hi Diego, thanks for your comments, and for finding a great solution of course
:-)
Regarding onreadystatechange, Mark Wubben and Dean Edwards researched this
event,
Mark even documented it [
http://novemberborn.net/javascript/domcontentloaded-style-information ], and
one of
his main conclusions was:
'It turns out that in Internet Explorer document.readyState fires after the
loading
of the image, and right before window.onload. In effect, it’s useless. The
“official,” script.readyState variant does fire before the image loads, and
is indeed
the correct version.'
Like jQuery, SWFObject already has a cross-browser unload function as fallback,
so
personally I don't see the use in also adding the onreadystatechange event. Am I
missing something here?
Regarding moving the "callDomLoadFunction()" out of the try/catch block, that's
a
good one, I've updated this for the next alpha.
Regarding setInterval vs setTimeout question. John Resig has written a post
about it
a while ago: [ http://ejohn.org/blog/how-javascript-timers-work/ ]. One of his
conclusions was that:
'setTimeout(function(){
/* Some long block of code... */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/* Some long block of code... */
}, 10);
These two pieces of code may appear to be functionally equivalent, at first
glance,
but they are not. Notably the setTimeout code will always have at least a 10ms
delay
after the previous callback execution (it may end up being more, but never less)
whereas the setInterval will attempt to execute a callback every 10ms
regardless of
when the last callback was executed.'
So I think you're right, from an execution point of view setTimeout will be a
less
processor taxing and a bit cleaner solution, because it doesn't queue up its own
calls. Will change this for the next alpha too.
If you have any additional comments, please let us know.
Original comment by bobbyvandersluis
on 26 Nov 2008 at 10:36
'cross-browser unload' -> onload, of course ;-)
Original comment by bobbyvandersluis
on 26 Nov 2008 at 10:37
SWFObject 2.2 alpha 3 contains a series of updates (comments 4-6).
Original comment by bobbyvandersluis
on 26 Nov 2008 at 2:37
Bobby,
I completely agree and recognize as valid those test you mention. The
"onreadystatechange" fires after the images are loaded, but the images or flash
may
be already cached and retrieving them will be really fast in today browsers.
The "onreadystatechange" is there also to catch those situations (most of the
time
except the first visit to the page). The first time the "doScroll()" trick will
do
the job, when everything is cached the standard Microsoft event will do the job.
Notice that Mark and Dean concluded:
'It turns out that in Internet Explorer document.readyState fires after the
loading
of the image, and right before window.onload.'
So the part we are interested in is exactly "it fires before onload". That's the
trick we were missing. Since it fires before "onload" it is good enough for us
to
keep a consistent load order on all browser.
Otherwise the "onload" event will sometime fire before on IE, and the worst is
the it
will do that only on IE. So if you have different things starting at READY time
and
others at ONLOAD time you will find yourself with different behavior in
different
browsers.
I published some test cases showing the problem both on my lab site and on
various
lists like jQuery and Prototype showing the problem. This technique is
currently used
by Google, jQuery, ExtJS and many other libraries out there.
jQuery has currently accepted the patch related to the "onreadystatechange"
event,
the ticket related to this was #2614.
Not that you should blindly follow what the other do, but if you want to try it
yourself put a console.log() line in both methods and see when each of them
does the
job. You will realize that "doScroll()" is mostly useful only at the very first
visit
alll the other cached hits should be routed through "onreadystatechange".
This is especially visible when there are no images or external binaries in the
file
but this is only to be able to see the problem easily, there are many other
situations that trigger that special behavior in IE like the Back/Forward
buttons,
Reload button, Refresh Menu Item and also presence of FORMs in the HTML.
The real problem with my solution is that the "doScroll()" method does not work
in
iframes, so the "onreadystatechange" is useful here too, it will fire a bit
late in
iframes but with a higher degree of consistency with other browser. The other
way is
just too risky for most developers. The "document.write" will overwrite your
content
first or later, that solution seems too tighten to network delays.
Hope these info may be of help, you can find more info and talks about it on the
jQuery list or in the ExtJS forum.
Let me know if I can be of further help with this.
--
Diego
Original comment by diego.pe...@gmail.com
on 27 Nov 2008 at 3:17
Ok, swfobject 2.2 alpha4 now has the following functionality:
var onDomLoad = function() {
if (!ua.w3cdom) { return; }
if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof
doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body)))
{ //
function is fired after onload, e.g. when script is inserted dynamically
callDomLoadFunctions();
}
if (!isDomLoaded) {
if (typeof doc.addEventListener != UNDEF) {
doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false);
}
if (ua.ie && ua.win) {
doc.attachEvent("onreadystatechange", function() {
if (doc.readyState == "complete") {
doc.detachEvent("onreadystatechange", arguments.callee);
callDomLoadFunctions();
}
});
if (win == top) { // if not inside an iframe
(function(){
if (isDomLoaded) { return; }
try {
doc.documentElement.doScroll("left");
}
catch(e) {
setTimeout(arguments.callee, 0);
return;
}
callDomLoadFunctions();
})();
}
}
if (ua.webkit) {
(function(){
if (isDomLoaded) { return; }
if (!/loaded|complete/.test(doc.readyState)) {
setTimeout(arguments.callee, 0);
return;
}
callDomLoadFunctions();
})();
}
addLoadEvent(callDomLoadFunctions);
}
}();
I think that this is exactly in line with your comments, not?
Original comment by bobbyvandersluis
on 27 Nov 2008 at 1:00
Good work Bobby, the IE part seems complete to me, at least as I depicted it.
Put it under test with some of the cases you already have about this specific IE
misbehaviors and let me know if it is able to fix the known failing tests or
not.
Hope this helps mitigate some of the mess of the most hated browser.
--
Diego
Original comment by diego.pe...@gmail.com
on 27 Nov 2008 at 8:19
Included in the SWFObject 2.2 beta1 release
Original comment by bobbyvandersluis
on 16 Apr 2009 at 3:05
Original issue reported on code.google.com by
bobbyvandersluis
on 31 Aug 2008 at 11:19