目次フレームを自動生成する
Javascript で HTML 文書中の h1 ~ h6 を抜き出して、目次を作成するスクリプトを作成しました。見出し要素に id が振られていなければ自動生成します。自動生成した場合にやたらと "-0" が付くのはご愛嬌…。
2010.01.06 10:40 追記
自動生成した id の階層がおかしかったのを修正したものはこちら
とりあえず、Google Chrome 3.0.195.38 と IE 8 で動作確認しました。あんまりきれいじゃないです。
さらに、CSS で目次部分を左側のフレームっぽく表示させるようにしています。なんちゃって擬似フレーム。これも動作確認環境は同じ。
2009.12.22 22:50 追記
Firefox 3.5 で確認したところ、目次が全部 "undefined" ってなっちゃってました。
Firefox は Element.innerText って使えないんでしたな… とりあえず、Element.textContent を優先的に使うように修正してみました。
サンプルの HTML / toc.js / toc.css
HTML 側では、toc.js と toc.css を読込むだけです。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja"> <head> <meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8"/> <meta http-equiv="content-script-type" content="text/javascript"/> <meta http-equiv="content-style-type" content="text/css"/> <link href="toc.css" rel="stylesheet" type="text/css"/> <script type="text/javascript" src="toc.js"></script> <!-- 省略… --> </head> <body> <h1>1章</h1> <h2>1章-1節</h2> <h3>1章-1節-1項</h3> <!-- 省略… --> </body> </html>
自動生成する内容は、若干カスタマイズできます。toc.js を読込んだより下の行で以下のように書けば。
<script type="text/javascript">//<![CDATA[ toc.listtag = "ol"; // 番号つきリストに toc.tocId = "tableOfContents"; // 目次部分の id を別の値に toc.defaultIdPrefix = "section"; // 見出し要素の自動生成 id のプリフィックス //]]> </script>
// toc.js var toc = function () { function Node (element, level, idprefix, sindex) { this.element = element; this.level = level; this.idprefix = idprefix; this.sindex = sindex; this.firstChild = null; this.nextSibling = null; if (element && !element.id) element.id = this.idprefix + "-" + this.sindex; } Node.prototype.append = function (element, level) { if (this.nextSibling != null) { this.nextSibling.append (element, level); return; } switch (level - this.level) { case 0: this.nextSibling = new Node (element, level, this.idprefix, this.sindex + 1); break; case 1: if (this.firstChild == null) this.firstChild = new Node (element, level, this.idprefix + "-" + this.sindex, 0); else this.firstChild.append (element, level); break; default: if (this.firstChild == null) this.firstChild = new Node (null, this.level + 1, this.idprefix + "-" + this.sindex, 0); this.firstChild.append (element, level); break; } }; Node.prototype.createIndex = function (listTagName) { var li = document.createElement ("li"); if (this.element != null) { var ancher = document.createElement ("a"); ancher.setAttribute ("href", "#" + this.element.id); var text = document.createTextNode (this.element.textContent || this.element.innerText); ancher.appendChild (text); li.appendChild (ancher); } if (this.firstChild) { var list = document.createElement (listTagName); var node = this.firstChild; while (node != null) { list.appendChild (node.createIndex (listTagName)); node = node.nextSibling; } li.appendChild (list); } return li; }; var scanElements = function (idprefix) { var elements = document.getElementsByTagName ("*"); var root = new Node (null, 0, idprefix, 0); for (var i = 0; i < elements.length; i ++) { var element = elements [i]; if (element.nodeName.match (/^h([1-9])$/i)) { var number = RegExp.$1 - 0; root.append (element, number); } } return root; }; var createIndex = function (root, listTagName) { var list = document.createElement (listTagName); var node = root.firstChild; while (node != null) { list.appendChild (node.createIndex (listTagName)); node = node.nextSibling; } return list; }; return new function () { // public this.listtag = "ul"; this.tocId = "toc"; this.defaultIdPrefix = "hedding"; this.create = function () { var root = scanElements (this.defaultIdPrefix); var tocelem = document.createElement ("div"); tocelem.id = this.tocId; tocelem.appendChild (createIndex (root, this.listtag)); document.body.appendChild (tocelem); }; } (); } (); window.onload = function () { toc.create (); };
/* toc.css */ html { /* start - for pseudo frame */ display: block; height: 100%; width: 100%; margin: 0; padding: 0; overflow: hidden; /* end - for pseudo frame */ } body { padding-left: 1.5em; /* start - for pseudo frame */ display: block; height: 100%; margin: 0; overflow: auto; /* end - for pseudo frame */ /* toc frame width */ margin-left: 200px; } #toc { padding: 0.5em; /* start - for pseudo frame */ position: absolute; left: 0; top: 0; height: 100%; overflow: auto; /* end - for pseudo frame */ /* toc frame width */ width: 200px; } /* edit as you like. */ #toc ul { padding-left: 1em; } #toc li { list-style-type: circle; marker-offset: 0; }
トラックバック
- このエントリーにトラックバック:
- http://frog.raindrop.jp/cgi-bin/mt/mt-tb.cgi/2464
コメント