PDA

View Full Version : DomHelper bug inserting before/after a table element.



Animal
1 Mar 2007, 3:53 AM
The following code (where "this.table.dom" refers to a table element)



Ext.DomHelper.insertBefore(this.table.dom, {tag:"div"}, true)


Returns null on IE7.

This because of the code below. It calls insertIntoTable even if where is "beforebegin" or "afterend". The tag is inserted INTO a temporary table using innerHTML, and pulled out using .firstChild.firstChild.firstChild. The result is a weird element (Its nodeType is 1) with no tagName which contains the div. Ext.get() called on that returns null.



if(tag == "table" || tag == "tbody" || tag == "tr"){
return insertIntoTable(tag, where, el, html);
}


This code should be:



if((tag == "table" || tag == "tbody" || tag == "tr") &&
(where != "beforebegin") && (where != "afterend")){
return insertIntoTable(tag, where, el, html);
}

jack.slocum
1 Mar 2007, 10:37 AM
Added, ty. Any chance you want to tackle refactoring the insertIntoTable function? ;)

Animal
1 Mar 2007, 10:59 AM
I'll have a look at it when I get a chance.

Animal
4 Mar 2007, 11:47 AM
DomHelper.insertHTML. The code which redirects to insertIntoTable should look like this:



if(/^t(r|able|body)$/.test(tag) &&
/^afterbegin$|^beforeend$/.test(where)){
return insertIntoTable(tag, where, el, html);


It is only inserting into a table if where is "afterBegin" or "beforeEnd". So insertIntoTable can be a bit simpler:



function insertIntoTable(tag, where, el, html){
if(!tempTableEl){
tempTableEl = document.createElement('div');
}
var node;
if(tag == 'tr'){
tempTableEl.innerHTML = '<table><tbody><tr>'+html+'</tr></tbody></table>';
node = tempTableEl.firstChild.firstChild.firstChild.firstChild;
}else{
if (tag == 'table') {
el = el.tBodies;
el = el[(where == 'afterbegin') ? 0 : el.length - 1];
}
tempTableEl.innerHTML = '<table><tbody>'+html+'</tbody></table>';
node = tempTableEl.firstChild.firstChild.firstChild;
}
if(where == 'afterbegin'){
el.insertBefore(node, el.firstChild);
}else{
el.appendChild(node);
}
return node;
}

jack.slocum
4 Mar 2007, 7:23 PM
Looking better. Did you try it with a TD as the target element?

Animal
5 Mar 2007, 1:27 AM
Yes with "afterBegin" and "beforeEnd". That inserts HTML insode a TD element without going into insertIntoTable.

Using "beforeBegin" and "afterEnd" of a TD won't work. Bah! TD elements with these "where" positions have to be handled weirdly too!

Animal
5 Mar 2007, 3:39 AM
This has been horrible.

I have



function insertIntoTable(tag, where, el, html){
if(!tempTableEl){
tempTableEl = document.createElement('div');
}
var node;
var before = null;
if(tag == 'td') {
if (where == 'afterbegin' || where == 'beforeend') { // INTO a TD
return;
}
if (where == 'beforebegin') {
before = el;
el = el.parentNode;
} else {
before = el.nextSibling;
el = el.parentNode;
}
tempTableEl.innerHTML = '<table><tbody><tr>'+html+'</tr></tbody></table>';
node = tempTableEl.firstChild.firstChild.firstChild.firstChild;
}
else if (tag == 'tr'){
if (where == 'beforebegin') {
before = el;
el = el.parentNode;
tempTableEl.innerHTML = '<table><tbody>'+html+'</tbody></table>';
node = tempTableEl.firstChild.firstChild.firstChild;
} else if (where == 'afterend'){
before = el.nextSibling;
el = el.parentNode;
tempTableEl.innerHTML = '<table><tbody>'+html+'</tbody></table>';
node = tempTableEl.firstChild.firstChild.firstChild;
} else { // INTO a TR
if(where == 'afterbegin') before = el.firstChild;
tempTableEl.innerHTML = '<table><tbody><tr>'+html+'</tr></tbody></table>';
node = tempTableEl.firstChild.firstChild.firstChild.firstChild;
}
} else if (tag == 'tbody'){
if (where == 'beforebegin') {
before = el;
el = el.parentNode;
tempTableEl.innerHTML = '<table>'+html+'</table>';
node = tempTableEl.firstChild.firstChild;
} else if (where == 'afterend'){
before = el.nextSibling;
el = el.parentNode;
tempTableEl.innerHTML = '<table>'+html+'</table>';
node = tempTableEl.firstChild.firstChild;
} else {
if(where == 'afterbegin') before = el.firstChild;
tempTableEl.innerHTML = '<table><tbody>'+html+'</tbody></table>';
node = tempTableEl.firstChild.firstChild.firstChild;
}
} else { // TABLE
if (where == 'beforebegin' || where == 'afterend') { // OUTSIDE the table
return;
}
if(where == 'afterbegin') before = el.firstChild;
tempTableEl.innerHTML = '<table>'+html+'</tbody>';
node = tempTableEl.firstChild.firstChild;
}
el.insertBefore(node, before);
return node;
}


With the test in insertHtml being



var tag = el.tagName.toLowerCase();
if(/^t(d|r|able|body)$/.test(tag)) {
result = insertIntoTable(tag, where, el, html);
if (result) {
return result;
}
}


Basically, anything to do with a table goes into insertIntoTable. That function returns undefined if it doesn't actually need to do that jiggery-pokery (ie before or after a TABLE, or inside a TD), so that "normal" processing can ocurr.

It has to go through all that convoluted logic in order to create the element in the correct place!

jack.slocum
6 Mar 2007, 2:39 AM
Yikes that's nasty. :) Thanks Animal.