The problem is that there is no better way to get the headers in the order of the document. For example, calling jQuery $('h1,h2,h3,h4,h5,h6') will return all your headers, but first will be <h1> , then <h2> s, etc. No main frame job returns elements in document order when you use a comma delimited selector.
You can overcome this problem by adding a generic class to each title. For example:
<h1 class="heading">Heading level 1</h1> <h2 class="heading">Sub heading #1</h2> <h2 class="heading">Sub heading #2</h2> <h3 class="heading">Sub Sub heading</h3> <h2 class="heading">Sub heading #3</h2> ...
Now the $('.heading') selector will get everything in order.
Here is how I will do it with jQuery:
var $result = $('<div/>'); var curDepth = 0; $('h1,h2,h3,h4,h5,h6').addClass('heading'); $('.heading').each(function() { var $li = $('<li/>').text($(this).text()); var depth = parseInt(this.tagName.substring(1)); if(depth > curDepth) { // going deeper $result.append($('<ol/>').append($li)); $result = $li; } else if (depth < curDepth) { // going shallower $result.parents('ol:eq(' + (curDepth - depth - 1) + ')').append($li); $result = $li; } else { // same level $result.parent().append($li); $result = $li; } curDepth = depth; }); $result = $result.parents('ol:last'); // clean up $('h1,h2,h3,h4,h5,h6').removeClass('heading');
$result should now be your <ol> .
Also note that this will handle <h4> followed by <h1> (moving more than one level down immediately), but it will not process <h1> followed by <h4> (more than one level up at a time) .
Prestaul
source share