I have created a piece of user JavaScript which modifies pages to show
what goes on beneath the surface of a page. One of the things which I am
doing is to add the name of select options to each option.
I am calling the code to do this from an event handler registered through
window.opera.addEventListener("AfterEvent.load", ...)
The code which adds the names looked like this:
var selects = document.getElementsByTagName("select");
for (var selectI = 0; selectI < selects.length; selectI++) {
var select = selects[selectI];
var options = select.options;
for (var optionI = 0; optionI < options.length; optionI++) {
var option = options[optionI];
var text = document.createTextNode(option.value + " — ");
option.insertBefore(text, option.firstChild);
}
}
Now on some pages, there are select elements which contain hundreds of
options. On pages like this my code will take several minutes. Now I
figured, this may be because of the reflow and repaint, so I hide the
select element while I'm modifying the options:
var selects = document.getElementsByTagName("select");
for (var selectI = 0; selectI < selects.length; selectI++) {
var select = selects[selectI];
var oldDisplay = select.style.display;
select.style.display = "none";
var options = select.options;
for (var optionI = 0; optionI < options.length; optionI++) {
var option = options[optionI];
var text = document.createTextNode(option.value + " — ");
option.insertBefore(text, option.firstChild);
}
select.style.display = oldDisplay;
}
This had absolutely no effect, apart from the fact that the input box is
now invisible while I wait.
So I try removing the select elements from the document altogether while
I work on them:
var selects = document.getElementsByTagName("select");
for (var selectI = 0; selectI < selects.length; selectI++) {
var select = selects[selectI];
var dummy = document.createComment("");
select.parentNode.replaceChild(dummy, select);
var options = select.options;
for (var optionI = 0; optionI < options.length; optionI++) {
var option = options[optionI];
var text = document.createTextNode(option.value + " — ");
option.insertBefore(text, option.firstChild);
}
dummy.parentNode.replaceChild(select, dummy);
}
The slowdown is gone. But now some pages are broken altogether. These are
legacy pages which access elements in a non-standard way, through
expressions like "document.formName.selectName". This works for elements
which were in the original HTML page, but once I removed an element from
the page using the DOM, and reinsert it later, this will stop working;
"document.formName.selectName" will be undefined.
Now I have three questions:
1. Why the slowdown? What is Opera doing behind the scenes which requires
what looks like quadratic time?
2. Is Opera intentionally only supporting the legacy way to access elements
when those elements come from the HTML source itself, and not when they
are added through the DOM? Or is this a bug?
3. What can I do to avoid this slowdown, without breaking legacy pages?
Thanks,
Serge