0

I wish to implement the following Javascript function:

function AllToDom(partsArray)
{
    // Magic!
}

// Called like:
var rowObject = AllToDom(['<tr>', tdElem1, tdElem2, '<td>XXX</td>', '<td>', 
    divContents,'</td></tr>']);

// Where tdElem1, tdElem2, divContents are DOM node objects.

The thing is I want it to work on any kinds of combinations of DOM nodes and HTML fragments. As long as it produces a valid HTML of course. Unclosed HTML tags and disallowed element combinations (like <table><div></div>) are allowed to have undefined behavior.

My first idea was to concatenate it all in a HTML string, except in place of DOM elements add a placeholder comment <!--SNOOPY-->. So the above would result in the following string:

<tr><!--SNOOPY--><!--SNOOPY--><td>XXX</td><td><!--SNOOPY--></td></tr>

This is already a valid piece of HTML, so next I create a <div>, assign this to innerHTML, gather the produced DOM nodes, and iterate through them and replace all <!--SNOOPY--> with the respective DOM element.

There are two flaws with this approach however:

  1. Adding a <tr> as a child element to a <div> is invalid. I don't know if it might not break on some condition.
  2. Internet Explorer 8 (the least version that I need to support) strips all comments when assigning to innerHTML.

Are there any workarounds? Is this possible at all?

Vilx-
  • 104,512
  • 87
  • 279
  • 422
  • So, all tags and elements passed in the parms are siblings, right? – Jonathan M Dec 05 '14 at 21:13
  • @JonathanM - No, not necessarily. See the example. – Vilx- Dec 05 '14 at 21:36
  • For flaw #2 you could use `document.createComment` – Alvaro Montoro Dec 05 '14 at 22:35
  • @AlvaroMontoro - No, I couldn't. I need to insert *SOMETHING* in the HTML-string so that after I have converted it to DOM elements, I could find it again and replace with the proper provided elements. Comments are the only thing that I can think of which are valid in **any** context. – Vilx- Dec 05 '14 at 22:42
  • The idea would be: loop through the array, if element is a string then do `innerHTML += string` else append `document.createComment("string to identify the element later")` to the `div`. Or are the comments eliminated after doing `innerHTML+=`? – Alvaro Montoro Dec 05 '14 at 22:56
  • you can use a fragment to store any node, like TR for example. oh, but i guess that doesn't help IE8... you can use a whole document, just remember to fetch from the auto-inserted body. document sources include dataURLs, document.write (in iframe/popup), and server echos. – dandavis Dec 05 '14 at 23:15
  • @dandavis Document Fragments **are supported** in IE 8. – Sampson Dec 05 '14 at 23:19
  • @JonathanSampson: technically, but there's no easy way to make a fragment from a string in IE8, like in – dandavis Dec 05 '14 at 23:20
  • @dandavis You still need to parse, yes. jQuery accomplishes this by offloading that to the browser by setting the `innerHTML` of a detached node, and then adding that node's children to a `documentFragment`. Curious if the array elements have event listeners bound to them in this scenario. – Sampson Dec 05 '14 at 23:22
  • @AlvaroMontoro - That wouldn't work. Imagine a content array of `['
    ', el, '
    ']`. Firstly, `parent.innerHTML+='
    '` is invalid since the resulting HTML is invalid. Secondly, calling `parent.appendNode(el)` will append it to `parent`, not the ``. And last, after calling `parent.innerHTML += '
    '` (which at this point will again be confusing and invalid), all event handlers from `el` will be removed (basically `el` will be recreated from it's HTML representation).
    – Vilx- Dec 05 '14 at 23:25
  • well, using innerHTML in the middle of the pipe is no good, for reasons stated. i think #2 could be overcome by using a certain weirdo-but-supported tag instead of comments, like "" instead of "". a regexp can convert the comments before the innerHTML part – dandavis Dec 05 '14 at 23:26
  • @Vilx- I asked about event listeners because if you don't have them you can replace each node (skipping strings) in the array with its outerHTML (using the detached node's innerHTML) and then concat the array strings afterwards. – Sampson Dec 05 '14 at 23:28
  • @dandavis - is there anything else that could be placed in ANY context? Like, a `
    ` cannot be placed directly inside a ``, and a `` cannot be placed directly inside a div. What (except for a comment) can be placed ANYWHERE? I also tried an XML processing instruction ``, but IE8 just ignored that as well.
    – Vilx- Dec 05 '14 at 23:28
  • @JonathanSampson - Ahh, I understand now. Sorry, they can and will have event listeners attached. :( – Vilx- Dec 05 '14 at 23:29
  • @Vilx- no, there is not. even new – dandavis Dec 05 '14 at 23:33
  • @JonathanSampson - Actually, you have me an idea. Since I know the elements that need to be plugged in the HTML string, I can check their `tagName`s and add similar elements in their places. I can distinguish them later by a special CSS class. – Vilx- Dec 06 '14 at 09:05

1 Answers1

0

Finally found an answer: jQuery has already done all the dirty work in their parseHTML() method. And I just happen to be using jQuery anyway, so good for me! :)

I checked what the magic was behind the scenes, and it's really pretty gruesome. First, they inspect the HTML (with regexs...) to see what parent tag they need to use, and then they have a workaround for IE8, which apparently it DOES preserve comment nodes - but only if they come after a text node. All comments before the first text node are lost. And some tags are affected this way too, which I had no idea about. And then there's half a dozen other workarounds for IE & Webkit problems that I've never even heard of.

So, I'm just going to leave it to them to do the right thing, because trying to reproduce that stuff would be madness.

Community
  • 1
  • 1
Vilx-
  • 104,512
  • 87
  • 279
  • 422