たぼさんの部屋

いちょぼとのんびり

自動もくじ生成

makeToc.js

/**
 * @author kamogashira_tsuyoshi
 */

window.onload =function(){

	if (d.toc===1) {
		maketoc();
		//maketoc.jaのmaketocファンクションを呼び出し
	}
};

/**
 * @author kamogashira_tsuyoshi
 */

/*[自動目次生成]
 * 自動的に目次を生成する
 * このモジュールはmaketoc()関数を定義する。
 * ドキュメントのロードが完了したときに自動的に実行されるように、
 * onloadイベントハンドラに登録する。
 * 実行すると、maketoc()は、ドキュメント中から、まず「toc」という
 * IDの要素を探す。要素が存在しない場合、maketoc()は何もしない。
 * 要素が存在する場合が、maketoc()はドキュメントを探索し、<h1>から<h6>までの
 * すべてのタグを探し、目次を生成し、toc要素に追加する。
 * maketoc()関数は、各節の見出しに節番号を追記し、
 * 目次に戻るためのリンクを見出しの前に挿入する。
 * maketoc()関数は、リンクとアンカーを生成する。
 * このとき、名前として「TOC」から始まる文字列を使用する。
 * したがって、HTML中では、この文字列から始まる名前は使用しない。
 * 
 * 生成された目次の各項目にはCSSでスタイルを指定できる。
 * 各項目は、「TOCEntry」クラスに属する。
 * また、各項目は節見出しのレベルに応じて、もう1つクラス付けされる。
 * <h1>タグで生成された項目は、「TOCLevel1」クラスになる。
 * <h2>タグで生成された項目は、「TOCLevel2」クラス。以下同様。
 * 見出しに挿入される節番号は「TOCSecNum」というクラスになり、
 * 目次に戻るリンクは、「TOCBackLink」というクラスになる。
 * 
 * デフォルトでは、目次に戻るリンク用の文字列は「Contents」である。
 * これを変更したい場合は、maketoc.backLinkTextプロパティにテキストを設定する。
 */

var maketoc=function(){
	//リンク用path生成用 location
	var locat = location.href;
	var locat_array = [];
	locat_array = locat.split('/');
	locat_array.pop();
	var locat = locat_array.join('/');
	//コンテナを見つける
	var container = document.getElementById('page_navi_ol');
	if (!container) return;
	
	//目次の対象とするノードを決める
	//target を id="nav_div"とする。
	var target = document.getElementById('layer_1');
	if(!target) return;
	
	//ドキュメントを探索し、<h1>...<h6>タグを配列 h_lists に追加する
	var h_lists = [];
	/*
	 * 初期値は下記のように探索ノードがdocumentになっており、これで実行すると
	 * body以下すべて対象となる
	 * そのため、main_contentのみを対象とするように変更した。
	 */
	//findSections(document, sections);
	findSections(target, h_lists);
	
	
	//コンテナ要素の前にアンカーを挿入し、戻るためのリンクを追加できるようにする。
	var anchor = document.createElement('a');
	anchor.name = "TOCtop";
	anchor.id = "TOCtop";
	container.parentNode.insertBefore(anchor, container);
	
	//節番号を記録する配列を初期化する
	var sectionNumbers = [0, 0, 0, 0, 0, 0];
	
	//見つけた見出し要素をループを使って操作する。
	for (var s = 0; s < h_lists.length; s++) {
		var section = h_lists[s];
		
		//どのレベルの見出しかを判定する。
		var level = parseInt(section.tagName.charAt(1));
		if (isNaN(level) || level < 1 || level > 6) 
			continue;
		
		//この見出しレベルの節番号を増加する。
		//そして、このレベルより下の節番号を0にリセットする。
		sectionNumbers[level-1]++;
		for (var i = level; i < 6; i++) sectionNumbers[i] = 0;
		
		//すべての見出しレベル用の節番号を結合して、
		//2.3.1のような節番号を生成する。
		var sectionNumber = "";
		for (i = 0; i < level; i++) {
			sectionNumber += sectionNumbers[i];
			if (i < level - 1) 
				sectionNumber += ".";
		}
		
		//見出しの前に節番号とスペースを追加する。
		//スタイルを指定できるように、節番号を<span>中に記述する。
		var frag = document.createDocumentFragment(); //<span>とスペース用
		var span = document.createElement('span'); //番号を保持する
		span.className = "TOCSectNum"; //スタイル設定可能にする
		span.appendChild(document.createTextNode(sectionNumber)); //節番号を追加
		frag.appendChild(span); //spanをフラグメントに追加
		frag.appendChild(document.createTextNode(" ")); //次にスペースを追加
		
		//番号追記をやめる kamogashira 2010/4/16
		//番号追記行う kamogashira 2010/4/20
		section.insertBefore(frag, section.firstChild); //見出しに追加
		
		
		//節の先頭にアンカーを作成する
		var anchor = document.createElement('a');
		anchor.name = "TOC" + sectionNumber; //アンカー名を設定してリンク可能にする
		anchor.id = "TOC" + sectionNumber; //IEではアンカーにIDが必須。
		//アンカーの周りに、目次に戻るリンクを追加する。
		var link = document.createElement("a");
		link.href = locat+"/#TOCtop";
		link.className = "TOCBackLink";
		link.appendChild(document.createTextNode(maketoc.backlinkText));
		anchor.appendChild(link);
		//節見出しの直前にアンカーとリンクを挿入する
		section.parentNode.insertBefore(anchor, section);
		
		//この節へのリンクを生成する
		var link = document.createElement('a');
		link.href = locat+"/#TOC" + sectionNumber; //リンクのとび先を設定する
		link.innerHTML = section.innerHTML; //リンクのテキストは見出しと同じ
		//リンクをdiv内に配置し、レベルに応じたスタイルを設定可能にする
		
		/*****************************************************/
		//2011/12/25変更
		//div ではなく li タグを生成する。
		//		var entry = document.createElement('div');
		var entry = document.createElement('li');
		
		entry.className = "TOCEntry TOCLevel" + level; //CSS用
		entry.appendChild(link);
		
		//divをTOCコンテナに追加する
		container.appendChild(entry);
	}

	
	//このメソッドは、ノードnをルートとするツリー構造を探索し、
	//<h1>から<h6>までのタグを探し、配列に追加している
	function findSections(n, h_list){
		//nのすべての子要素をループで操作する。
		for (var m = n.firstChild; m != null; m 	=m.nextSibling) {
			//m は子要素である。
			//要素以外のノードは読みとばす。

			if (m.nodeType != 1 /*Node.Element_NODE*/) 
				continue;
			//コンテナ要素は目次なのでとばす。
			if (m == container)
				continue;
			//最適化として、見出しは段落中には現れないので
			//<p>要素は飛ばす
			if (m.tagName == "P") 
				continue;

			if(m.tagName == "HR")
				continue;
			
			/*
		 * 読み飛ばさなかった場合、見出しかどうかチェックする。
		 * 見出しの場合は配列に追加する。
		 * それ以外の場合は再帰的に処理する。
		 */
			if (m.tagName.length == 2 && m.tagName.charAt(0) == 'H') {
				h_list.push(m);
			}
			else {
				findSections(m, h_list);
			}
		}
	}
}
maketoc.backlinkText ="content";

makeToc.css

#page_navi{
	border:solid 1px #7697D6;
	/* border radius */
	-webkit-border-radius: 5px;
	-moz-border-radius: 5px;
	border-radius: 5px;
	margin:5px;
	padding:5px;
}
#page_navi header{
	text-align:center;
	background:#dedede;
}
#page_navi ol li{
	font-size:1.5em;
	width:140px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	-webkit-text-overflow: ellipsis;
	-o-text-overflow: ellipsis;
}