Layout Manager: Layout inside a resizable Panel

実は(わざわざもったいぶって言うことでもないのだが)、このLayout Panelというのは個人的には好きではない。
これは、かつて(随分前だけど)、dojoでひどい目にあったことがある。
簡単そうで、(その中をごちゃごちゃやろうとすると)意外と面倒くさいというイメージ。

ここで紹介されているサンプルは、ResizableなPanelに4ペイン(ヘッダー、フッターと真ん中2つ)のLayoutで、真ん中の仕切りは引っ張れるようになっている。(下)

外側の枠はYAHOO.widget.Panelになっていて、Resizableの修飾を加えるのは、以前の「Container Family: Creating a Resizable Panel」と同じ。
この間(Panelがrenderingされる前)に、YAHOO.widget.Layoutをつかって仕切りを作る。
YAHOO.widget.LayoutのAPIドキュメントを見ると、仕切りはLayoutUnitオブジェクトになるらしい。

こまごました事はソースに記したが、resizeのイベントにあわせて、Layoutをresizeする必要がある。
このタイミングで、centerユニットの文言を変えてみた。LayoutUnitはYAHOO.widget.Elementを祖先にもつので、DOM的に扱うのが正当なのだろうが、body属性をsetメソッドで変更したのが以下である。
(とても窮屈なコードなので、良いサンプルとはいえないなぁ)

以下に、Javascriptを含むHTML全文を示す。
コードはモジュール・パターンに書き直した。

<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE>Ajax_Sampling</TITLE>

<style type="text/css">
body {
	margin:0;
	padding:0;
}
</style>
<link rel="stylesheet" type="text/css" href="scripts/yui/reset-fonts-grids/reset-fonts-grids.css" /> 
<link rel="stylesheet" type="text/css" href="scripts/yui/container/assets/skins/sam/container.css" /> 
<link rel="stylesheet" type="text/css" href="scripts/yui/resize/assets/skins/sam/resize.css" /> 
<link rel="stylesheet" type="text/css" href="scripts/yui/layout/assets/skins/sam/layout.css" /> 
<link rel="stylesheet" type="text/css" href="scripts/yui/button/assets/skins/sam/button.css" /> 
<script type="text/javascript" src="scripts/yui/yahoo/yahoo-min.js"></script> 
<script type="text/javascript" src="scripts/yui/event/event-min.js"></script> 
<script type="text/javascript" src="scripts/yui/dom/dom-min.js"></script> 
<script type="text/javascript" src="scripts/yui/element/element-beta-min.js"></script> 
<script type="text/javascript" src="scripts/yui/dragdrop/dragdrop-min.js"></script> 
<script type="text/javascript" src="scripts/yui/container/container-min.js"></script> 
<script type="text/javascript" src="scripts/yui/resize/resize-min.js"></script> 
<script type="text/javascript" src="scripts/yui/animation/animation-min.js"></script> 
<script type="text/javascript" src="scripts/yui/layout/layout-min.js"></script> 

<style type="text/css" id="defaultstyle">
/*
#container {
	margin: 2px;
	padding: 3px;
	width: 400px;
	height: auto;
	border:1px dashed #999999;
}
*/

#demo .yui-resize-handle-br {
    height: 11px;
    width: 11px;
    background-position: -20px -60px;
    background-color: transparent;
}

</style>

<script type="text/javascript">
YAHOO.namespace("EGP");

YAHOO.EGP.LayoutResizable = function() {
    var Dom = YAHOO.util.Dom,
    Event = YAHOO.util.Event,
    layout = null,
    resize = null;
			
	return{
    	init: function() {
		// Panel(大枠)の作成
		var panel = new YAHOO.widget.Panel('demo', {
            draggable: true,
            close: false,
            autofillheight: "body", // default value, specified here to highlight its use in the example            
            underlay: 'none',
            width: '500px',
            xy: [100, 100]
        });
        panel.setHeader('Test Panel');
		// bodyに大枠を分割してLayoutするためのElementをセットする。
        panel.setBody('<div id="layout"></div>');
        
		// 大枠のPanelがレンダリングされる前のイベントとして、レイアウト構築を仕込む。
		panel.beforeRenderEvent.subscribe(function() {
			// 上で追加したlayoutエレメントが利用可能になるまで待つ
			Event.onAvailable('layout', function() {
                layout = new YAHOO.widget.Layout('layout', {
                    height: 400,
                    // 大枠の幅は500pixなので、padding:20pxと同じことになる(※)
                    width: 480,
                    // Yahoo.widget.LayoutUnitになる。
                    units: [
                        // Topのレイアウト。 gutter(溝)は周囲2pix
                        { position: 'top', 
                            height: 25, 
                            resize: false, 
                            body: 'Top', 
                            gutter: '2' },
                        // Leftのレイアウト
                        { position: 'left', 
                            width: 150,
                            // resize可能 
                            resize: true, 
                            body: 'Left', 
                            // gutter の指定は 't r b l'。rは引っ張るので大きめ。
                            gutter: '0 5 0 2', 
                            // resizeする際の制限値
                            minWidth: 150, 
                            maxWidth: 300 },
                        // Bottomのレイアウト
                        { position: 'bottom', 
                            height: 25, 
                            body: 'Bottom', 
                            gutter: '2' },
                       // Centerのレイアウト
                        { position: 'center', 
                            body: 'Center Unit', 
                            gutter: '0 2 0 0' }
                    ]
                });
 				// まず、レイアウトをレンダリングする。
                layout.render();
            });
        });
        // Layoutの次にPanelをレンダリングする。
        panel.render();

        // Resizeで修飾する。
        resize = new YAHOO.util.Resize('demo', {
            handles: ['br'],
            autoRatio: true,
            status: false,
            minWidth: 380,
            minHeight: 400
        });

        // resizeのresizeイベントのタイミングでレイアウトを変更する。
        resize.on('resize', function(args) {
            var panelHeight = args.height,
            // 上※
            padding = 20;
            //Hack to trick IE into behaving
            Dom.setStyle('layout', 'display', 'none');
			// this は Panel
            this.cfg.setProperty("height", panelHeight + 'px');
            // おまじない。
            layout.set('height', this.body.offsetHeight - padding);
            layout.set('width', this.body.offsetWidth - padding);
            // 遊び
            var wkLu = layout.getUnitByPosition('center');
            wkLu.set('body','Resizeされました。');
            //Hack to trick IE into behaving
            Dom.setStyle('layout', 'display', 'block');
			// Layoutをresizeする。
            layout.resize();
     
        	}, 
        panel, true);
	}
	};
}();
		
//DOMが完全にloadされたら、サンプルを初期化する。
YAHOO.util.Event.onDOMReady(
		//DomReadyイベントで発火するハンドラ
		YAHOO.EGP.LayoutResizable.init,
		//ハンドラに渡すオブジェクト(関数)
		YAHOO.EGP.LayoutResizable,
		//ハンドラは、上記のオブジェクトのスコープをもつ。   
		true
);
</script>
</HEAD>

<BODY class="yui-skin-sam">
<div id="demo"></div> 
</BODY>
</HTML>