Google Groups Home
Help | Sign in
Message from discussion Determining document structure
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
RobG  
View profile
 More options Jan 30 2007, 10:27 am
Newsgroups: comp.lang.javascript
From: RobG <rg...@iinet.net.au>
Date: Wed, 31 Jan 2007 01:27:45 +1000
Local: Tues, Jan 30 2007 10:27 am
Subject: Re: Determining document structure

Jeremy wrote:
> Does anyone have a clever algorithm for generating an outline of the
> current document from (client-side) javascript using DOM methods?

> For example, let's say I predictably have a document structured
> hierarchically with <h1>...<h6> tags.  I want to generate an outline of
> the document wherein I have nested lists of the contents of the headers.
>  Take for example the following snippet of a fictional legal document:

> ------------
> <h1>Main Title</h1>
> <h2>Section One</h2>
> <h3>Paragraph A</h3>
> <p>Congress shall make no law regarding the production of baggy clown
> pants.</p>
> <h3>Paragraph B</h3>
> <p>Congress shall make now law restricting the use of said clown pants,
> for any purpose otherwise legal.</p>

> <h2>Section Two</h2>
> <h3>Paragraph A</h3>
> <p>Etc, etc.</p>
> ----------

>  From this I would want to generate
> ------
> <ul>
> <li>Main Title
>  <ul>
>  <li>Section One
>   <ul>
>   <li>Paragraph A</li>
>   <li>Paragraph B</li>
>   </ul>
>  </li>
>  <li>Section Two
>   <ul>
>   <li>Paragraph A</li>
>   </ul>
>  </li>
> </ul>
> ------

> using DOM methods.  There are two ways I can think of to do this

Just wander down the DOM and create a series of nested ULs with the
heading text in LIs. It's a tad easier using a bit of innerHTML, but not
much.  Here's a pure DOM method:

  <title>Outline</title>
   <script type="text/javascript">

   var genTOC = (function () {

     var tocHTML = '';
     var level = 1;
     var tagRE = /^h\d+/;
     var toc = genNode('ul');
     var currentEl = toc;

     function getText (el) {
       if (el.textContent) {return el.textContent;}
       if (el.innerText) {return el.innerText;}
       if (typeof el.innerHTML == 'string') {
         return el.innerHTML.replace(/<[^<>]+>/g,'');
       }
     }
     function genNode(t) { return document.createElement(t);}
     function genText(s) { return document.createTextNode(s);}
     function previous(el, t){
       el = el.parentNode;
       while(el.tagName.toLowerCase() != t) {
         el = el.parentNode;
       }
       return el;
     }

     return {
       start: function (tocEl, startEl) {
         if (!document.getElementById)
           return;
         if (typeof tocEl == 'string')
           tocEl = document.getElementById(tocEl);
         if (typeof startEl == 'string')
           startEl = document.getElementById(startEl);

         startEl = startEl || document.body;
         this.run(startEl);
         tocEl.appendChild(toc);
       },

       run: function(el){
         var kid, kids = el.childNodes;
         var t, thisLevel;

         for (var i=0, len=kids.length; i<len; i++) {
           kid = kids[i];

           if (kid.tagName && tagRE.test(kid.tagName.toLowerCase())) {
             thisLevel = kid.tagName.substring(1);
             if (thisLevel > level) {
               currentEl.appendChild(genNode('ul'));
               currentEl = currentEl.lastChild;
               level++;
             } else {
               while (thisLevel < level) {
                 currentEl = previous(currentEl, 'ul');
                 level--;
               }
             }
             t = genNode('li');
             t.appendChild(genText(getText(kid)))
             currentEl.appendChild(t);
           }
          if (kid.childNodes) {this.run(kid);}
         }
       }
     }
   })();

   window.onload = function(){genTOC.start('tocDiv');}
   </script>

<body>
  <div id="tocDiv"></div>
  <div>
   <h1>Heading 1</h1>
    <p>Lorem Ipsum</p>
    <h2>Heading 1.1</h2>
     <p>Lorem Ipsum</p>
    <h2>Heading 1.2</h2>
     <p>Lorem Ipsum</p>
     <h3>Heading 1.2.1</h3>
      <p>Lorem Ipsum</p>
     <h3>Heading 1.2.2</h3>
      <p>Lorem Ipsum</p>
     <h3>Heading 1.2.3</h3>
      <p>Lorem Ipsum</p>
    <h2>Heading 1.3</h2>
     <div>
      <p>Lorem Ipsum</p>
      <h3>Heading 1.3.1</h3>
       <p>Lorem Ipsum</p>
      <h3>Heading 1.3.2</h3>
       <p>Lorem Ipsum</p>
     </div>
   <div>
    <h1>Heading 2</h1>
     <p>Lorem Ipsum</p>
     <h2>Heading 2.1</h2>
      <p>Lorem Ipsum</p>
      <h3>Heading 2.1.1</h3>
       <p>Lorem Ipsum</p>
      <h3>Heading 2.1.2</h3>
   </div>
  </div>
</body>

Lightly tested.

--
Rob


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2008 Google