contentsx.inc.php

Top > Plugin > contentsx.inc.php
First Edition. 05/16/2006
Last Modified. 01/12/2007

ページの目次を作成する #contents のプラグイン化、拡張

Table of Contents

説明

ページの目次を作成するプラグインです。

#contents プラグインは実際のところプラグインではなく、本体組み込みの機能であり、拡張がしにくいのでプラグイン化し、機能拡張しました。

本体組み込み #contents との違い

  • 設置行以降の見出しのみリストする機能
  • MenuBar に設置しても有効
  • 見出しレベル指定機能
  • 表示件数指定機能
  • 正規表現による見出しのフィルタ機能
  • 正規表現による見出しの除外フィルタ機能
  • キャッシュ機能
  • リンク形態指定機能(リンクしないなど)
  • 固定アンカ必須

旧 contents2_1からの変更点

  • 固定アンカ必須
    • pukiwiki.ini.php で $fixed_heading_anchor = 1;
  • 相対アンカのバグ
    • プラグインという形で完全対応は不可能なことがわかっている。固定アンカ必須にすることで避けた
  • display 削除
    • inline 却下
  • depth=2-5 -> depth=2:5
    • depth=-1:-5 (最後から、最後から5番目まで) が可能に
    • depth=-1+5 なども可能
    • depth=(1,3,5:9) のように複数指定も可能
  • number -> num
    • number=10 (10個) ではなく num=1:10 (depth と同じ書式)
  • キャッシュ機能
  • キャッシュリセット用のアクション型
  • link オプション追加
  • 出力HTML

変更なし

  • page
  • fromhere
  • hierarchy
  • compact
  • except
  • filter

使い方

設定

固定アンカ必須です。pukiwiki.ini.php で $fixed_heading_anchor = 1; と設定します。 PukiWiki Plus! の場合デフォルトで有効です。

固定アンカは編集保存する際に自動作成されます(見出しの横に [#kf58bbaf] のようなものが作成されます)。 今まで設定していなかった場合、全てのページを編集保存しなおす必要があります。

replaceplugin.inc.php を使用して全ページの #contents を #contentsx に変換する処理を行うと編集保存もすることになりアンカーを作成してくれるので一石二鳥かもしれません。

書式

#contentsx(オプション)

option=bool なオプションは共通して、 option, option=true, option=on でそのオプションが有効になり、option=false, option=off で無効になります。

page=ページ名

見出しリストを行うページを指定できる。デフォルトはカレントページ。

fromhere=bool

#contentsx がある行以降の見出しのみをリストする。デフォルトで有効。

備考:page オプションで別ページを指定した場合は強制的に off になります。

hierarchy=bool

階層的表示。デフォルトで有効。

compact=bool

リストのレベルを詰める。デフォルトで有効。気になる場合は使用例参照のこと。

num=数字

表示件数指定。正数は前からN件目、負数は後ろからN件目の意味。

num=1:10 で先頭1件目から10件目までの意味。num=-10:-1 で後ろ10件目から後ろ1件目までの意味。num=2: で先頭2件目から最後までの意味。 num=5+2 で先頭5件目から、そこから2件先まで(5,6,7)の意味。

depth=数字

見出しレベル限定。数字の指定は num と同じ書式。

includeページタイトルはレベル0になる。compact=on,off に関わらず絶対値指定。

except=正規表現

リストしない見出しを正規表現にて指定。

ヒント: ereg で判定を行います。 except=Test|sample → Test または sample を含む見出しを除く。

filter=正規表現

リストする見出しを正規表現で限定する。

ヒント: ereg で判定を行います。

include=bool

#include プラグインで取り込んでいるページとその見出しも扱う。 デフォルトで有効。

cache=on | off

キャッシュの利用。デフォルトで有効。

link=on | off | anchor | page

リンク形態指定。デフォルトは on。

  • on - 柔軟に、現在ページへは link=anchor、page オプションで別ページが指定されていた場合 link=page。
  • anchor - 強制的にアンカーのみ使用。
  • page - 強制的にページ名も含めたリンク。
  • off - リンクしない。

ヒント: link=anchor で include したページに対してもページ内アンカーによるリンクを貼れます。include にはもともと対応していますが、類似のものにも対応できると思います。link=page はついでです。

動作例(仕様)

次のような「とあるページ」があったとします。

**AA
#contentsx
*B
***BBB
**BC
#include(別のページ)
*D

「別のページ」の内容は次のとおりだったとします。

*1
#contentsx
**11

「とあるページ」の #contetnsx が変更されると思ってください。


まず参考に #contents

#contents
  • AA
  • B
    • BBB
    • BC
  • D

#contentsx のデフォルト動作

#contentsx // == #contentsx(include,fromhere,compact,hierarchy)
  • B
    • BBB
    • BC
  • 別のページ
    • 1
      • 11
  • D

#contentsx(include=off,fromhere=off,compact=off,hierarchy=off)
  • AA
  • B
  • BBB
  • BC
  • D

#contentsx(include=off,fromhere=off,compact=off,hierarchy) // 以下 hierarchy 略
  • AA
  • B
    • BBB
    • BC
  • D

#contentsx(include=off,fromhere=off,compact) // compact
  • AA (<-注目)
  • B
    • BBB (<-注目)
    • BC
  • D

完全に #contents と同じものはないが、compact としてはこの挙動が正解だと思っている(#contents の場合は先頭要素だけが compact されている)。


#contentsx(include=off,fromhere,compact=off) // fromhere
  • B
    • BBB
    • BC
  • D

#contentsx(include,fromhere=off,compact=off) // include
  • AA
  • B
    • BBB (表現できない。もう1段下がる)
    • BC
  • 別のページ
    • 1
      • 11
    • D

include がある場合、全体的に1段階下がる。


#contentsx(depth=1:2,compact=false)
  • B
    • BC
  • 1
    • 11
  • D

include が depth=0


#contentsx(depth=1:2) // compact
  • B
    • BC
  • 1
    • 11
  • D

#contentsx(depth=1:2,filter=B)
  • B
    • BC

#contentsx(depth=1:2,except=B)
  • 1
    • 11
  • D

#contentsx(depth=1:2,except=B,num=1:2)
  • 1
    • 11

#contentsx(page=別のページ)
  • 1
    • 11

FAQ

MenuBar に設置する場合?

MenuBar に設置する際は

#contentsx(fromhere=off)

のように記述しておきます*1

#contents を一度に置き換えたい

プラグインの置き換え用プラグインとして replaceplugin.inc.php を作成してありますので利用してみてください。

CSSデザイン

#contentsx は

<table border="0" class="toc"><tbody>
<tr><td class="toctitle">
  <span>Table of Contents</span>
</td></tr>
<tr><td class="toclist">
  <ul class="contentsx">
    <li> ... </li>
    <li> ... </li>
  </ul>
</td></tr>
</tbody></table>

のようなタグを出力します(微妙にMediaWikiの真似)。クラス toc、toctitle、toclist を利用します。

このサイトでは以下のようにしています。 サイトのデザインは各々で違うと思いますので、参考までに。

/* contentsx */
div#body .toc {
	font-size:13px;
	border:2px solid gray;
	background:white;
	margin:0px 0px 0px 10px;
	z-index: 2;
}
div#body .toc .toctitle {
	text-align:center;
	margin:0px 10px 0px 0px;
}
div#body .toc .toctitle span {
	font-weight:bold;
	margin:0px 5px 0px 5px;
}
div#body .toc .toclist ul{
	margin:5px 5px 5px 20px;
}
div#body .toc .toclist ul ul{
	margin-left:15px;
}

Table of Contents の文字を消したい場合は

div#body .toc .toctitle {
        display: none;
}

とでもしてください。

ちなみに #lsx プラグインからの呼び出しの場合 <ul class="contentsx">....</ul> の部分のみが出力されます。toc, toctitle, toclist は #contentsx 単体呼び出し用と考えて使用できます。

キャッシュについて

  • 1ページにつき1キャッシュです。
    • cache/ページ名.toc のような形で保存されます。
  • ページを毎回パースして見出しを見つける処理を短縮するためのキャッシュです。そこの計算量が多すぎなのです。
    • 最終出力HTMLをキャッシュしているわけではありません。
    • 最終出力HTMLをキャッシュしたい場合は ecache.inc.php を使用してください(更新タイミングは contentsx と同じです)
  • ページ参照時に(プラグイン実行時に)キャッシュファイルとdiffファイルのタイムスタンプを比べて、Wikiページのほうが新しければ更新します。
    • Wiki ページではなく diff ファイルのタイムスタンプを見ることによって「タイムスタンプを更新しない」編集でもキャッシュを最新に保つことができます。
  • アクション型(?cmd=contentsx)で管理者ならばキャッシュのリセットができます。

ダウンロード

v2.0 系統版

Sonots PukiWiki Plugin Collection に含まれています。

lsx-vX.XX.zip をダウンロードし、plugin ディレクトリ以下に展開してください。
同時梱包されているその他のプラグインは上述ページ内の「Release Notes」リンクから参照できます。

旧 v1.0 系統版

技術的詳細

固定アンカ必須

include オプション指定時に相対アンカに完全対応できないことがわかっています。

調査

  1. 相対アンカ番号は convert_html が呼ばれた回数を利用して割り振られます。その呼び出された回数は convert_html 関数内で static $contents_id; として外からはアクセスできないように宣言されています。
  2. #contents は実際はプラグインではなく、本体組み込み機能です。convert_html は Wiki ページ全体をパースし、見出し文をストック、相対アンカをその地点における $contents_id を元に作成、見出しを作成、#contents の文字があった部分を後で置換します。
  3. #contents には include オプションはありません。#include される文書の中で $contents_id がいくつになっているかは興味の外です。

問題

  1. プラグインの側から $contents_id を取得する方法が用意されていません。
  2. $contents_id を取得できるように改造したとしても(global にするなど)、#include される文書の中で $contents_id がいくつになっているかは前もって知ることが出来ません(これができないと include オプション時に相対アンカを貼れない)

考えた対策

  1. Wiki 文書をプラグイン側で独自にパースし、convert_html を内部で呼び出すプラグインの数を数え(特に #include の数)、$contents_id に相当する数を取得する。

この対策に対する問題

  1. 全てのプラグインに対応することは不可能、特に新しく作られる自作プラグインに対応できない。

結論

相対アンカの利用は無理。固定アンカを使用するしかない。

関連



*1 MenuBar でプラグインが起動されているとわかる仕組みが PukiWiki にあれば自動で動作を切り替えられるのですが・・・