jqueryで目次を作るプログラム

CMSの記事で、目次が有ると良いんだけど、毎回管理画面で入力するのかアホくさいので、
Jquryで目次のul>liを作ってくれるプログラムを作ってみた。

##使い方？

 * 一番下のソースで適当にjsファイルを作って読み込む。toc.jsとでも。  
 ※読み込む方法とかは調べてください。
 * 設定値を環境に合わせる
 * 動くwww

気付いたと思うけど、**CSSは無い**のでご自由にwww

###設定値

最低限、下の2個だけ環境に合わせれば、動く。
他の設定値はソースに書いてる

```
contentSelecter = jqueryのselecter文字列
reg = 目次に置き換える部分の正規表現オブジェクト
```


##ソース

```js
jQuery(function($){
	var toc = {
		//コンテンツ部分のセレクター
		contentSelecter :'.column-detail_content',
		//目次HTMLを配置する目印
		reg:new RegExp("\\[@目次@\]"),
		//H3H4の時に文字列の前に入れるスペーサー
		//H3の時は1回、h4の時は2回
		spacer:'&nbsp;&nbsp;',
		//目次htmlのclass名を付ける
		class:{
			ul:'toc_warp',
			li:'toc_li',
			a:'toc_ancker',
		},
		//アンカーへスライドする時のオフセット値
		ofsetTop:-20,
		
	
		//作成した目次html
		html :'',
		//目次を作るのに必要なデータを格納
		rows : [],
		numType :[],
		ids:{
			h2:[],
			h3:[],
			h4:[]
		},

		/**
		 *	全体処理
		 */
		make:function(){
			if(toc.isMakeToc()){
				toc.getHeadingNo();
				toc.setHeadingId();
				toc.makeHtml();
				toc.replace();
			}
		},
		/**
		 * 目次部分をhtmlに埋め込む
		 */
		replace:function(){
			var contDom =  $(toc.contentSelecter);
			html = contDom.html().replace(toc.reg, toc.html);
			contDom.html(html);
		},
		/**
		 * 目次部分のhtmlを作る
		 */
		makeHtml:function(){
			var contDom =  $(toc.contentSelecter);
			html = '';
			for(var i = 0; i < toc.numType.length;i++){
				type = toc.numType[i];
				html = html +'<li class="'+toc.class.li+' level_'+type.level+'">';
				html = html +'<a class="'+toc.class.a+'" href="#'+type.id+'">';
				for(var s = 2; s < type.level; s++ ){
					html = html + toc.spacer;
				}
				html = html + contDom.find('#'+type.id).text();
				html = html +'</a>';
				html = html +"</li>\n";
			}
			toc.html = '<ul class="'+toc.class.ul+'">'+html+'</ul>';
		},
		/**
		 * h2～h4のタグにIDを作る
		 * @return {[type]} [description]
		 */
		setHeadingId:function(){
			var contDom =  $(toc.contentSelecter);
			var h2s = contDom.find('h2');
			for(var i = 0; i < h2s.length;i++){
				var h2Dom = $(h2s[i]);
				var id = toc.ids.h2[i];
				h2Dom.attr('id',id);
			}
			var h3s = contDom.find('h3');
			for(var i = 0; i < h3s.length;i++){
				var h3Dom = $(h3s[i]);
				var id = toc.ids.h3[i];
				h3Dom.attr('id',id);
			}
			var h4s = contDom.find('h4');
			for(var i = 0; i < h4s.length;i++){
				var h4Dom = $(h4s[i]);
				var id = toc.ids.h4[i];
				h4Dom.attr('id',id);
			}
		},
		/**
		 * h2~h4までのタグを調べて、それぞれのidを作っていく
		 * もっとかっこいい書き方が有ると思うけど、非同期処理対策の為にカッコ悪い方法をしてる。
		 */
		getHeadingNo:function(){
			cntentHtml = $(toc.contentSelecter).html();
			var h2ary = cntentHtml.split('<h2');			
			for(var i = 1; i < h2ary.length;i++){
				idName =('00'+i).slice(-2);
				toc.ids.h2.push(idName);
				toc.numType.push({
					level :2,
					id:idName
				});
				h2row  = {};
				h2row['h2Str'] = h2ary[i];
				//h3で分割
				h2row = toc._splitH3(h2row,idName);
				toc.rows.push(h2row);				 
			}
			//できた後のデータを確認する場合はtoc.rowsをconsole.log;
			// console.log(toc.rows);
		},
		//h3タグで分割する
		_splitH3:function(h2row,h2Name){
			if(h2row['h2Str'].indexOf('<h3') >= 0){
				h2row['h3'] = [];
				var h3ary = h2row['h2Str'].split('<h3');
				for(var i3 = 1; i3 < h3ary.length;i3++){
					idName =h2Name +'-'+('00'+i3).slice(-2);
					toc.ids.h3.push(idName);
					toc.numType.push({
						level :3,
						id:idName
					});
					h3row = {};
					h3row['h3str'] = h3ary[i3];
					//h4で分割
					h3row = toc._splitH4(h3row,idName);
					h2row['h3'].push(h3row);
				}
			}
			return h2row;
		},
		//h4タグで分割する
		_splitH4 : function(h3row,h3Name){
			if(h3row['h3str'].indexOf('<h4') >= 0){
				h3row['h4'] = [];
				var h4ary = h3row['h3str'].split('<h4');
				for(var i4 = 1; i4 < h4ary.length;i4++){
					idName =h3Name +'-'+('00'+i4).slice(-2);
					toc.ids.h4.push(idName);
					toc.numType.push({
						level :4,
						id:idName
					});
					h4row = {};
					h4row['h4str'] = h4ary[i4];
					h3row['h4'].push(h4row);
				}				
			}
			return h3row;
		},
		/**
		* 目次を作るか確認する。
		* toc.regに入ってる正規表現にマッチするものが有れば作る。
		* @return bool 作る場合はTRUE
		*/
		isMakeToc : function(){
			var contentHtml = $(toc.contentSelecter).html();
			var reg = toc.reg;
			var isCot = contentHtml.match(reg);
			if(isCot !== null){
				return true;
			}
			return false;
		}
	};
	
	toc.make();
	
	
	//目次をクリックしたら、アンカーまでスライドする。
	$(document).on('click', '.toc_ancker', function(){
		var dom = $(this);
		var targSelecter = dom.attr('href');
		var targPos = $(targSelecter).offset().top;
		targPos = targPos + toc.ofsetTop;
		$("html,body").animate({scrollTop:targPos});	
		return false;
	});
});
```