javascript - Replacing #text elements with spans causes documents to reshape -


i need replace every #text has siblings spans have ids. following code supposed this, reason causes many documents reshape: parts of document move, page changes appearance.

var eltid = 0;  function geneltid() {     return "my-id-" + ++eltid; }  function hashtextstospans(elt) {     (var in elt.childnodes) {         var eltchild = elt.childnodes[i];         if (eltchild.nodename == "#text" && elt.childnodes.length > 1) {             // #text 1 of multiple childs             var eltdiv = document.createelement("span");             eltdiv.setattribute("id", geneltid());             elt.replacechild(eltdiv, eltchild);             eltdiv.appendchild(eltchild);         } else {             if (eltchild.nodename != "iframe") {                 hashtextstospans(eltchild);             }         }     } }  function onkeypress(e) {     if (e.keycode == 105) {         // key         hashtextstospans(document.body);     } }  window.parent.addeventlistener("keypress", onkeypress); 

for example, inject in chrome (using "cjs" addon) https://en.wikipedia.org/wiki/linux , press "i", , observe page reshapes.

what problem? aren't #text , span both inline elements, , should displayed in same way when text same , span has no style?

assumptions: no iframe elements, no other javascript manipulates dom tree @ same time.

the issue in html, many elements have restrictions on types of child nodes allowed contain.

for example, list elements (e.g. ul or ol) can contain li elements , blank (whitespace-only) text nodes. when wrap such blank text nodes in spans, page non-standards-compliant.

in specific case of wikipedia page linked to, original page had text nodes containing whitespace between tr , td elements of table. when script runs, text nodes become spans, not allowed have elements outside of tr , td elements within table. thus, causes browsers automatically insert phantom columns table, messing layout.

as quick fix, ignore text nodes contain whitespace. trivial if use treewalker api, passing in following function filter:

node => /\s/.test(node.nodevalue) ? nodefilter.filter_accept : nodefilter.filter_reject 

as more long-term fix, you'll need through html5 spec know sure elements allowed contain span nodes, , write script accordingly.


Comments