Browser History Manager: TabView Control

YUIには、Browser History Managerという変わった機能がある。

このサンプルは以下のようにTabviewを使った例となっている。

ここで、上の画面には現れていないが、ブラウザーのURLが

http://........../ajax_yui_history_tabview_control.html#tabview=tab1

となっている。
History Managerでは、このように(セクションを表示する形式で)画面の遷移が管理される。History Managerがユニークなのは、画面の「進む」/「戻る」という動きについても、これをスタックするようになっていること。
そして、これらの管理された画面の動きは、「進む」/「戻る」ボタンと連動したHistory Managerから再現される。

History Managerは、画面の遷移をスタックするもので、画面そのものをキャッシュするものではない。
(ブラウザのキャッシュ機能が有効になっていれば、staticなページについてはそれが再利用される。History Mangerによって遷移がスタックされ、ブラウザーの機能によってキャッシュされることになる)

以下にHTMLの全文を示す。
YUIのExampleのソースは非常に読みにくいので、モジュールパターンで書き直しを行い、どのような手順でHistory Managerが画面をスタックしていくのかについて注釈を加えた(特に重要な部分については、[戦略]という書いてある)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html> 
<head> 
    <meta http-equiv="content-type" content="text/html; charset=utf-8"> 
<title>Ajax Sample</title> 
 
<style type="text/css"> 
body {
	margin:0;
	padding:0;
}
</style> 

<link rel="stylesheet" type="text/css" href="scripts/yui/fonts/fonts-min.css" /> 
<link rel="stylesheet" type="text/css" href="scripts/yui/tabview/assets/skins/sam/tabview.css" /> 
<script type="text/javascript" src="scripts/yui/yahoo-dom-event/yahoo-dom-event.js"></script> 
<script type="text/javascript" src="scripts/yui/element/element-beta-min.js"></script> 
<script type="text/javascript" src="scripts/yui/tabview/tabview-min.js"></script> 
<script type="text/javascript" src="scripts/yui/history/history-min.js"></script> 

<style type="text/css" id="defaultstyle">
#main {
	margin: 2px;
	padding: 3px;
	width: 450px;
}
#yui-history-iframe {
  position:absolute;
  top:0; left:0;
  width:1px; height:1px; /* avoid scrollbars */
  visibility:hidden;
}
 
#demo { margin-bottom:1em; }

</style>

<script type="text/javascript"> 
//
//モジュールパターンで実装する。
//
YAHOO.namespace("EGP");

YAHOO.EGP.SimpleNavigation = function() {

    var bookmarkedTabViewState;
    var initialTabViewState;
    var tabView;

    // Activeなタブが変更されたら実行されるハンドラ。
    //  ... [戦略] タブ変更のイベントで、訪れたstate(ページ)をnavigateでスタックし、
    //      register時に登録した、※1様の、ページ表示関数を呼び出す。
    function handleTabViewActiveTabChange (e) {
        var newState, 
        currentState;
        newState = "tab" + this.getTabIndex(e.newValue);
 
        try {
            currentState = YAHOO.util.History.getCurrentState("tabview");
            if (newState != currentState) {
                // 訪れたstateをスタックする。そして、※1を呼ぶ。
                YAHOO.util.History.navigate("tabview", newState);
            }
        } catch (e) {
            tabView.set("activeIndex", newState.substr(3));
        }
    }
 
    // Tabviewの初期化を行う。
    // ... [戦略] ※2 画面を表示させるための初期化処理を行い、※3様のハンドラを仕掛ける。
    function initTabView () {
        // Instantiate the TabView control...
        tabView = new YAHOO.widget.TabView("demo");
        // [戦略] ※3 ページが遷移するイベントに、上のようなハンドラを仕掛ける。
        tabView.addListener("activeTabChange", 
                		handleTabViewActiveTabChange);
    }
	    	    
    return {
		init : function(){
	     	    // 初期画面(initSection)の決定を行う。==========================
		    // 決まり文句
	     	    bookmarkedTabViewState = YAHOO.util.History.getBookmarkedState("tabview");
    	            initialTabViewState = bookmarkedTabViewState || "tab0";
    	 
	    	    // モジュール;navbar(これがSection名になる)とその最初のセクションを登録する。===================
    	            // (注) History.initializeより前に行われなくていけない。
    	            YAHOO.util.History.register("tabview", initialTabViewState,
    	    	    // [戦略] ※1 
  	            // この関数は、YAHOO.util.History.navigateが呼ばれるか、back/forward button
       	    	    // が押されたときに動く。
        	    function (state) {
			// tabviewのタブを変更
    	    		tabView.set("activeIndex", state.substr(3));
    	    	    }
    	    );

   	    	// History Managerがreadyになったら発火するハンドラ。=====================
		// ...History Managerが非同期に生成されるため。
   	    	YAHOO.util.History.onReady(function () {
    	        var currentState;
    	        initTabView();
    	 	// currestState(tab0 etc)が入る。
    	        currentState = YAHOO.util.History.getCurrentState("tabview");
    	        tabView.set("activeIndex", currentState.substr(3));
    	    });
    	 
   	    // History Managerの初期化==========================================
   	    // initialize("aplicationのステートを保存するマークアップ","Historyを保存するiframe")
    	    try {
    	        YAHOO.util.History.initialize("yui-history-field", "yui-history-iframe");
    	    } catch (e) {
    	        // The only exception that gets thrown here is when the browser is
    	        // not supported (Opera, or not A-grade) Degrade gracefully.
    	        initTabView();
    	    }
       	}
	};
}();

//DOMが完全にloadされたら、サンプルを初期化する。
YAHOO.util.Event.onDOMReady(
	//DomReadyイベントで発火するハンドラ
	YAHOO.EGP.SimpleNavigation.init,
	//ハンドラに渡すオブジェクト(関数)
	YAHOO.EGP.SimpleNavigation,
	//ハンドラは、上記のオブジェクトのスコープをもつ。   
	true
);
</script>
</head> 
 
<body class="yui-skin-sam">
<iframe id="yui-history-iframe" src="scripts/yui/history/assets/blank.html"></iframe> 
<input id="yui-history-field" type="hidden"> 

<div id="main">

<div id="demo" class="yui-navset yui-navset-top"> 
  <ul class="yui-nav"> 
    <li>
    	<a href="#tab1"><em>Tab One Label</em></a>
    </li> 
    <li title="active" class="selected">
    	<a href="#tab2"><em>Tab Two Label</em></a>
    </li> 
    <li title="" class="">
    	<a href="#tab3"><em>Tab Three Label</em></a>
    </li> 
  </ul> 
  <div class="yui-content"> 
    <div style="display: none;" id="tab1"><p>Tab One Content</p></div> 
    <div style="display: block;" id="tab2"><p>Tab Two Content</p></div> 
    <div style="display: none;" id="tab3"><p>Tab Three Content</p></div> 
  </div> 
</div> 

</div>
</body> 
</html>