フォームの入力項目ごとのヘルプコンテンツを動的に表示・非表示する

Jenkinsで、ジョブの作成や設定などで、画面の右側にあるクエスチョンマークのついたアイコンをクリックすると、ヘルプが表示される例のアレ。

私的にすごく気に入っていて(たかが一つの項目の説明を知りたいだけなのに、いちいちPDFやWordのユーザーズガイドを見るなんて面倒だし)、今作っているアプリでも同じようなことをしたいと思った。

そんなわけで、より簡単な形で、既存のHTMLに組み込めるようなものを書いてみた。

form.html

まず入力フォーム。ここで<span>タグで囲まれた[?]をクリックすることで、ヘルプコンテンツを挿入されるようにしたいというもの。

入力フォーム用のHTMLでは、以下のように<table>を使ってフォームを表示させているとする。
この例では、NameとPasswordの2つのテキストフィールドがある。

<table class="form">
  <tr>
    <td>Name <span id="help-name" class="help">[?]</span></td>
    <td><input type="text" id="name" /></td>
  </tr>
  <tr>
    <td>Password <span id="help-password" class="help">[?]</span></td>
    <td><input type="password" id="password" /></td>
  </tr>
</table>

「Name」や「Password」の右にある[?]をクリックすると、その下に1行新しく追加して、該当項目に対するヘルプコンテンツが表示されるようにする。

_help.html

挿入するヘルプコンテンツは、以下のようなHTMLファイルを別に用意*1

form.html中でNameの右の[?]をクリックすると「hoge」、Passwordの右の[?]をクリックすると「fuga」というヘルプコンテンツが挿入されるようにしたい。

<html>
<head>
<title>Example</title>
</head>
<body>
  <p id="help-name">
    hoge
  </p>
  
  <p id="help-password">
    fuga
  </p>
<body>
</html>

help.js

ここまでが準備。で、肝になるのがこのJavascript

form.html側で、以下のJavascriptを読み込んでおくようにする(要JQuery)。

$(document).ready(function() {
  $(".help").unbind("click").bind("click", function() {
    var id = $(this).attr("id");
    var helpContent = $("#_" + id);
    if (helpContent[0]) {
      helpContent.toggle();
    } else {
      $(this).parent().parent().after("<tr><td colspan='2'><div id='_" + id +"'></div></td></tr>");
      helpContent.load("_help.html #" + id);
    }
  });
});

jQuery#after()を使ってヘルプコンテンツを表示するための要素を挿入して、その要素に対してjQuery#load()を使って別HTML(_help.html)を読み込む。で、一度挿入された後は、jQuery#toggle()を使って表示・非表示を切り替えるだけ。

jQuery#after()でコンテンツを挿入するための位置を決めないとならないけど、テーブルの位置関係を暗黙の前提条件にして、parent().parent()という風に決め打ち。この辺りはもうちょっと汎用的にしたいけど。

挿入されるヘルプコンテンツは別に文字だけでなく、画像や任意のブロック要素でOK。一番外側の要素にIDを振っておけばよい。

前提条件

  • フォーム用のテーブルが、項目名を1列目、入力フォームを2列目においた2列のテーブルになっている。
  • ヘルプ用のspanのIDと、ヘルプ用HTML側のIDを対応づけておく。

CSSで、helpクラス(.help)に対して、cursor:pointer;を定義したり、背景画像としてヘルプ用のアイコンを表示する(background: url("help.png") no-repeat;)ようにしておくと、よりそれっぽくなると思う。

jQuery#after()を呼んでる行を工夫すると、下の行への挿入だけでなく、ポップアップとかにも応用できそう。

大したことではないけど、思ったよりもすっきりとやりたいことができた。

*1:ヘルプコンテンツはひとつのHTMLにまとめることにした。ファイルが増えるのも管理が大変なので。
このHTML自体を直接見ることはないけど、段落(p)よりは定義リスト(dl)で書いておいた方がよいとは思う。