YUI2.7.0+PHP5で画面のヘルプ機能を自作する。

漠然としたタイトルだが、要するに「アプリを作ったとき、画面それぞれにヘルプをつけたい」というためのプログラムのこと。

先日のログで作成した、(ログインユーザーのロールに応じた)メニュー機能を転用し、以下の仕様とした。

  • ヘルプの文面はMarkupで記述し、サーバーのhelpディレクトリ下におく。
  • ヘルプを記述したファイルの、ファイル名は、(対応する画面の)ファイル名+'.txt'とする。
  • アプリでは、画面のどこかに「?」を記述し、そこをクリックすると、YUIのパネルに差し込まれたヘルプを表示する。
  • パネルはドラッグ・アンド・ドロップ可能なウィンドウとする。


具体的なイメージを見てしまった方が早い。以下は、初期画面のスクリーンショット


上の「?」のリンクをクリックすると、下のようなヘルプを記述したウィンドウが表示される。


ウィンドウに差し込んだマークアップは、以下(help/test_help1.html.txtという変な名前)。

画面idに対応したヘルプ画面を表示するサンプルです。<br>
helpディレクトリ下に、
<ul>
<li> 画面のファイル名+".txt"
</ul>
でファイルを作成してください。<br>
このテキストのファイル名は<strong>test_help1.html.txt</strong>
です。


このために作成したプログラムは以下。

XHRを通じて送信された画面のファイル名から、対応するヘルプをフィードする getHelp1.php
ヘルプ文書の要求とパネルの生成などおこなうHTML test_help1.html


以下が、getHelp1.php。helpディレクトリ下のファイルをピックアップするために、以前に作成した、TextPickup.class.phpを利用している。メニュー機能のときと同様に、helpディレクトリ下にdefault.txtというMarkup文書を作成しておけば、要求に該当する文書が見つからなかった場合に、代わりにレスポンスされる。

<?php
/* 
 * ヘルプの取得を行う
 *  ヘルプは、help/下にユーザーロール別に存在する前提です。
 *      
 *		author	; t.odaka
 *		date	; 2009/5/8
*/
	require_once("TextPickup.class.php");
	require_once("../Myznala/MyConverter.class.php");
	
	// リクエストデータの取り出し
	switch($_SERVER['REQUEST_METHOD']) {
		case 'GET'	: $rMethod = &$_GET; break;
		case 'POST'	: $rMethod = &$_POST; break;
		default:
	}

	// パラメータをサニタイズして配列に入れる。
	$cObj = new MyConverter();
	$reqParm = array();
	foreach ($rMethod as $key => $value) {
		$key	=$cObj->sanitize($key,'UTF-8');
		$value	=$cObj->sanitize($value,'UTF-8');
		$m_log->debug($key.'; '.$value); // Debugログ
		$reqParm[$key]=$value;
	}
	
	// 取り出すメニューの名称
	$_help = 'help/'.$reqParm["fname"].'.txt';
	if(!file_exists($_help)) $_help = 'help/default.txt';
	
	// テキストの取り出し
	$ret = null;
	$tObj = new TextPickup();
	$tObj->setFileName($_help);
	$fp = $tObj->fileOpen('r');
	$ret = $tObj->pickupText($fp);
	$tObj->fileClose($fp,'r');

	// 出力
	header("Content-Type:text/html");
	echo($ret);
	
	return;
?>


以下が、Javascriptを含むHTMLの全文(test_help1.html)。比較的シンプルになっている。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html> 
<head> 
	<meta http-equiv="Pragma" content="no-cache">
	<meta http-equiv="Cache-Control" content="no-cache">
	<meta http-equiv="Expires" content="Thu, 01 Dec 1994 16:00:00 GMT">
	<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
	<meta http-equiv="Content-Style-Type" content="text/css">
	<meta http-equiv="Content-Script-Type" content="text/javascript">
<title>Menu</title> 

<link rel="stylesheet" type="text/css" href="../scripts/lib/yui/build/fonts/fonts-min.css" /> 
<link rel="stylesheet" type="text/css" href="../scripts/lib/yui/build/container/assets/skins/sam/container.css" /> 

<script type="text/javascript" src="../scripts/lib/yui/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="../scripts/lib/yui/build/connection/connection-min.js" ></script>
<script type="text/javascript" src="../scripts/lib/yui/build/dragdrop/dragdrop-min.js" ></script>
<script type="text/javascript" src="../scripts/lib/yui/build/container/container-min.js" ></script> 
<style type="text/css" id="defaultstyle">
#main {
	margin: 2px;
	padding: 3px;
}

.ez_error {
	/* red(エラー用) */
	color:#ff0000;
}

#res {
	visibility: hidden;
}
</style>

<script type="text/javascript">
DisplayHelp = function() {
	var Event	= YAHOO.util.Event;
	var Dom		= YAHOO.util.Dom;
	var Connect	= YAHOO.util.Connect;
	var Panel 	= YAHOO.widget.Panel;
	
	var helpPanel;

	/*
	* メニューリンクをクリックしたときのハンドラ
	*/
	var helpClickHdlr = function(_evt){
		Event.preventDefault(_evt);

		// メッセージのクリア
		Dom.get('msg').innerHTML = '';
		Dom.get('helpDiv').innerHTML = '';

		var _url	= 'getHelp1.php';
		var _arg ={
			'errId'	:	'msg',
			'resId'	: 	'helpDiv'
		};
		helpCallback.argument = _arg;
		var _parm = 'fname=' + Dom.get('pagename').innerHTML;
		// ajaxで検証
		YAHOO.util.Connect.asyncRequest('POST',_url,
						helpCallback, _parm);
	}
		
	/*
	* ヘルプ取得時のコールバック
	*/
	var helpCallback = {
    	        success : function(_obj) {
		        var _resId = _obj.argument.resId;
			var _errId = _obj.argument.errId;

			// XHRの戻り値の取得(メニュー文字列)
			var _ret = _obj.responseText;

			// メニューの表示
			if(_ret.length > 0){
		 		//Panelのインスタンス化:
				helpPanel = new Panel("hpanel", 
						{ 	width:"320px", 
							visible:true, 
							draggable:true, 
							close:true,
							constraintoviewport:true
						}
				);
				helpPanel.setHeader("Help");
				helpPanel.setBody(_ret);
				helpPanel.setFooter(Dom.get('pagename').innerHTML);
				// id=panel1のMarkupが存在しないので、
				// renderingする場所(div)を指定
				// div id=helpDivにappendされる。
				helpPanel.render("helpDiv");
			} else {
	 			// エラーのハンドル(皆さん適当に)
				Dom.get(_errId).innerHTML = 'メニューの取得に失敗しました.';
			}
		},
		
     	        failure : function(_obj) {
 			var _errId = _obj.argument.errId;
 			var _ret = 'ステータス: ' + _obj.status + 'ステータステキスト: ' +
 						_obj.statusText + ' メニューの取得に失敗しました。';
 			// エラーのハンドル(皆さん適当に)
 			Dom.get(_errId).innerHTML = _ret;	     
 		}
	 };

	return{
    	init: function() {
    	// ヘルプ画面のハンドラー
		Event.on('lnk1',
   			'click',
	        	helpClickHdlr);

		}, // initの終わり
	};
}();

//DOMが完全にloadされたら、サンプルを初期化する。
YAHOO.util.Event.onDOMReady(
	//DomReadyイベントで発火するハンドラ
	DisplayHelp.init,
	//ハンドラに渡すオブジェクト
	DisplayHelp,
	//ハンドラは、上記のオブジェクトのスコープをもつ。   
	true
);

</script>
</HEAD>

<BODY class="yui-skin-sam">
<div id="pagename">test_help1.html</div>
<br>
<div id="container">
<p>
画面ヘルプのサンプルです。<br/>
</p>
<a id="lnk1" href="#" class="lnk">?</a>
<div id="msg" class=".ez_error"></div>
<div id="res"></div>

<!-- ヘルプ表示のためのマークアップ -->
<div id = 'helpDiv'></div>

</div>
</BODY>
</HTML>