Email conversation
From | Philip Green |
To | Me |
Subject | importXML.js and IE5.2(.3) Mac |
Date | 26 May 2005 15:26 |
Hello Tarquin
First off, thanks for this useful script.
To be honest, this could apply to any (fairly DOM-compliant) browser
which has to fall back to the hidden <iframe /> trick to grab another
file, but as I'm fighting with IE5.2 I thought I'd share.
Specifically: The delay workaround for slow requests.
It struck me that instead of having to put an arbitrary number in a
function call and subsequently experiment with loading times, it would
be better for the checking function to verify the file was actually
loaded. This would mean the callback function would only run when it had
content it could use.
I also had annoyances with .innerHTML for some reason (it turned
read-only) and other scripts in the same page just stopping (somehow
ifr.src=url. / ifr.location.href=url; (or even using .replace();) just
took "focus" away from any other scripts, which then didn't run. No
errors, no alerts, just nothing!). I'll deal with the latter two first
as they impinge (slightly) upon the first issue.
To sort the .innerHTML annoyance I just extended the DOM calls to create
the iframe to append into the div:
var
div=document.createElement('DIV'),ifr=document.createElement('IFRAME'),n
='XML_loader_'+l;
div.style.position='absolute';div.style.visibility='hidden';div.style.to
p=div.style.left='0px';
ifr.height=ifr.width=0;ifr.name=n;
div.appendChild(ifr);document.body.appendChild(div);
To deal with other scripts stopping, I found that setting a timeout
(originally a hook into window.onload) to specify the source using the
delay parameter (so it didn't end up being superfluous after all!).
Admittedly this still means that some experimentation might be called
for, but for the most part it won't be needed (no slow / complex scripts
clogging up the browser):
setTimeout('window.frames[\'MWJ_XML_loader_'+x+'\'].location.replace(\''
+url+'\');',delay?delay:1000);
For checking that the file has actually loaded means adding an extra
boolean in the check function using the loaded document readyState:
if( MWJ_ldD[x] && window.frames['MWJ_XML_loader_'+x] &&
window.frames['MWJ_XML_loader_'+x].window.document.readyState ==
'interactive'){
.
.
.
}
I'm using .readyState as it popped out at me when I did a quick for(var
prop in document){alert(prop);} to try and find something fairly
DOM-compliant. Note that an immediate check of .readyState will give you
"complete" when it quite clearly isn't (semantically speaking) due to
the timeout for the load.
I also considered that the interval should be cleared (as once the
file(s) have been loaded, it isn't needed any more) so there isn't a
function repeating itself when it doesn't need to:
function MWJ_checkXMLLoad() {
while (MWJ_ldD.length&&!MWJ_ldD[0]){MWJ_ldD.shift();}
if(!MWJ_ldD.length){clearInterval(window.MWJ_XML_timer);interval=null;}
.
.
}
An added sidenote: as the delay parameter isn't being used in the
setTimeout(callback) call, this means that each element pushed to
MWJ_ldD only needs the function name (I've kept setTimeout rather than
going down the eval() route):
if( MWJ_ldD[x] && window.frames['MWJ_XML_loader_'+x] &&
window.frames['MWJ_XML_loader_'+x].window.document.readyState ==
'interactive' ) {
setTimeout(
MWJ_ldD[x]+'(window.frames[\'MWJ_XML_loader_'+x+'\'].window.document);',
10 );
MWJ_ldD[x] = false;
}
All dot references to the frame document have been changed to provide a
spot of consistency :)
What do you think?
Regards
Phil Green
From | Me |
To | Philip Green |
Subject | Re: importXML.js and IE5.2(.3) Mac |
Date | 26 May 2005 16:28 |
Phil,
> It struck me that instead of having to put an arbitrary number in a
> function call and subsequently experiment with loading times, it would
> be better for the checking function to verify the file was actually
> loaded.
This is sadly not possible, as I described on the page
http://www.howtocreate.co.uk/tutorials/jsexamples/importingXML.html
(see the section titled "Why not use iframes for everything?")
> I also had annoyances with .innerHTML for some reason (it turned
> read-only)
This should happen only if your main page is being served using an XML or
XHTML content type HTTP header, but IE 5 Mac cannot use that content type
anyway, so I am guessing this is not the case. Maybe it is misinterpreting
something else.
> To sort the .innerHTML annoyance I just extended the DOM calls to create
> the iframe to append into the div:
Yep, this sounds like an acceptable approach. A more reliable approach than
innerHTML (if you are using XHTML content-type). Unfortunately, it requires
a lot more code, but sometimes that is a worthy tradeoff.
> For checking that the file has actually loaded means adding an extra
> boolean in the check function using the loaded document readyState:
Readystate is proprietary in this instance, and is not supported by browsers
like Opera 7, which also uses the iframe. As a result, I refuse to use it
(if I wanted to use incompatible code, I would just use onload, which works
in Opera 7.5+ but not IE Mac).
> while (MWJ_ldD.length&&!MWJ_ldD[0]){MWJ_ldD.shift();}
IE 5 Mac does not like shift, so this is not a viable solution, I am afraid,
although personally, I like the idea of what you are doing here.
http://www.quirksmode.org/browsers/explorer5mac.html
> What do you think?
Some nice ideas, but not quite enough to make it work cross browser, so I
would need to work on it before I could add something like this to the main
script distribution.
Cheers
Mark 'Tarquin' Wilton-Jones - author of http://www.howtocreate.co.uk/
From | Philip Green |
To | Me |
Subject | Re: importXML.js and IE5.2(.3) Mac |
Date | 26 May 2005 17:29 |
<snip />
>>> > To sort the .innerHTML annoyance I just extended the DOM calls to
>>> > create the iframe to append into the div:
>>
>> Yep, this sounds like an acceptable approach. A more reliable
>> approach than innerHTML (if you are using XHTML
>> content-type). Unfortunately, it requires a lot more code,
>> but sometimes that is a worthy tradeoff.
Not that much more and I think that if one element is being added via
DOM methods then all should (the old consistency approach again).
>> Readystate is proprietary in this instance, and is not
>> supported by browsers like Opera 7, which also uses the
>> iframe. As a result, I refuse to use it (if I wanted to use
>> incompatible code, I would just use onload, which works in
>> Opera 7.5+ but not IE Mac).
Esprit d'escalier: I realised that .readyState wasn't in Op7 immediately
after I clicked "Send". C'est la vie. Drat. Etc.
Having to munge object detection code to get it to work in both is
annoying; I was just chuffed I'd got the function to work in IE5.2 (to
be honest, I was chuffed to get ANYTHING working even slightly in
IE5.2!)
>>
>
>>> > while (MWJ_ldD.length&&!MWJ_ldD[0]){MWJ_ldD.shift();}
>
>>
>> IE 5 Mac does not like shift, so this is not a viable
>> solution, I am afraid, although personally, I like the idea
>> of what you are doing here.
>> http://www.quirksmode.org/browsers/explorer5mac.html
>>
Extending the Array prototype is something I have in all base scripts
because too many clients don't use ECMA2 capable browsers (sigh)...
if(![].push){Array.prototype.push=function(){for(var
i=0;i<arguments.length;++i){this[this.length]=arguments[i];}return
this.length;};}
if(![].pop){Array.prototype.pop=function(){var
r=null;if(this.length){r=this[this.length-1];--this.length;}return r;};}
if(![].copy){Array.prototype.copy=function(){var a=[];for(var
i=0;i<this.length;++i){a[i]=this[i].copy?this[i].copy():this[i];}return
a;};}
if(![].concat){Array.prototype.concat=function(a){var
b=this.copy();for(var i=0;i<a.length;++i){b.push(a[i]);}return b;};}
if(![].reverse){Array.prototype.reverse=function(){var
a=[],i=this.length;while(i>0){a.push(this[--i]);}return a;};}
if(![].shift){Array.prototype.shift=function(){var
r=null;if(this.length){r=this.reverse().pop();this.reverse();}return
r;};}
if(![].unshift){Array.prototype.unshift=function(){this.reverse();for(va
r
i=0;i<arguments.length;++i){this.push(arguments[i]);}this.reverse();retu
rn this.length;};}
if(![].splice){Array.prototype.splice=function(b,d){var
m=b+d,af=this.slice(m),r=d>0?this.slice(b,m-1):[];for(var
i=2;i<arguments.length;++i){af.unshift(arguments[i]);}if(b>0){this.slice
(0,b).concat(af);}else{while(this.length){this.pop();}while(af.length){t
his.push(af.pop());}}return r;};}
Most of the time, push() can be ignored as array[array.length]=obj;
works fine, but pop() and shift() are just too useful for me. The other
functions are just here for completeness' sake (due to instatiation
reasons they aren't in nice alphabetical order!).
Regards
Phil Green