FreeStyleWikiにpermalinkを入れるよう改造してみた

FSWikiはページ内の見出し単位で編集が可能なのですが、はてなダイアリーのような見出し単位での個別表示がありません。そこでそれをできるようにしようと思いました。

まず、FSWikiはplugin構成になっているのでpluginでできないか調べました。
どうやら個別ページ表示のほうはpluginでできます。ページを作るプラグインは、coreプラグインのEditPage.pmが参考になります。

一方、ページのほうにpermalinkページへのリンクを埋める処理ですが、こちらはフックは無いようなので、見出し個別編集へのリンクなどを埋める処理をしているlib/Wiki/HTMLParser.pmに埋め込むことにしました。

とりあえず、インラインでのpermalinkページへのリンク埋め込みを追加。

InterWikiのようにWikiNameへの対応。。。とかして無いけど投稿

以下は最新版より古い内容です。

permalinkページ表示&個別ページへのリンク埋め込みplugin

FSWikiのpluginは、pluginディレクトリにplugin名のディレクトリを作り、Install.pmを所定の書式で書けばよい構造になっています。Install.pmのinstallメソッドで、各コールバックを登録する構造になっています。コールバックが行われるポイントは、ページ内に埋め込むinlineプラグイン、メニュー、ページ表示、HTML生成時のフックなどいろいろあります。

ページを表示するコールバックはadd_handlerで、そこに登録したモジュールのdo_actionメソッドが呼び出されます。その戻り値にHTMLを出せば、ページ化してくれます。

permalinkページへのリンクを埋め込むプラグインは、inlineプラグインとして登録します。こちらはadd_inline_pluginで登録し、inlineメソッドが呼び出されます。

plugin/permalink/Install.pm

############################################################
#
# 見出しごとに個別ページにするplugin
#
############################################################
package plugin::permalink::Install;
use strict;
sub install {
	my $wiki = shift;
	
	$wiki->add_handler("PERMALINK","plugin::permalink::PermaLink");
	$wiki->add_inline_plugin("plink","plugin::permalink::PermaLink","HTML");
}

1;

plugin/permalink/PermaLink.pm

###############################################################################
#
# <p>有効化することで見出し部分をページ化できます。</p>
# <p>インラインで見出し個別ページへのリンクを張ることができます。</p>
# <pre>
# {{plink ページ名, 見出し番号}}
# </pre>
#
###############################################################################
package plugin::permalink::PermaLink;
use strict;


#==============================================================================
# コンストラクタ
#==============================================================================
sub new {
	my $class = shift;
	my $self = {};
	return bless $self,$class;
}

#==============================================================================
# アクションの実行
#==============================================================================
sub do_action {
	my $self = shift;
	my $wiki = shift;
	my $cgi = $wiki->get_CGI;
	
	my $page = $cgi->param("page");
	my $artno = $cgi->param("artno");
	
	my $pagename = Util::url_encode($page);
	my $scriptname = $wiki->config('script_name');
	
	my $pagecontent = $wiki->get_page($page);
	my $content = &_read_by_part($pagecontent, $artno);
	my $buf = $wiki->process_wiki($content);
	
	my $subtitle = &_get_subtitle($content);
	if ($subtitle) {
		$wiki->set_title($page . "#" . $artno .": " . $subtitle);
	} else {
		$wiki->set_title($page . "#" . $artno);
	}
	
	my $prevno = $artno - 1;
	my $nextno = $artno + 1;
	my $prevname = &_get_subtitle_at($pagecontent, $prevno);
	my $nextname = &_get_subtitle_at($pagecontent, $nextno);
	
	my $prevlink = "";
	if ($prevname) {
		$prevlink = "<a href=\"$scriptname?action=PERMALINK&amp;page=$pagename&amp;artno=$prevno\">$prevname</a>" . Util::escapeHTML(" << ");
	}
	my $nextlink = "";
	if ($nextname) {
		$nextlink = Util::escapeHTML(" >> ") . "<a href=\"$scriptname?action=PERMALINK&amp;page=$pagename&amp;artno=$nextno\">$nextname</a>";
	}
	my $pagelink = "<a href='$scriptname?page=$pagename'>$page</a>";
	my $navi = "<div class=\"comment\"><p>[ " . $prevlink	. $pagelink . $nextlink . " ]</p></div>";
	
	$buf = $navi . $buf . $navi;
	return $buf;
}

#==============================================================================
# インライン処理
#==============================================================================
sub inline {
	my $self = shift;
	my $wiki = shift;
	my $page = Util::trim(shift);
	my $artno = Util::trim(shift);
	
	my $pagename = Util::url_encode($page);
	my $scriptname = $wiki->config('script_name');
	
	my $content = &_read_by_part($wiki->get_page($page), $artno);
	my $subtitle = &_get_subtitle($content);
	if (!$subtitle) {
		my $subtitle = $artno;
	}
	
	my $permalink = "<a href=\"$scriptname?action=PERMALINK&amp;page=$pagename&amp;artno=$artno\">$page: $subtitle</a>";
	
	return $permalink;
}


#==============================================================================
# パート編集の場合の編集部分の取り出し copy from read_by_part in core/EditPage.pm
#==============================================================================
sub _read_by_part {
	my $page	= shift;
	my $num	 = shift;
	my $count = 0;
	my $buf	 = "";
	my $level = 0;
	my $flag	= 0;
	foreach my $line (split(/\n/,$page)){
		if($line=~/^(!{1,3})/){
			if($flag==1 && $level<=length($1)){
				last;
			}
			if($count==$num){
				$flag = 1;
				$level = length($1);
			}
			$count++;
		}
		if($flag==1){
			$buf .= $line."\n";
		}
	}
	return $buf;
}

#==============================================================================
# 見出し切り出し
#==============================================================================
sub _get_subtitle {
	my $content = shift;
	if ($content =~ /^!+(.*)/) {
		return Util::escapeHTML(Util::trim($1));
	}
	return "";
}

#==============================================================================
# 特定見出し切り出し
#==============================================================================
sub _get_subtitle_at {
	my $pagecontent = shift;
	my $artno = shift;
	my $content = &_read_by_part($pagecontent, $artno);
	return &_get_subtitle($content);
}

1;

permalinkリンクの埋め込みの修正

FSWikiはフックできる部分が多く、大抵はプラグインでフックにコールバックを登録すればよいのですが、ここはフックがなかったので、直接埋め込みました。

場所は、lib/Wiki/HTMLParser.pmの180行目くらいの個別編集リンク生成の直後に入れています。このため、個別編集モードをONにしないと、permalinkは表示されませんが。

                  if ($self->{wiki}->is_installed("permalink")) {
                    my $page = $wiki->get_CGI()->param("page");
                    my $full = $page;
                    my $path = $self->{wiki}->config('script_name');
                    if(index($page,":")!=-1){
                      ($path,$page) = split(/:/,$page);
                      $path = $self->{wiki}->config('script_name')."/$path";
                    }
                    my $pagename = &Util::url_encode($page);
                    my $artno = $self->{partedit}->{$full}; # 「編集」の残りデータを再利用
                    my $permalink = " [<a class=\"partedit\" href=\"$path?action=PERMALINK&amp;page=$pagename&amp;artno=$artno\">Permalink</a>]";
                    $part_edit .= $permalink;
                  }

怪しかった部分を完全に見出し編集とあわせることで、きちんと対応するようになった。