1/*! 2 * jQuery TOC Plugin v1.1.x based on 3 * samaxesJS JavaScript Library 4 * http://code.google.com/p/samaxesjs/ 5 * 6 * Copyright (c) 2008 samaxes.com 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 * 2009-10-04, guwi17: modified and extended to meet uBLAS' needs 21 */ 22 23(function($) { 24 /* 25 * The TOC plugin dynamically builds a table of contents from the headings in 26 * a document and prepends legal-style section numbers to each of the headings. 27 */ 28 $.fn.toc = function(options) { 29 var opts = $.extend({}, $.fn.toc.defaults, options); 30 31 return this.each(function() { 32 var toc = $(this).append('<ul></ul>').children('ul'); 33 var headers = {h1: 0, h2: 0, h3: 0, h4: 0, h5: 0, h6: 0}; 34 var index = 0; 35 var indexes = { 36 h1: (opts.exclude.match('h1') == null && $('h1').length > 0) ? ++index : 0, 37 h2: (opts.exclude.match('h2') == null && $('h2').length > 0) ? ++index : 0, 38 h3: (opts.exclude.match('h3') == null && $('h3').length > 0) ? ++index : 0, 39 h4: (opts.exclude.match('h4') == null && $('h4').length > 0) ? ++index : 0, 40 h5: (opts.exclude.match('h5') == null && $('h5').length > 0) ? ++index : 0, 41 h6: (opts.exclude.match('h6') == null && $('h6').length > 0) ? ++index : 0 42 }; 43 44 $(':header').not(opts.exclude).each(function() { 45 var linkId = ""; 46 if ($(this).is('h6')) { 47 checkContainer(headers.h6, toc); 48 updateNumeration(headers, 'h6'); 49 $(this).text(addNumeration(headers, 'h6', $(this).text())); 50 linkId = fixAnchor($(this)); 51 appendToTOC(toc, indexes.h6, linkId, $(this).text(), headers); 52 } else if ($(this).is('h5')) { 53 checkContainer(headers.h5, toc); 54 updateNumeration(headers, 'h5'); 55 $(this).text(addNumeration(headers, 'h5', $(this).text())); 56 linkId = fixAnchor($(this)); 57 appendToTOC(toc, indexes.h5, linkId, $(this).text(), headers); 58 } else if ($(this).is('h4')) { 59 checkContainer(headers.h4, toc); 60 updateNumeration(headers, 'h4'); 61 $(this).text(addNumeration(headers, 'h4', $(this).text())); 62 linkId = fixAnchor($(this)); 63 appendToTOC(toc, indexes.h4, linkId, $(this).text(), headers); 64 } else if ($(this).is('h3')) { 65 checkContainer(headers.h3, toc); 66 updateNumeration(headers, 'h3'); 67 $(this).text(addNumeration(headers, 'h3', $(this).text())); 68 linkId = fixAnchor($(this)); 69 appendToTOC(toc, indexes.h3, linkId, $(this).text(), headers); 70 } else if ($(this).is('h2')) { 71 checkContainer(headers.h2, toc); 72 updateNumeration(headers, 'h2'); 73 $(this).text(addNumeration(headers, 'h2', $(this).text())); 74 linkId = fixAnchor($(this)); 75 appendToTOC(toc, indexes.h2, linkId, $(this).text(), headers); 76 } else if ($(this).is('h1')) { 77 updateNumeration(headers, 'h1'); 78 $(this).text(addNumeration(headers, 'h1', $(this).text())); 79 linkId = fixAnchor($(this)); 80 appendToTOC(toc, indexes.h1, linkId, $(this).text(), headers); 81 } 82 }); 83 }); 84 }; 85 86 /* 87 * Checks if the last node is an 'ul' element. 88 * If not, a new one is created. 89 */ 90 function checkContainer(header, toc) { 91 if (header == 0 && !toc.find(':last').is('ul')) { 92 toc.find('li:last').append('<ul></ul>'); 93 } 94 }; 95 96 /* 97 * Updates headers numeration. 98 */ 99 function updateNumeration(headers, header) { 100 $.each(headers, function(i, val) { 101 if (i == header) { 102 ++headers[i]; 103 } else if (i > header) { 104 headers[i] = 0; 105 } 106 }); 107 }; 108 109 /* 110 * Prepends the numeration to a heading. 111 */ 112 function addNumeration(headers, header, text) { 113 var numeration = ''; 114 115 $.each(headers, function(i, val) { 116 if (i <= header && headers[i] > 0) { 117 numeration += headers[i] + '.'; 118 } 119 }); 120 121 return removeFinalDot(numeration) + ' ' + text; 122 }; 123 124 function removeFinalDot(text) { 125 return (text||"").replace(/\.$/g, "" ) 126 } 127 128 function fixAnchor(element) { 129 // use existing id by default 130 var linkId = element.attr('id'); 131 // next, look for an anchor and use its id or name 132 if ( !linkId ) { 133 element.find('> a:first').each( function() { 134 linkId = $(this).attr('id') || $(this).attr('name'); 135 }); 136 } 137 // next, use the text content as last resort 138 if ( !linkId ) { 139 linkId = (element.text()||"unknown").replace(/[^a-zA-Z0-9]/g,""); 140 } 141 142 element.attr('id',linkId); 143 return linkId; 144 } 145 146 /* 147 * Appends a new node to the TOC. 148 */ 149 function appendToTOC(toc, index, id, text, headers) { 150 var parent = toc; 151 152 for (var i = 1; i < index; i++) { 153 if (parent.find('> li:last > ul').length == 0) { 154 parent = parent.append('<li><ul></ul></li>'); 155 } 156 parent = parent.find('> li:last > ul'); 157 } 158 if (id) { 159 parent.append('<li><a href="#' + id + '">' + text + '</a></li>'); 160 } else { 161 parent.append('<li>' + text + '</li>'); 162 } 163 }; 164 165 $.fn.toc.defaults = {exclude: 'h1, h5, h6'} 166})(jQuery); 167