If you think a bug might affect users in the 57 release, please set the correct tracking and status flags for Release Management.

replaceChild() operation in TBODY causes THEAD & first TBODY line to disappear




DOM: Core & HTML
18 years ago
9 years ago


(Reporter: lhylan, Assigned: karnaze (gone))


Mac System 8.6

Firefox Tracking Flags

(Not tracked)




(1 attachment)



18 years ago
[This problem also reproduces in M13 on Windows98.]

[I'm pasting the code in below in case I change what's at the URL above. The 
pasted code includes IDs for all of the table rows, the THEAD, and the TBODY to 
assist in debugging.]

The following code works fine in IE5.5, but M13 fails to display the THEAD row 
and the first TBODY row the first time a sort is performed. In subsequent 
sorts, the first TBODY row returns, but the THEAD row does not.

<title>Sort Table</title>

<!-- Much of the code below is borrowed from the Sort Table command in 
Dreamweaver 2; I've just adapted it to run in IE5 & Mozilla instead of within 
Dreamweaver. -->

<script langauge="JavaScript">

var rowIter, rowArray, sortOrder;
var colIter, sortCol, rowHTML;
var textString, currRow, i;
var Lisa, Lori, Linda;

function sortTable(quotedTableID,sortBy,sortType,AscOrDesc){

var tableID = document.getElementById(quotedTableID);

Create an array of all the TR tags in the table. Note that there
is a table body (TBODY) in the DOM whether you've specified one or not,
so it's a good idea to specify it explicitly in the HTML just to remind
yourself which childNode you're interested in. The first childNode
(tableID.childNodes[0]) of the table is the table head (THEAD); its
child is a header row, which does not need to be sorted. The rows to
be sorted are the children of tableID.childNodes[1].
tbody = tableID.childNodes[1];
rowIter = tbody.childNodes;
rowCount = rowIter.length;

Define sortCol as the column number - 1 so that the sort column can be used
as a 0-based index.
sortCol = sortBy-1;

// Determine the sort order
sortOrder = AscOrDesc;

Create a two-dimensional array containing rowCount rows and 2 columns.
The first column contains the HTML for the row; the second
column contains the contents of column number sortCol for that row.
rowArray = new Array();

for (i=0;i<rowCount;i++) {
Copy each row into rowArray using the cloneNode(deep) method. Set the 'deep'
argument to true to clone the childNodes as well as the node itself. This
serves to copy the entire row contents, not just the TR tag.
rowArray[i] = new Array();
rowHTML = rowIter[i];
rowArray[i][0] = rowHTML.cloneNode(true);

// Copy the contents of the sort column into rowArray
colIter = rowHTML.childNodes;
rowArray[i][1] = sortType == "alpha" ? gobbleWhiteSpace(textString.toLowerCase

// Sort the rowArray, based on the sort column

// Copy the contents of the sorted rowArray back into the HTML document.
for (i = 0; i < rowCount; i++) {

Lisa = rowArray[i][0];
Lori = rowIter[i];
Linda = Lori.parentNode;


function compareCallback(a,b){
var retVal=0;

Determine whether to switch a and b based on a and b values and specified sort
order. If -1 is returned, order stays the same; if 1, values are switched;
if 0, values are equal.
if (a[1]!=b[1]){
retVal=((a[1]<b[1])?-1:1)*(sortOrder == "A" ?1:-1);
return retVal;

function parseNumber(value){

var retVal=value;
var numLength = retVal.length;
var k=0;

// Before sorting as numbers, remove % and $ symbols
if (retVal.charAt(0)=="$")
else if (retVal.charAt(numLength-1)=="%" || retVal.charAt(numLength-1)=="$")

Before sorting as numbers, remove spaces and turn commas
into decimal points
if (retVal.charAt(k)==" "){
retVal=retVal.substring(0,k) + retVal.substring(k+1);continue;
if (retVal.charAt(k)==","){
retVal=retVal.substring(0,k) + retVal.substring(k+1);continue;

The following lines treat non-numbers as strings to help prevent
a possible crash when two values that are both NaN are compared.
if (parseFloat(retVal) == retVal)
retVal = parseFloat(retVal);
return retVal;

function getTextNode(theObj){
var iter=theObj.childNodes;
var counter=0;
var theChild = (iter.length>0)?iter[counter]:false;
var retVal="";

for (var i=0; i < iter.length; i++) {

// If the object is a text node, extract its data.
if (theObj.nodeType == 3){
return retVal;

function gobbleWhiteSpace(textstring){
var lastChar,counter=0;

Remove whitespace from beginning of string to prevent it from affecting
the sort order.
while (textstring.charAt(0)==" " || textstring.charAt(0)=="\n" || 
textstring.charAt(0)=="\r" || textstring.charAt(0)=="\t"){
textstring = textstring.substring(1);

// Remove whitespace from end of string.
lastChar = textstring.length-1;
while (textstring.charAt(0)==" " || textstring.charAt(0)=="\n" || 
textstring.charAt(0)=="\r" || textstring.charAt(0)=="\t"){
textstring = textstring.substring(0,textstring.length-1);
lastChar = textstring.length-1;
return textstring;

<style type="text/css">
th { font-family: Arial, Helvetica, sans-serif; font-size: 11pt; font-weight: 
td { font-family: Geneva, Arial, Helvetica, sans-serif; font-size: 10pt}
a { text-decoration: none}
p { font-family: Geneva, Arial, Helvetica, sans-serif; font-size: 10pt }


<body bgcolor="#FFFFFF" text="#000000" link="#000000" vlink="#000000" 

<table width="400" border="0" cellspacing="5" id="table1">
<thead id="tableHead">
<tr id="columnHeads" align="LEFT" bgcolor="#CCFF99">
<th id="Engineer" width="160">Engineer</th>
<th id="Fixed" width="120">Bugs fixed</th>
<th id="Remaining" width="120">Bugs remaining</th>

<tbody id="tableBody">
<tr id="George">
<td width="160">George</td>
<td width="120" align="RIGHT">27</td>
<td width="120" align="RIGHT">13</td>

<tr id="Dietrich">
<td width="160">Dietrich</td>
<td width="120" align="RIGHT">19</td>
<td width="120" align="RIGHT">21</td>

<tr id="nj">
<td width="160">nj</td>
<td width="120" align="RIGHT">34</td>
<td width="120" align="RIGHT">27</td>

<tr id="Heidi">
<td width="160">Heidi</td>
<td width="120" align="RIGHT">25</td>
<td width="120" align="RIGHT">16</td>

<tr id="Jay">
<td width="160">Jay</td>
<td width="120" align="RIGHT">20</td>
<td width="120" align="RIGHT">14</td>

<tr id="Joe">
<td width="160">Joe</td>
<td width="120" align="RIGHT">15</td>
<td width="120" align="RIGHT">22</td>

<tr id="Sho">
<td width="160">Sho</td>
<td width="120" align="RIGHT">28</td>
<td width="120" align="RIGHT">16</td>

<tr id="Ken">
<td width="160">Ken</td>
<td width="120" align="RIGHT">18</td>
<td width="120" align="RIGHT">19</td>

<tr id="Dave">
<td width="160">Dave</td>
<td width="120" align="RIGHT">30</td>
<td width="120" align="RIGHT">6</td>

<tr id="Scott">
<td width="160">Scott</td>
<td width="120" align="RIGHT">9</td>
<td width="120" align="RIGHT">24</td>

<tr id="Hava">
<td width="160">Hava</td>
<td width="120" align="RIGHT">26</td>
<td width="120" align="RIGHT">14</td>

<tr id="Darrick">
<td width="160">Darrick</td>
<td width="120" align="RIGHT">32</td>
<td width="120" align="RIGHT">20</td>


<form action="">
<input type="button" value="sort by engineer" onClick="sortTable
('table1','1','alpha','A')" name="eng"> <input type="button" value="sort by 
fixed" onClick="sortTable('table1','2','num','D')" name="fixed"> <input 
type="button" value="sort by remaining" onClick="sortTable
('table1','3','num','D')" name="remaining">

Comment 1

18 years ago
I checked to see if extra text node reporting was the problem here (see non-bug 
#26179 for details), but it doesn't appear to be. There are no differences 
between the number or type of nodes being reported by IE5 and M13 within the 

Comment 2

18 years ago
This seems to be a problem with nsTableRowGroupFrame::InsertFrames and the way 
it deals with cell maps. I've narrowed down the problem to the following case: 
if we insert a new row at the beginning of a row group and there is a previous 
row group, the code in nsTableRowGroupFrame::InsertFrames doesn't seem to 
calculate the correct row index *relative to the current row group* before 
calling into nsTableCellMap::InsertRows.

A reduced test case is attached below.
Assignee: vidur → karnaze

Comment 3

18 years ago
Created attachment 5049 [details]
reduced test case that shows assertion

Comment 4

18 years ago
Forgot to mention that we hit the assertion "SetMapCellAt called with row index 
> num rows" in nsCellMap::SetMapCellAt because the row index passed in is -1.


18 years ago
Target Milestone: M15

Comment 5

18 years ago
mass move to m16
Target Milestone: M15 → M16

Comment 6

18 years ago
Last Resolved: 18 years ago
Resolution: --- → FIXED

Comment 7

17 years ago
Mass update of qa contact
QA Contact: gerardok → janc
Component: DOM Level 1 → DOM HTML

Comment 8

17 years ago
QA contact Update
QA Contact: janc → desale

Comment 9

17 years ago
Updating QA contact to Shivakiran Tummala.
QA Contact: desale → stummala

Comment 10

16 years ago
verified win2k 2001-10-17-18
Keywords: vtrunk

Comment 11

16 years ago
verified fixed. 2001-12-14-09


9 years ago
Component: DOM: HTML → DOM: Core & HTML
QA Contact: stummala → general
You need to log in before you can comment on or make changes to this bug.