Hikiプラグインの作り方 第四回その二 管理画面

上の「ヘッダーとフッター」だけで一回分の内容がありますが、前回(id:s2_it:20101003)の最後にした予告がまだ成就されていないので、「第四回」のまま続きます。


上のプラグインはページの上と下にナビゲーションを表示しています。これを、上だけ、下だけに表示したくなる、というのは充分考えられることです。
その都度プラグインの中身を書き換えてもいいのですが、管理画面から、ブラウザーを使って管理できると便利です。


管理画面では、幾つかのばらばらな要素を組み合わせて、一つのプラグインを管理しています。

です。

サイドバーのメニュー

管理画面の「基本、パスワード、表示設定……」と並んでいるサイドバーに、「グローバルナビ」という文字を追加しましょう。

# global-nav.rbの続き
add_conf_proc('global-nav', global_nav_label) do
end
# ja/global-nav.rbの続き
def global_nav_label
  'グローバルナビ'
end

サイドバーに「グローバルナビ」というメニューが追加された筈です。
add_conf_procメソッド、さっきのadd_body_enter_procと名前が似ていますね、同種の物です。サイドバーのメニュー表示に割り込んでプラグイン用のメニューを表示します。
add_conf_procメソッドに渡される引数のうち、最初の物はリンクのURIに使われます。二つ目は、サイドバーに表示されるメニューです。言語ファイルにメソッドを作っています。
今は更に、空っぽのブロックを渡していますが、このブロックが管理画面の表示に使われます。

プラグインの管理画面

add_conf_procメソッドに渡したブロックの戻り値が、管理画面になります。
正確に言うと、form要素とsubmit要素は事前に用意されているので、それ以外を用意することになります。テキストや、そのformの中に置くinput、textareaといった要素です。


ここでは、ページ上の目次について表示「する」「しない」、下について「する」「しない」を選べるようにすればいいでしょう。

# global-nav.rbの続き
add_conf_proc('global-nav', global_nav_label) do
  global_nav_conf
end
# ja/global-nav.rbの続き
def global_nav_conf
  <<CONF
<p>上部のナビを
<input type="radio" name="top-nav" value="display">表示する
<input type="radio" name="top-nav" value="hide">表示しない
</p>

<p>下部のナビを
<input type="radio" name="bottom-nav" value="display">表示する
<input type="radio" name="bottom-nav" value="hide">表示しない
</p>
CONF
end

サイドバーの「グローバルナビ」をたどって管理画面に移ってみてください。
ページタイトルやOKボタンは既に用意されています。
今回は表示するHTMLの全体をja/global-nav.rbに書きましたが、勿論、add_conf_procのブロック内で大枠を作って、要所だけで日本語ファイルのメソッドを呼び出しても結構です。僕はそっちの方が好みです。

今は、ラジオボタンをクリックしてOKボタンを押しても、何も起きません。選んだ設定を保存する必要があります。

プラグイン設定の保存

管理画面を表示する時にadd_conf_procで割り込みを掛けたのですが、実は、管理画面のフォームの内容をPOSTする時に割り込むにも、add_conf_procを使います。
POSTされたのかされていないのか、という区別は@modeという変数で判定します。@modeに'saveconf'という文字列が入っていたら、POSTされた(設定をセーブした)ことを意味しています。

# global-nav.rbの続き
add_conf_proc('global-nav', global_nav_label) do
  if @mode == 'saveconf'
    # 設定保存の手続き
  end
  
  global_nav_conf
end

全てのプラグインの設定は、@confという変数(ハッシュのようにアクセスします)に入っています。逆に、新しい設定を保存しようと思ったら、@confに入れればいいわけです。
全てのプラグイン設定が入っているので、他のプラグインと同じ設定名(ハッシュのキー)を使わないよう、キーの最初にプラグインの名前を付けるのが慣例になっています。

# global-nav.rbの続き
add_conf_proc('global-nav', global_nav_label) do
  if @mode == 'saveconf'
    @conf['global-nav.top-nav'] = @cgi.params['top-nav'][0]
    @conf['global-nav.bottom-nav'] = @cgi.params['bottom-nav'][0]
  end
  
  global_nav_conf
end

@cgiRuby標準添付のcgiライブラリーにある、CGIクラスのオブジェクトです。
@cgi.params['top-nav']とかは、配列になっているので注意してください。というか僕は、上のプラグインを作っている時、最初は[0]を付け忘れました。


これで設定保存もできるようになって、global-nav管理画面が完成したわけですが、今現在、どういう設定なのか分かった方が心理的には何と無くいいですね。

# ja/global-nav.rbの続き
def global_nav_conf
  top_nav_display = @conf['global-nav.top-nav']
  bottom_nav_display = @conf['global-nav.bottom-nav']
  
  <<CONF
<p>上部のナビを
<input type="radio" name="top-nav" value="display"
       #{'checked="checked"' if top_nav_display == 'display'}>表示する
<input type="radio" name="top-nav" value="hide"
       #{'checked="checked"' if top_nav_display == 'hide'}>表示しない
</p>

<p>下部のナビを
<input type="radio" name="bottom-nav" value="display"
       #{'checked="checked"' if bottom_nav_display == 'display'}>表示する
<input type="radio" name="bottom-nav" value="hide"
       #{'checked="checked"' if bottom_nav_display == 'hide'}>表示しない
</p>
CONF
end

設定の反映

さて、最後に上で保存した設定を、ナビゲーションの表示の時に反映させれば、global-navプラグインの完成です。
もう一度add_body_enter_procに戻りましょう。

# global-nav.rbの続き(置き換え)
add_body_enter_proc do
  if @conf['global-nav.top-nav'] == 'display'
    global_nav()
  elsif @conf['global-nav.top-nav'] == 'hide'
    nil
  else
    raise "Invalid global-nav.top-nav value: #{@conf['global-nav.top-nav']}"
  end
end

add_body_leave_proc do
  if @conf['global-nav.bottom-nav'] == 'display'
    global_nav()
  elsif @conf['global-nav.bottom-nav'] == 'hide'
    nil
  else
    raise "Invalid global-nav.bottom-nav value: #{@conf['global-nav.bottom-nav']}"
  end
end

本当は設定が'display'なら表示、それ以外(else)なら非表示、でいいんですが、設定ファイルが壊れた時なんか、'display'と'hide'以外の値が入っているかも知れないので一応例外を起こしておきます。


ふう。ようやっと完成です。
管理画面を使おうと思うとちょっと大変ですね。その割りにやることは結構決まっているんでフレームワークを用意してくれているといいんだけどなあ。
そこまでいかなくても、add_conf_procのブロックを読み取ってフォーム要素を作ってくれるユーティリティメソッドなんかはあってもいいかも。
とにかくばらばらの三つを有機的に結び付けてくれると楽になるわけです、柔軟性は失われるかも知れないけど。
自分で作れって?