[whatwg] When a script element's child nodes are changed
David Flanagan
dflanagan at mozilla.com
Fri Oct 28 11:49:02 PDT 2011
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
More information about the whatwg
mailing list