Dynamic Script Insertion Revisited
|
|
Thread rating:  |
Randy Webb - 08 Aug 2007 17:56 GMT In this thread:
<URL: http://groups.google.com/group/comp.lang.javascript/browse_frm/thread/7e23f42490 c301de/56d47ba8d4d73e30?lnk=gst&q=createtextnode+randy+webb&rnum=1#56d47ba8d4d73 e30>
The problem was, and still is, that IE - no version - will allow you to use createTextNode and then appendChild it to a Script element. It throws a "Unexpected call to method or property access" error.
The only browsers, that I am aware of, that don't support createTextNode on a SCRIPT element are IE/Win, IE/MAC, and iCAB3.0.3 (Is there a newer iCAB?).
iCab and IE/mac support neither .text or .createTextNode so for this code they have become part of the "Give up Randy, it won't work there" group.
The browsers, again that I know of, that don't support the .text property are:
IE/Mac iCab3.0.3 Safari 1.3.2 Safari 2.0.4 Shiira 1.2.2 Sunrise 0.89
Safari surprised me on windows though as it supports .text, go figure.
Where it left me was wanting to use .createTextNode for support and then falling back on the .text property.
What I ended up with is this:
var isIE = false; /*@cc_on @*/ /*@if (@_jscript_version >= 4) var isIE = true; @end @*/
function executeJSString(stringToExecute){ var newScript = document.createElement('script'); newScript.type = "text/javascript"; if (isIE) { newScript.text = stringToExecute; } else { var s = document.createTextNode(stringToExecute); newScript.appendChild(s); } document.getElementById("scriptDiv").appendChild(newScript); }
Where "scriptDiv" is a container for script elements. The actual code has code in it to empty the container so that I don't end up with duplicate script blocks and/or excessive script elements.
The problem comes in if a browser, other than IE, supports .text and not .createTextNode (or errors on it like IE does). That lead me to try to set the .text property of a script element (on page load) to set a variable and then branch on that variable. The problem there comes in when the browser throws an error trying to set the .text property.
function insertScript(scriptContents) { var useIt = false; var newScript = document.createElement('script'); newScript.type = "text/javascript"; newScript.text = "var useText=true"; document.getElementById("myDiv").appendChild(newScript); //end text insert section
var newScript = document.createElement('script'); newScript.type = "text/javascript"; if(useText){ newScript.text = scriptContents; } else{ var s = document.createTextNode(scriptContents); newScript.appendChild(s); } document.getElementById("scriptDiv").appendChild(newScript); }
I don't have a browser that doesn't support .text so I can't test it thoroughly.
If anybody has any other ideas on a true feature detection approach and/or that can test the above code on any non-windows browser I would be gratefully appreciative.
Also, anybody that can test this page with a browser not listed (Other than Netscape 4.xx series and lower) and give me the results of the 5 button clicks, I would again be gratefully appreciative.
<URL: http://members.aol.com/_ht_a/hikksnotathome/loadJSFile/>
 Signature Randy Chance Favors The Prepared Mind comp.lang.javascript FAQ - http://jibbering.com/faq/index.html Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Stevo - 08 Aug 2007 18:23 GMT > The problem was, and still is, that IE - no version - will allow you to > use createTextNode and then appendChild it to a Script element. It > throws a "Unexpected call to method or property access" error. How about this:
var the_code = "alert('hello world');"; var newscript = document.createElement('script'); newscript.type = "text/javascript"; if(typeof newscript.text === 'string') newscript.text = the_code; else if(document.createTextNode) newscript.appendChild(document.createTextNode(the_code)); document.getElementById("scriptDiv").appendchild(newscript);
Are there any browsers that don't support .text? I've just tried this line in the address bar:
javascript:alert(typeof document.createElement('script').text)
in the following browsers and seen 'string' alerted.
Mac Safari 1.3 Win Safari 3.0 Win NS6.2 Win NS7.0 Win Firefox 2.0 Win IE7 Win Opera 9.2
[Steve]
Randy Webb - 08 Aug 2007 20:53 GMT Stevo said the following on 8/8/2007 1:23 PM:
>> The problem was, and still is, that IE - no version - will allow you >> to use createTextNode and then appendChild it to a Script element. It >> throws a "Unexpected call to method or property access" error. > > How about this: The logic/testing is backwards from what I preferred and that is using createTextNode if it can be successful and falling back on .text as a second course. Even the code I posted goes about attempting .text first and that logic may end up being the best route to go with.
> var the_code = "alert('hello world');"; > var newscript = document.createElement('script'); [quoted text clipped - 7 lines] > Are there any browsers that don't support .text? I've just tried this > line in the address bar: From my original post:
The browsers, again that I know of, that don't support the .text property are:
IE/Mac iCab3.0.3 Safari 1.3.2 Safari 2.0.4 Shiira 1.2.2 Sunrise 0.89
Can you test this page for me on a mac and either confirm or bust the results for Safari?
<URL: http://members.aol.com/_ht_a/hikksnotathome/loadJSFile/>
The green/red/blue area scrolls but the scrollbars are not there. I need to update it but can't get on AOL right now to upload a new one. The results there say that Safari on a Mac doesn't execute scripts if you assign it via the .text property. If that is true, and it shows that string is typeof .text then it makes the test fallible and un-usable for me.
You should get an alert as the page loads that confirms the original external file is loaded. Clicking each of the 5 buttons will do one of three things:
1) Give you an alert telling you it was successful if the browser supports that feature/method. 2) Throw an error. 3) Nothing. Indicating silent failure.
The five buttons, and what they attempt:
1) Change Source- attempts to change the .src property of a script element. 2) Change innerHMTL - inserts a script string via innerHTML. 3) createElement - uses createElement to create a script block with a .src attribute. 4) Change .text - changes the .text property of a script element. 5) createTextNode - creates the text part of a script element using createTextNode
 Signature Randy Chance Favors The Prepared Mind comp.lang.javascript FAQ - http://jibbering.com/faq/index.html Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
RobG - 08 Aug 2007 22:12 GMT [...]
> Can you test this page for me on a mac and either confirm or bust the > results for Safari? [quoted text clipped - 6 lines] > assign it via the .text property. If that is true, and it shows that > string is typeof .text then it makes the test fallible and un-usable for me. That may be true for the version os Safari listed, Safari 3.0.3 on Mac OS X 10.4.10 gives:
red, red, green, green, green.
which I think is consistent with what you reported for the Windows version.
-- Rob
Randy Webb - 09 Aug 2007 00:28 GMT RobG said the following on 8/8/2007 5:12 PM:
> [...] >> Can you test this page for me on a mac and either confirm or bust the [quoted text clipped - 15 lines] > which I think is consistent with what you reported for the Windows > version. Yes, it is consistent with the Windows version. I have added Safari 3.0.3 to the local file, thank you for the test.
 Signature Randy Chance Favors The Prepared Mind comp.lang.javascript FAQ - http://jibbering.com/faq/index.html Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices
Stevo - 08 Aug 2007 23:09 GMT > Stevo said the following on 8/8/2007 1:23 PM: > The logic/testing is backwards from what I preferred and that is using > createTextNode if it can be successful and falling back on .text as a > second course. OK. I thought maybe trying .text first was an alternative way to go.
> <URL: http://members.aol.com/_ht_a/hikksnotathome/loadJSFile/> > You should get an alert as the page loads that confirms the original > external file is loaded. Clicking each of the 5 buttons will do one of > three things: I'm not at work so can't try that on a Mac but I have tried it on IE and Firefox on Windows and noticed something. Firstly, it's not the createTextNode that fails. It's the appendChild right afterwards. Something about that text node is un-appendchild-able. I compared the properties of it between IE and Firefox and took a screenshot. I think the textContent property of the textnode created could be a simple test. For example, something like this might work:-
var the_code = "alert('hello world');"; var newscript = document.createElement('script'); newscript.type = "text/javascript"; var textnode=document.createTextNode(the_code); if(textnode.textContent && textnode.textContent==the_code) newscript.appendChild(textnode); else if(typeof newscript.text === 'string') newscript.text = the_code; document.getElementById("scriptDiv").appendchild(newscript);
That if textnode.textContent test is checking for whether the text node that was created is a good textnode and is appendchild-able. If it's not, then try .text (if that property exists).
I'm sure your code won't end up looking anything like that, but it might give you an idea for something inspired by it.
Here is the screenshot of the properties I saw:-
http://img513.imageshack.us/img513/169/createtextnodeoi9.jpg
You see IE on the left and Firefox on the right (with it's extra property textContent). I put green blobs against the matching properties. I hope this helps.
Randy Webb - 09 Aug 2007 00:47 GMT Stevo said the following on 8/8/2007 6:09 PM:
>> Stevo said the following on 8/8/2007 1:23 PM: >> The logic/testing is backwards from what I preferred and that is using >> createTextNode if it can be successful and falling back on .text as a >> second course. > > OK. I thought maybe trying .text first was an alternative way to go. It might end up having to be.
>> <URL: http://members.aol.com/_ht_a/hikksnotathome/loadJSFile/> >> You should get an alert as the page loads that confirms the original [quoted text clipped - 4 lines] > Firefox on Windows and noticed something. Firstly, it's not the > createTextNode that fails. It's the appendChild right afterwards. Yes. It is because IE falls down on itself when you try to appendChild a textNode created with createTextNode to a SCRIPT element.
> Something about that text node is un-appendchild-able. It isn't the text node itself, but the container you are trying to appendChild it to. IE just won't let you appendChild it to a SCRIPT element. You can appendChild it to scriptDiv and it works flawlessly. It is only when you appendChild it to a SCRIPT element that IE barfs all over itself.
> I compared the properties of it between IE and Firefox and took a screenshot. > I think the textContent property of the textnode created could be a simple test. [quoted text clipped - 6 lines] > if(textnode.textContent && textnode.textContent==the_code) > newscript.appendChild(textnode); Internet Explorer 7 passes both of those tests and then barfs all over the appendChild line.
> else if(typeof newscript.text === 'string') > newscript.text = the_code; [quoted text clipped - 12 lines] > property textContent). I put green blobs against the matching > properties. I hope this helps. It did. If nothing else it told me another property that I can't test :(
Thanks for the help though.
 Signature Randy Chance Favors The Prepared Mind comp.lang.javascript FAQ - http://jibbering.com/faq/index.html Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Richard Cornford - 09 Aug 2007 00:01 GMT <snip>
> The problem was, and still is, that IE - no version - will > allow you to use createTextNode and then appendChild it to > a Script element. <snip>
Internet Explorer Elements have a boolean - canHaveChildren - property. For script elements it has a false value. It doesn't represent the whole solution but I would think that if you found that a script element had a - canHaveChildren - property of boolean type, and that it was false, then attempting to add child nodes of any sort would look line a non-viable activity.
Richard.
Randy Webb - 09 Aug 2007 01:26 GMT Richard Cornford said the following on 8/8/2007 7:01 PM:
> <snip> >> The problem was, and still is, that IE - no version - will [quoted text clipped - 3 lines] > > Internet Explorer Elements have a boolean - canHaveChildren - property. Is IE the only one that implements canHaveChildren?
> For script elements it has a false value. It doesn't represent the whole > solution but I would think that if you found that a script element had a > - canHaveChildren - property of boolean type, and that it was false, > then attempting to add child nodes of any sort would look line a > non-viable activity. if ((typeof(newScript.canHaveChildren) === 'boolean') && (newScript.canHaveChildren === false))
I don't think a test to see if it is false or not would be required but probably wouldn't hurt to include it just in case some other browser is out or comes out that implements canHaveChildren.
I have it noted in a Notes file I have on script insertion so that I can go back to it and give it some more thought later.
Thanks Richard.
 Signature Randy Chance Favors The Prepared Mind comp.lang.javascript FAQ - http://jibbering.com/faq/index.html Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Richard Cornford - 09 Aug 2007 02:09 GMT > Richard Cornford said the following on 8/8/2007 7:01 PM: >> <snip> [quoted text clipped - 7 lines] > > Is IE the only one that implements canHaveChildren? It is the only one I have noticed, but some manufacturers strive to imitate IE and if they notice that the property exists they may well reproduce it, but whilst doing so may not restrict the ability of the script element to have children.
>> For script elements it has a false value. It doesn't represent >> the whole solution but I would think that if you found that a [quoted text clipped - 4 lines] > if ((typeof(newScript.canHaveChildren) === 'boolean') && > (newScript.canHaveChildren === false)) Having verified that the property is of boolean type I would not bother with the comparison in the second test. Just NOT - canHaveChildren - would do.
> I don't think a test to see if it is false or not would be > required but probably wouldn't hurt to include I would say that the second test is necessary to complete the logic of the test.
> it just in case some other browser is out or comes out that implements > canHaveChildren. And that as well.
> I have it noted in a Notes file I have on script insertion > so that I can go back to it and give it some more thought later. <snip>
If I had time to look at this properly I might look at putting a script element on a page that had code contents and then examining it to see what type of children it did have (if any). If Text node(s) then that may be good grounds for particular actions. Though logically you could suspect that some would (or may) have CDATASection nodes (nodeType == 4), given that in HTML the contents of a scirpt are interpreted as CDATA.
Richard.
dhtmlkitchen@gmail.com - 31 Aug 2007 04:47 GMT On Aug 8, 9:56 am, Randy Webb <HikksNotAtH...@aol.com> wrote:
> In this thread: > [quoted text clipped - 94 lines] > > <URL:http://members.aol.com/_ht_a/hikksnotathome/loadJSFile/> Randy,
Can you include tests for scripts that have defer attribute?
That will have different results for innerHTML
_________________+ safari2/Mac | webkit/Mac(419.3) change src | n | n | change innerHTML | n | n | createElement | Y | n | change .text | n | Y | createTextNode | Y | Y |
The chart will be more complete with testing the defer attribute on innerHTML injections.
Garrett
> -- > Randy > Chance Favors The Prepared Mind > comp.lang.javascript FAQ -http://jibbering.com/faq/index.html > Javascript Best Practices -http://www.JavascriptToolbox.com/bestpractices/ Randy Webb - 31 Aug 2007 06:12 GMT dhtmlkitchen@gmail.com said the following on 8/30/2007 11:47 PM:
> On Aug 8, 9:56 am, Randy Webb <HikksNotAtH...@aol.com> wrote: <snip>
>> <URL:http://members.aol.com/_ht_a/hikksnotathome/loadJSFile/> >> > Randy, > > Can you include tests for scripts that have defer attribute? Are you saying that you get different results for Safari with and without a defer attribute? The page, as written, has a defer attribute in the script that it tries to insert via innerHTML.
> That will have different results for innerHTML > [quoted text clipped - 7 lines] > The chart will be more complete with testing the defer attribute on > innerHTML injections. I will add one in the next day or so that doesn't have a defer attribute and see if any testing shows different results for them.
 Signature Randy Chance Favors The Prepared Mind comp.lang.javascript FAQ - http://jibbering.com/faq/index.html Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/ Answer:It destroys the order of the conversation Question: Why? Answer: Top-Posting. Question: Whats the most annoying thing on Usenet?
dhtmlkitchen@gmail.com - 31 Aug 2007 21:27 GMT > dhtmlkitc...@gmail.com said the following on 8/30/2007 11:47 PM: > [quoted text clipped - 11 lines] > without a defer attribute? The page, as written, has a defer attribute > in the script that it tries to insert via innerHTML. no, I didn't actually look at your source code to see the defer attribute.
> > That will have different results for innerHTML > [quoted text clipped - 4 lines] > > change .text | n | Y | > > createTextNode | Y | Y | The column on the left represents a button in your test.
The other columns represent browsers. You can see that changing ".text" deosn't work in Safari 2, but does work in Webkit.
Webkit nightlies has lots of improvements over safari. Lots.
Garrett
> > The chart will be more complete with testing the defer attribute on > > innerHTML injections. [quoted text clipped - 11 lines] > Answer: Top-Posting. > Question: Whats the most annoying thing on Usenet? Randy Webb - 31 Aug 2007 22:29 GMT dhtmlkitchen@gmail.com said the following on 8/31/2007 4:27 PM:
>> dhtmlkitc...@gmail.com said the following on 8/30/2007 11:47 PM: >> [quoted text clipped - 10 lines] > no, I didn't actually look at your source code to see the defer > attribute. I don't think it will ever matter but I am adding another button so that there are two innerHTML buttons - one with and one without a defer attribute. I am going to have to work on the layout of the page for alignment so it may be a few days or so before I get an updated version uploaded.
>>> That will have different results for innerHTML >>> _________________+ safari2/Mac | webkit/Mac(419.3) [quoted text clipped - 10 lines] > > Webkit nightlies has lots of improvements over safari. Lots. Is Webkit a browser or an engine? Sounds like an ignorant question but I honestly don't know what it is. Right now, I have it listed locally like this:
WebKit 419.3 OS X 10.3.9
Is your OS different? Or, should it be listed differently?
Also, do you have any other browser/OS combinations that are not listed on that page?
 Signature Randy Chance Favors The Prepared Mind comp.lang.javascript FAQ - http://jibbering.com/faq/index.html Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
David Mark - 09 Aug 2007 02:32 GMT > Richard Cornford said the following on 8/8/2007 7:01 PM: > [quoted text clipped - 7 lines] > > Is IE the only one that implements canHaveChildren? I believe it is IE5.5 and up. Other may have copied it, but it seems doubtful.
> > For script elements it has a false value. It doesn't represent the whole > > solution but I would think that if you found that a script element had a [quoted text clipped - 8 lines] > probably wouldn't hurt to include it just in case some other browser is > out or comes out that implements canHaveChildren. I think you need to check the value unless you are just using it to infer IE.
This seems like the solution:
function executeJSString(stringToExecute) { var newScript = document.createElement('script'); newScript.type = "text/javascript";
if (document.createTextNode && (typeof(newScript.canHaveChildren) == 'undefined' || (typeof(newScript.canHaveChildren) == 'Boolean' && newScript.canHaveChildren))) { var s = document.createTextNode(stringToExecute); newScript.appendChild(s); } else { newScript.text = stringToExecute; }
var div = document.getElementById("scriptDiv"); if (div) div.appendChild(newScript); }
I tried it in IE6/7, Opera 9, FireFox 2, Windows Safari and Netscape 6.2. All but IE used createTextNode.
Randy Webb - 09 Aug 2007 03:28 GMT David Mark said the following on 8/8/2007 9:32 PM:
>> Richard Cornford said the following on 8/8/2007 7:01 PM: >> [quoted text clipped - 23 lines] > I think you need to check the value unless you are just using it to > infer IE. That is part of what I am trying to get away from is detecting/inferring IE.
> This seems like the solution: It is a possible solution. I don't think there is a single one that can be referred to as "the solution" though. As soon as it is, and a browser mimics canHaveChildren or doesn't support createTextNode (itself or on a SCRIPT Element), then you are back at the drawing board. If I knew, without a doubt, that IE was the only one with a problem with createTextNode then I would just keep using conditionals to trap IE and let it go. Well, until some browser copies that as well.
> function executeJSString(stringToExecute) { > var newScript = document.createElement('script'); [quoted text clipped - 8 lines] > else { > newScript.text = stringToExecute; This branch as well is apt to fail as well. That is the other side of the feature detection that I am working on. The only way I have come up with to know - for sure - is to try to insert it with .text and see what happens with it. I don't remember what the results were on mac browsers that didn't support the .text avenue. Whether they threw errors or failed silently.
The silent failure is why the data page that I keep doesn't have any feature detection in it at all. That way you get a more accurate picture of where a browser is failing.
> } > [quoted text clipped - 4 lines] > I tried it in IE6/7, Opera 9, FireFox 2, Windows Safari and Netscape > 6.2. All but IE used createTextNode. I think that testing on a mac is going to bear out those same results with the exceptions of IE5.2 and iCab which support neither .text or .createTextNode. The only saving grace with those two are that they support inserting script elements via innerHTML and they will execute them. Just another headache for me to work around :)
Thanks for the input and insight.
 Signature Randy Chance Favors The Prepared Mind comp.lang.javascript FAQ - http://jibbering.com/faq/index.html Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
David Mark - 09 Aug 2007 04:01 GMT > David Mark said the following on 8/8/2007 9:32 PM: > [quoted text clipped - 33 lines] > be referred to as "the solution" though. As soon as it is, and a browser > mimics canHaveChildren or doesn't support createTextNode (itself or on a If it mimics it incorrectly then you would have problems, but if it tells the truth about a node's ability to append a child, it will work.
> SCRIPT Element), then you are back at the drawing board. If I knew, If it doesn't support document.createTextNode then you end up trying to use the text method. If it fails like IE and has no canHaveChildren property, then you've got problems. I suspect IE is the only one that will fail in this way, so it is lucky that it has canHaveChildren to check.
> without a doubt, that IE was the only one with a problem with > createTextNode then I would just keep using conditionals to trap IE and > let it go. Well, until some browser copies that as well. I don't think anyone will copy conditional comments or compilation It would seem an insane thing to do as those features are specifically designed to work around IE quirks. If they set out to write a quirky IE-like browser, then perhaps. Regardless, it seems the canHaveChildren feature test covers more bases than IE conditionals.
> > function executeJSString(stringToExecute) { > > var newScript = document.createElement('script'); [quoted text clipped - 11 lines] > This branch as well is apt to fail as well. That is the other side of > the feature detection that I am working on. Right. I didn't consider that part of it.
The only way I have come up
> with to know - for sure - is to try to insert it with .text and see what > happens with it. I don't remember what the That seems like a valid test to me, despite the creation of a dummy variable. If the dummy variable is not set by the test then you are left with innerHTML as a last resort.
results were on mac browsers
> that didn't support the .text avenue. Whether they threw errors or > failed silently. I would guess that they fail silently as the technique probably just creates a new text property on the script element object. One scenario that would error is if these Mac browsers support a read-only text property for script elements. I guess you will have to try them, but I thought your posted chart had test results for these browsers.
As for using try/catch, at the very least you could use it for your initial test, which could reside in its own file. That way if it fails to parse, the dummy variable is undefined, which would indicate failure, but would not affect the other scripts on the page.
David Mark - 09 Aug 2007 07:21 GMT > David Mark said the following on 8/8/2007 9:32 PM: [snip]
> Thanks for the input and insight. No problem. I was sufficiently intrigued by this problem that I gave it another go with the third branch included.
I think this should cover "everything" without resorting to try/ catch. I tested with the usual suspects. Other than the single dummy variable, it is unobtrusive and results in a function that returns a success flag.
BTW, I tried short-circuiting all but the innerHTML method and found that it didn't work on Windows browsers at all (inserted script doesn't execute.) I'm surprised it works on Mac versions.
var executeJSString, passed; var oldOnLoad = window.onload;
window.onload = function() { var div, scr;
function createScript() { scr = document.createElement('script'); scr.type = 'text/javascript'; return scr; }
function addScript() { div.appendChild(scr); scr = null; }
function tryAdd() { executeJSString('passed = true;'); }
if (document.getElementById) { div = document.getElementById('scriptDiv'); var oldOnError = window.onerror; window.onerror = function() {return true;}; if (div) { if (document.createElement && div.appendChild) { scr = createScript(); if (scr.appendChild && document.createTextNode && (typeof(scr.canHaveChildren) == 'undefined' || (typeof(scr.canHaveChildren) == 'Boolean' && scr.canHaveChildren))) { executeJSString = function(stringToExecute) { scr = createScript(); scr.appendChild(document.createTextNode(stringToExecute)); addScript(); return true; } tryAdd(); } if (!passed) { executeJSString = function(stringToExecute) { scr = createScript(); scr.text = stringToExecute; addScript(); return true; } tryAdd(); } } if (!passed && typeof(div.innerHTML) == 'string') { executeJSString = function(stringToExecute) { div.innerHTML = '<script type="text/javascript">' + stringToExecute + '<\/script>'; return true; } tryAdd(); } window.onerror = oldOnError; } } if (!passed) { executeJSString = function(stringToExecute) { return false; }; } if (oldOnLoad) oldOnLoad(); };
David Mark - 09 Aug 2007 10:30 GMT > > David Mark said the following on 8/8/2007 9:32 PM: > [quoted text clipped - 4 lines] > No problem. I was sufficiently intrigued by this problem that I gave > it another go with the third branch included. Oops. I just realized that my window.onerror afterthought has a flaw. It should define the executeJSString the same as if all three tests fail (and put the old error handler back.) And of course, if one of the three fail with an error (something I tried to avoid with feature detection throughout), the other tests won't be tried.
The only real value of the window.onerror handler in this example is to prevent a script error from being reported to the user. The alternative of using try/catch clauses for the tests you think might cause an error (and putting the whole thing in its own file) is looking like a better idea.
Randy Webb - 11 Aug 2007 15:52 GMT David Mark said the following on 8/9/2007 2:21 AM:
>> David Mark said the following on 8/8/2007 9:32 PM: > [snip] >> Thanks for the input and insight. > > No problem. I was sufficiently intrigued by this problem that I gave > it another go with the third branch included. Welcome to HikkScript, I have been intrigued with dynamic JS insertion for a very long time :) If it will give you some idea of how long, I can load JS dynamically in Netscape 4.
> I think this should cover "everything" without resorting to try/ > catch. I tested with the usual suspects. Other than the single dummy [quoted text clipped - 4 lines] > that it didn't work on Windows browsers at all (inserted script > doesn't execute.) I'm surprised it works on Mac versions. I discovered it in very early versions of Netscape 6 in testing why people couldn't get it to work in IE when it "works in Netscape". The finding of it working in Mac browsers was a by product of me knowing it worked on NS6/Win and giving it a whirl in Mac browsers by having the innerHTML button on the test/date page.
I have been out of town the last 2 days and will give this a thorough testing/lookover this weekend. The major thing this thread has found me is the canHaveChildren property.
 Signature Randy Chance Favors The Prepared Mind comp.lang.javascript FAQ - http://jibbering.com/faq/index.html Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Richard Cornford - 09 Aug 2007 21:40 GMT >> Richard Cornford said the following on 8/8/2007 7:01 PM: >>> <snip> [quoted text clipped - 9 lines] > > I believe it is IE5.5 and up. Your belief is false. Windows IE 5 certainly had this property. IE 4 may also have had the property, as it was the browser that had 'children' collections and the name of the property is not 'canHaveChildNodes'.
> Other may have copied it, but it seems > doubtful. It would not matter if they did, so long as they did not implement them irrationally and attach true values to elements that would reject attempts to add children.
<snip>
> This seems like the solution: > [quoted text clipped - 6 lines] > (typeof(newScript.canHaveChildren) == 'Boolean' && > newScript.canHaveChildren))) { I don't see much point in testing the type of the property more than once. It only seems worth checking that it is boolean and then branching on its trueness if it is.
Though I would expect to see a test for an - appendChild - (and possibly - insertBefore - ) method on the element, as the absence of either might also be taken a good grounds for expecting the failure of the attempt to add a new child.
Richard.
David Mark - 10 Aug 2007 00:57 GMT On Aug 9, 4:40 pm, "Richard Cornford" <Rich...@litotes.demon.co.uk> wrote:
> >> Richard Cornford said the following on 8/8/2007 7:01 PM: > >>> <snip> [quoted text clipped - 13 lines] > also have had the property, as it was the browser that had 'children' > collections and the name of the property is not 'canHaveChildNodes'. Who said it was "canHaveChildNodes?"
> > Other may have copied it, but it seems > > doubtful. > > It would not matter if they did, so long as they did not implement them > irrationally and attach true values to elements that would reject > attempts to add children. Right.
> <snip> > [quoted text clipped - 12 lines] > once. It only seems worth checking that it is boolean and then branching > on its trueness if it is. If it is undefined (all but IE) then you want to try createTextNode as it often works. If it is boolean and true, then you also want to try it, though this scenario never seems to come up and probably won't until IE adds the ability to add children to a script element.
> Though I would expect to see a test for an - appendChild - (and > possibly - insertBefore - ) method on the element, as the absence of > either might also be taken a good grounds for expecting the failure of > the attempt to add a new child. I didn't add all of the feature testing needed to this snippet. I did address all of the issues you mention in the next post. I think the "full" solution covers everything, but I admittedly botched the window.onerror handling.
I may post one more revision to this as I did come up with a way to make the window.onerror trick work. I'll wait to see if try/catch is deemed viable for the solution.
Randy Webb - 11 Aug 2007 15:56 GMT David Mark said the following on 8/9/2007 7:57 PM:
> On Aug 9, 4:40 pm, "Richard Cornford" <Rich...@litotes.demon.co.uk> > wrote: [quoted text clipped - 13 lines] > > Who said it was "canHaveChildNodes?" It is an inference. IE5 had childNodes. If IE4 had childNodes and not the children collection, then the property would probably have been named canHaveChildNodes, since it is named canHaveChildren then it reasons that IE4 had the canHavechildren property and that is how it got named.
 Signature Randy Chance Favors The Prepared Mind comp.lang.javascript FAQ - http://jibbering.com/faq/index.html Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Peter Michaux - 09 Aug 2007 02:28 GMT Hi Randy,
What is wrong with just trying the different approaches like below? No sniffing, it can deal with errors and it checks if the insertion can be successful. It is efficient after the first use.
Peter
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en"> <head> <title>Script Insertion Test</title>
<script type="text/javascript">
this.inserter = function(stringToExecute) { // first time through do the initialization
// candidate inserters var inserters = [ function(ste) { var newScript = document.createElement('script'); newScript.type = "text/javascript"; newScript.text = ste; document.getElementById("scriptDiv").appendChild(newScript); }, function(ste) { var newScript = document.createElement('script'); newScript.type = "text/javascript"; var s = document.createTextNode(ste); newScript.appendChild(s); document.getElementById("scriptDiv").appendChild(newScript); } ];
// try the each candidate for (var i=inserters.length; i--;) { var inserter = inserters[i]; try { inserter('this.testVar=true;'); if (window.testVar == true) { // set window.insterter to the successful candidate window.inserter = inserter; return window.inserter(stringToExecute); } } catch (e) {} }
// none of the candidates worked (window.inserter = function() { throw new Error('Blame Randy.'); })();
} </script>
<script type="text/javascript"> function testcase() { window.inserter('alert("hi");'); } </script>
</head> <body>
<p onclick="testcase();">click me to see a hi alert</p>
<div id="scriptDiv"></div>
</body> </html>
Randy Webb - 09 Aug 2007 03:09 GMT Peter Michaux said the following on 8/8/2007 9:28 PM:
> Hi Randy, > > What is wrong with just trying the different approaches like below? No > sniffing, it can deal with errors and it checks if the insertion can > be successful. It is efficient after the first use. Main objection from me? I am still stuck in my old ways and don't care for try/catch. Too many possible browsers that may still not support it. I know my cell phone doesn't. Part of the reason I lovingly refer to it as the "abomination I call my cell phone".
> // none of the candidates worked > (window.inserter = function() { > throw new Error('Blame Randy.'); I like that!
 Signature Randy Chance Favors The Prepared Mind comp.lang.javascript FAQ - http://jibbering.com/faq/index.html Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
|
|
|