Menu Family: Adding A Context Menu To A Table

このExampleは、動かしただけでは意味の分からない例(YUIのExampleのページへのリンクはこちら)。

Exampleのページを読むと「何をしたいのか」分かるのだが、tableのようなたくさんの要素があるmarkupに対してContextMenuを貼る方法の例となっている。
このページでは、

tableのtdやtr(ulやli)といった数の多い要素(エレメント)に、ContextMenuインスタンスを貼り付けるのはレスポンスの観点から見てもよくない。
そのルート要素に貼り付けて(つまり、大きな括りのElementをtriggerにして)、動的にメニューのコンテンツを変化させる。

といったことが書かれている。

このExampleは、その方法を1つの示している。
サンプリングした初期画面は以下。YUIのExampleでは、99行もある行列が使われているが、上の目的を理解してしまえば、そんなに数は必要ないので、10行に減らした。
その代わりに、各行の第1列の要素に「type1」とかの「選択されるメニューのタイプ」を示した。タイプとしては5つのメニューが用意されている。(後述のソースコードを参照)

この例では、tableエレメントは、id=datasetというdiv要素をルートに囲まれている。
ContentMenuを生成するときのtriggerは、このdiv要素を設定する。
メニューの選択は、このdiv要素内で右クリックをしたときのtrエレメントのclass属性に設定で行うようにしてある。
このdiv要素内で右クリックをしたときの画面が以下。選択された行(tr)のスタイルを変え、ハイライトするようになっている。

以下にJavascriptを含むhtmlの全文をしめす。
今回の例でも、scriptの空間構造は変えないようにした。

<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/fonts/fonts-min.css" />
<link rel="stylesheet" type="text/css" href="scripts/yui/reset/reset.css" />
<link rel="stylesheet" type="text/css" href="scripts/yui/menu/assets/skins/sam/menu.css" />

<script type="text/javascript" src="scripts/yui/yahoo/yahoo-min.js"></script>
<script type="text/javascript" src="scripts/yui/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="scripts/yui/container/container_core-min.js"></script>
<script type="text/javascript" src="scripts/yui/menu/menu-min.js"></script>

<style type="text/css" id="defaultstyle">

h1 { 
	font-weight: bold; 
	margin: 0 0 1em 0;
}

body {
	padding: 1em;
}

p, ul {
	margin: 1em 0;
}
            
p em,
#operainstructions li em {
	font-weight: bold;
}

#operainstructions {
	list-style-type: square;
	margin-left: 2em;
}

#dataset {
	border: solid 1px #000;
}

#dataset tr.odd {	
	background-color: #ccc;
}
            
#dataset tr.selected {
	background-color: #039;
}

#dataset td {
	border: solid 1px #000;
	padding: .25em .5em;
}

</style>

<script type="text/javascript">

YAHOO.util.Event.onContentReady("dataset", function () {

	var Dom = YAHOO.util.Dom;
	var oSelectedTR;  // contextmenuイベントのtargetとなる<tr>を格納する
	
    /*
    Map of CSS class names to arrays of MenuItem 
    configuration properties.
	*/
	var oContextMenuItems = {
	    "type1": [
                "Context Menu 1, Item 1", 
                {
                    text: "Context Menu 1, Item 2", 
                    submenu: { 
                                id: "submenu1", 
                                lazyload: true, 
                                itemdata: [
                                    "Context Menu 1 Submenu, Item 1", 
                                    "Context Menu 1 Submenu, Item 2", 
                                    "Context Menu 1 Submenu, Item 3", 
                                    "Context Menu 1 Submenu, Item 4"
                                ] 
                            } 
                }, 
                "Context Menu 1, Item 3", 
                "Context Menu 1, Item 4"
            ],

    	"type2": [
                "Context Menu 2, Item 1", 
                "Context Menu 2, Item 2", 
                "Context Menu 2, Item 3", 
                "Context Menu 2, Item 4", 
                "Context Menu 2, Item 5", 
                "Context Menu 2, Item 6", 
                "Context Menu 2, Item 7", 
                "Context Menu 2, Item 8", 
                "Context Menu 2, Item 9", 
                "Context Menu 2, Item 10"
            ],

    	"type3": [
                "Context Menu 3, Item 1", 
                "Context Menu 3, Item 2", 
                "Context Menu 3, Item 3", 
                "Context Menu 3, Item 4"
            ],

    	"type4": [
                "Context Menu 4, Item 1", 
                "Context Menu 4, Item 2"
            ],

    	"type5": [
                "Context Menu 5, Item 1", 
                "Context Menu 5, Item 2", 
                "Context Menu 5, Item 3", 
                "Context Menu 5, Item 4", 
                "Context Menu 5, Item 5", 
                "Context Menu 5, Item 6"
            ]

	};

	//
	// ContextMenuがshowされるまえのハンドラー
	// ContextMenuが表示されるきっかけとなった、要素の<tr>のclass定義から
	// Menuの中身を選択して、レンダリングを行う
   	// thisは、選択されたContextMenuインスタンス 

   	function onContextMenuBeforeShow(p_sType, p_aArgs) {

		// this.contextEventTargetはメニュー表示のきっかけとなった
		// contextmenuイベントの発生のHTMLエレメント。
    	var oTarget = this.contextEventTarget,
    		aMenuItems,
        	aClasses;

		// this.getRoot():ルートメニュー
    	if (this.getRoot() == this) {

			// ContextMenuのTargetとして、TRノードを探し、oSelectedTRに格納。
        	oSelectedTR = oTarget.nodeName.toUpperCase() == "TR" ? 
						oTarget : Dom.getAncestorByTagName(oTarget, "TR");

			// TargetになったoSelectedTRが、oddというclass属性を持つときは、
			// class属性をスペースで分割して、表示するMenuを選択する。
			// 以外は、trimだけかけて、Menuを選択する。
        	if (Dom.hasClass(oSelectedTR, "odd")) {
            	aClasses = oSelectedTR.className.split(" ");
            	aMenuItems = oContextMenuItems[aClasses[0]];
        	}
        	else {
            	aMenuItems = 
                oContextMenuItems[YAHOO.lang.trim(oSelectedTR.className)];
        	}

        	// ContextMenuインスタンスの中をクリアする。
        	this.clearContent();

        	// ContextMenuインスタンスに、上で選んだメニューを追加する。                    
        	this.addItems(aMenuItems);

        	// レンダリング
	        this.render();

    	    // contextmenuイベントのターゲットとなった<tr>をハイライトする。
	        Dom.addClass(oSelectedTR, "selected");
	    }
	}

	// hideイベントのイベントハンドラ
	function onContextMenuHide(p_sType, p_aArgs) {

    	if (this.getRoot() == this && oSelectedTR) {
        	Dom.removeClass(oSelectedTR, "selected");
    	}

	}

	// ContextMenuのインスタンス化
	var oContextMenu = 
		new YAHOO.widget.ContextMenu("contextmenu", 
					{
					// id=datasetのエレメントでクリックしたら、メニュー表示 
					trigger: "dataset", 
					lazyload: true 
					});

	// ContextMenuインスタンスにbeforeShowとhideのイベントハンドラを仕掛ける
	oContextMenu.subscribe("beforeShow", onContextMenuBeforeShow);
	oContextMenu.subscribe("hide", onContextMenuHide);            

});

</script>
</HEAD>

<!-- class=" yui-skin-sam"の指定が必要 -->
<BODY class="yui-skin-sam">
<p>
動的に、表示するコンテキストメニューを変えるサンプルです。<br/>
"type1"から"type5"までのメニューを、クリックした行の情報をもとに切り替えます。
</p>
<table id="dataset">

<tr class="type5 odd"><td>(type5)Row 0, Column 1</td><td>Row 0, Column 2</td><td>Row 0, Column 3</td><td>Row 0, Column 4</td></tr>
<tr class="type3"><td>(type3)Row 1, Column 1</td><td>Row 1, Column 2</td><td>Row 1, Column 3</td><td>Row 1, Column 4</td></tr>

<tr class="type2 odd"><td>(type2)Row 2, Column 1</td><td>Row 2, Column 2</td><td>Row 2, Column 3</td><td>Row 2, Column 4</td></tr>
<tr class="type5"><td>(type5)Row 3, Column 1</td><td>Row 3, Column 2</td><td>Row 3, Column 3</td><td>Row 3, Column 4</td></tr>
<tr class="type3 odd"><td>(type3)Row 4, Column 1</td><td>Row 4, Column 2</td><td>Row 4, Column 3</td><td>Row 4, Column 4</td></tr>
<tr class="type1"><td>(type1)Row 5, Column 1</td><td>Row 5, Column 2</td><td>Row 5, Column 3</td><td>Row 5, Column 4</td></tr>

<tr class="type5 odd"><td>(type5)Row 6, Column 1</td><td>Row 6, Column 2</td><td>Row 6, Column 3</td><td>Row 6, Column 4</td></tr>
<tr class="type1"><td>(type1)Row 7, Column 1</td><td>Row 7, Column 2</td><td>Row 7, Column 3</td><td>Row 7, Column 4</td></tr>
<tr class="type5 odd"><td>(type5)Row 8, Column 1</td><td>Row 8, Column 2</td><td>Row 8, Column 3</td><td>Row 8, Column 4</td></tr>
<tr class="type4"><td>(type4)Row 9, Column 1</td><td>Row 9, Column 2</td><td>Row 9, Column 3</td><td>Row 9, Column 4</td></tr>

</table>

</BODY>
</HTML>