Closed Bug 276037 Opened 20 years ago Closed 18 years ago

In application/xhtml+xml during page load getElementsByTagNameNS and getElementsByTagName does not find all currently parsed elements

Categories

(Core :: DOM: Core & HTML, defect)

x86
Windows XP
defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: martin.honnen, Unassigned)

References

()

Details

Attachments

(3 files)

HTML and XHTML allow the use of the <script> element to embed script code in the
document. The script code inside of a <script> element has traditionally been
executed during loading of the document, directly after the <script> element has
been parsed. For instance in HTML (text/html) documents people use
document.write to insert content into the document during page load. With "real"
XHTML, meaning with application/xhtml+xml content, document.write is no longer
available but of course scripters would still like to insert content into the
document with script while the page loads.

My solution for that is to use document.getElementsByTagName('script')
respectively document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml',
'script') to grab the last <script> element in the document and call appendChild
on its parent node, in the hope that while the script code inside of a <script>
element is executed that <script> element is already available in the DOM tree
and thus any content is executed directly after the <script> element, the same
way document.write would do it.

However with Mozilla (tested with the latest nightly Mozilla/5.0 (Windows; U;
Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041225 as well as with Firefox 1.0
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107
Firefox/1.0) the approach doesn't work when the <script> element sits inside of
a table cell inside of a document served as application/xhtml+xml. 

The test case at:
http://home.arcor.de/martin.honnen/mozillaBugs/domInsertionDuringPageLoad/domInsertionDuringPageLoad.xhtml
shows that the <script> element inside of the table cell is not yet found by the
getElementsByTagName/getElementsByTagNameNS('script') so that the text meant to
be inserted into the table cell ends up as a child of the parent node of an
earlier <script> element.

The same test case served as text/html, available here:
http://home.arcor.de/martin.honnen/mozillaBugs/domInsertionDuringPageLoad/domInsertionDuringPageLoad.html
however works as intended, the code inside of a <script> element finds that
<script> element in the DOM tree and is able to append to its parent node.

While I cannot cite a specification saying that script code run during page load
needs to have access to the DOM tree including the <script> element the code is
contained in that would be highly desirable in my view as it is the only way for
script in application/xhtml+xml to insert content at the position of the
<script> element. Therefore I file this bug on Mozilla.

I add that this is becoming more important as an increasing number of people are
using content type negotiation to serve XHTML as text/html to IE but as
application/xhtml+xml to Mozilla (or other browsers understanding XML) and
therefore use script in application/xhtml+xml and run into the problem to have
the script run during page load insert content into the page when and where the
script is executed. One newsgroup post about that topic is here:
http://groups-beta.google.com/group/netscape.public.mozilla.dom/browse_frm/thread/a9be9f42491271ad/09ad74e3c8fec90c?tvc=1&scrollSave=&&d#09ad74e3c8fec90c
I think this is because of bug 18333. See also 232004 comment 9.
Depends on: incrementalxml
Martin, is the table cell relevant?  That is, if you replace it with a paragraph, do you still 
see the problem?  What about if the <script> is just a child of <body>?

Anne, this is rather unlikely to be a consequence of bug 18333 -- that bug is about 
_layout_ objects not being constructed, and this bug is about the content model and 
looks like it should be reproducible even in a display:none iframe (where there are no 
layout objects in sight).
No longer depends on: incrementalxml
I have done some further tests and Boris rightly suspects that the table is not
relevant, changing summary to reflect that.
In the following application/xhtml+xml test case:
http://home.arcor.de/martin.honnen/mozillaBugs/domInsertionDuringPageLoad/domInsertionDuringPageLoadParagraph.xhtml
there are only paragraphs but only the script code in the first <script> element
inserts content into its parent node while all following scripts insert content
as a child of the first paragraph which is the parent node of the first <script>
element.
The same test case as text/html works fine:
http://home.arcor.de/martin.honnen/mozillaBugs/domInsertionDuringPageLoad/domInsertionDuringPageLoadParagraph.html
Summary: In application/xhtml+xml a script element inside a table cell is not yet available in the DOM when the script executes → In application/xhtml+xml a script element is not yet available in the DOM when the script executes
Further investigation shows that the problem is that during page load in
application/xhtml+xml content the methods document.getElementsByTagName and
document.getElementsByTagNameNS do not find all parsed elements.
The test case during page load counts XHTML span and script elements using the
two methods and manually walking the document tree, while the tree walks shows
that the last span and script element has been parsed and is in the document
tree the two methods do not find those elements, only after onload the methods
find the correct number of elements.
Changing summary again to reflect the findings of the last test case
<https://bugzilla.mozilla.org/attachment.cgi?id=169634> which shows that the
problem is not restricted to <script> elements not being found but other
elements like <span> too.
Summary: In application/xhtml+xml a script element is not yet available in the DOM when the script executes → In application/xhtml+xml during page load getElementsByTagNameNS and getElementsByTagName does not find all currently parsed elements
Hmm... It'd be interesting to see exactly what the callstack looks like when we
actually do anything in nsHTMLScriptElement::MaybeProcessScript, i.e. when we
reach line 649 in that file.

I would exect things to work since we in nsGenericElement::AppendChildTo add the
new child to mAttrsAndChildren before we call SetDocument on it.
The problem is that content lists are lazy and rely on the
ContentAppended/ContentInserted/ContentRemoved notifications to clear their
cached state.  But the XML content sink doesn't fire these notifications until
the parsing is finished and it fires a single ContentInserted on the root....

Perhaps content lists should be non-lazy for still-loading xml documents (as a
short-term hack or something)?  What should the behavior of content lists be
when they're created by a script element in a document that is then transformed
with xslt, btw?
Shouldn't "we" "just" make the XML content sink fire the notifications like the
HTML content sink?
I'm not sure, in part because I'm not sure how that interacts with XSLT.  When
we transform, do we change document objects too, or just stick the
transformation result into the original document?  If the latter, content lists
created in the pre-transform document would start seeing post-transform content,
which is undesirable.

For the rest, I think it should be safe to do content notifications, since we
wouldn't call InitialReflow, so frame construction would be suppressed.  But we
may still up with significant inefficiency from once-per-content notification,
whereas a batching system like the HTML sink would take some work (see bug 18333).
ccing people who may know answers to my questions...
XSLT creates a compleatly new document (so that we can create an html document
rather then an xml one).

Also, it shouldn't be an issue with stuff created in the original document,
since we shouldn't be running any scripts at all in that document once we detect
that we're going to XSLT transform it (not sure if we actually do that currently).

XSLT currently use DOM methods to create the result tree, so I would think that
we send out notifications continously. This might change though if we switch
over to the faster nsIContent interfaces.
I attach this as workaround as long as the bug is not fixed as the problem of
inserting content during page load into application/xhtml+xml comes up again
and again in newsgroups. Instead of using getElementsByTagName(NS) to find the
last and current <script> element the workaround looks at the childNodes and
that way is able to find the correct <script> element.
Just as an additional information: I've tripped on this problem in one of my
projects too, where a script basically needs to located its own script element
in order to be able to "include" more script files automatically.

This currently fails, because getElementByTagName() does not return all script
DOM nodes. However, when looking at document and its child DOM elements, I can
find the "missing" DOM node.
Fixed by bug 18333.  (I was able to reproduce the bug using an opt build from a few days ago, but not using a debug build with the fix for bug 18333.)
Status: NEW → RESOLVED
Closed: 18 years ago
Resolution: --- → FIXED
PLEASE mark the in-testsuite stuff when resolving.  Or better yet, add the tests!
Flags: in-testsuite?
OK.  So I wrote a regression test for this based on attachment 169634 [details].  Sometimes the test succeeds.  Sometimes it fails.

Reopening.
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
could be a regression from 18333
No, it was broken before 18333.
Depends on: 369011
Attached patch TestsSplinter Review
The random failures are due to bug 369011 (yay writing regression tests!).  Once that lands I'll land these tests.
Tests committed.  Now they pass.
Status: REOPENED → RESOLVED
Closed: 18 years ago18 years ago
Flags: in-testsuite? → in-testsuite+
Resolution: --- → FIXED
Component: DOM: Core → DOM: Core & HTML
QA Contact: ian → general
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: