[whatwg] When a script element's child nodes are changed

I'm replying to my own post because I've tested it and found that 
browsers are not interoperable on this point, so we really do need to 
clarify this in the spec.

First of all, the following code obviously runs the specified code and 
displays an alert:

     var s0 = document.createElement("script");
     document.head.appendChild(s0);
     var t0 = document.createTextNode("alert('added a text node child');");
     s0.appendChild(t0);

All browsers do that correctly.  The case I'm interested in is this one:

     var s1 = document.createElement("script");
     var t1 = document.createTextNode("");
     s1.appendChild(t1);
     document.head.appendChild(s1);
     t1.appendData("alert('changed text node data');");

Firefox runs this script and Chrome, Safari and Opera do not. (I don't 
have a windows installation, so I haven't tested IE)

Step 4 of the "prepare a script" algorithm says: " If the element has no 
|src 
<http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#attr-script-src>| 
attribute, and its child nodes, if any, consist only of comment nodes 
and empty text nodes 
<http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#text-node>, 
then the user agent must abort these steps at this point. The script is 
not executed."  So when the script is added to the document, it has only 
an empty text node, and it does not execute, and (this is the important 
part) it does not get its already started flag set.  So it should still 
be runnable.

One thing that is supposed to trigger script execution is "the script 
element is in a Document and its child nodes are changed".   My original 
point in this post was that "child nodes are changed" isn't specific 
enough.  The most obvious interpretation to me would be "a child is 
inserted or deleted".  Firefox has a more sophisticated interpretation 
that seems to boil down to "when the value of the text idl attribute 
changes".  Is Firefox correct here?

We're not done yet, though.  If I comment out the appendData() call in 
the code above and replace it with this line:

     s1.appendChild(document.createTextNode("alert('then added a new 
text node');"));

Firefox now runs this new script.  But Chrome, Safari and Opera still 
don't run it.  So the issue here isn't that the other browsers differ 
from Firefox on the interpretation of "child nodes are changed".  
Apparently the other browsers are marking the script with the empty text 
node as already started, and aren't allowing it to run when a change 
happens later.   And this isn't just limited to the empty text node 
case.  If I change that empty text node into a <div> element, or to a 
comment, Firefox still (correctly) runs a script inserted later, and the 
other browsers still (incorrectly) fail to run it.

Frankly, from an implementation standpoint, having to do what the spec 
says (and what Firefox does) seems unnecessarily complex.  One way to 
simplify things and to bring Chrome, Safari and Opera into compliance 
would be to change step 4 of the prepare a script algorithm so that it 
only aborts if the script tag has no children at all.  If it has 
children then the already_started flag would be set, and the script 
would never run again even if those children do not define any script 
content.

Making this change would also simplify that second trigger for preparing 
the script.  Instead of a vague "its child nodes are changed", the spec 
could just say "a child is inserted".

     David

On 10/27/11 4:03 PM, David Flanagan wrote:
> ?4.3.1 The Script Element says:
>>
>> When a |script 
>> <http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#the-script-element>| 
>> element that is not marked as being "parser-inserted" 
>> <http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#parser-inserted> 
>> experiences one of the events listed in the following list, the user 
>> agent must synchronously prepare 
>> <http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#prepare-a-script> 
>> the |script 
>> <http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#the-script-element>| 
>> element:
>>
>>   * The |script
>> <http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#the-script-element>|
>>     element gets inserted into a document
>> <http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#insert-an-element-into-a-document>.
>>   * The |script
>> <http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#the-script-element>|
>>     element is in a |Document|
>> <http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#in-a-document>
>>     and its child nodes are changed.
>>   * The |script
>> <http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#the-script-element>|
>>     element is in a |Document|
>> <http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#in-a-document>
>>     and has a |src
>> <http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#attr-script-src>|
>>     attribute set where previously the element had no such attribute.
>>
> Bullet point 2 seems ambiguous to me.  Does it mean only that the list 
> of children changes, or does it mean that any change to any child node 
> also causes the script to be prepared?  In particular, if a script 
> with no src attribute whose only child is an empty text node is 
> inserted into the document, the prepare() algorithm will abort before 
> the already_started flag is set.  Later, if I do 
> script.firstChild.insertData(jscode) does that trigger script execution?
>
> I haven't tried it out yet to see what browsers do, but I think that 
> the spec should be clarified to make it explicit.
>
>     David

Received on Friday, 28 October 2011 11:49:02 UTC