2017-01-24

tobijibu

DokuWikiでpjaxを使う

Webページで画面遷移する時に、ページの一部だけが切り替わってコンテンツが表示されることがあります。そういったコンテンツの表示方法はいくつか方法があるのですが、その中でも人気がある方法として、pjaxという方法があります。ajaxの技術を使ってページの一部分だけの取得して、取得した部分だけを書き換えて表示するといった方法です。

そこで、DokuWikiでもpjaxを利用しようと思い、jquery.pjax.jsを導入してみたのですが正常に動きませんでした。DokuWikiでのpjaxの情報を探していたところ、下記の記事を見つけました。

http://lampe2e.blogspot.jp/2016/08/speeding-up-dokuwiki.html

記事に書かれた内容を見つつ実装し、なんとか無事にpjaxを使えるようになったので対応内容を説明します。

説明にはDokuWikiのdokuwikiテンプレート(標準テンプレート)を利用して説明します。他のテンプレートでも設定しやすいように出来るだけ簡単(?)に説明します。
また、DokuWikiのドキュメントルートは/var/www/html/squareknotとして、その中のファイル、ディレクトリで説明します。

大まかな手順は以下になります。

  1. Jokuwiki Pluginを入れる
  2. jquery.pjax.jsを読み込む
  3. 共通箇所(ヘッダー、フッター等)にpjax判定を入れる
  4. pjax読み込み対象のコンテンツをdivで囲む

1. Jokuwiki Pluginインストール

Jokuwiki Pluginをインストールします。このプラグインはjsで生成したプラグインを読み込むことが出来るようになります。

DokuWikiの管理画面からインストールしてください。

2. Starter Templateダウンロード

このテンプレート内に含まれているファイルを使います。ここからStarter Templateプラグインをダウンロードして、zipファイルを解凍します。

※プラグインのインストールではなく、ダウンロードしてください。

解凍フォルダ内にあるjquery.pjax.js、 util.js./lib/tpl/dokuwiki/に設置します。

パス末尾のディレクトリ名:dokuwikiはテンプレート名なので、変更するテンプレートに合わせて読み替えてください。

3. script.jsのfade.jsをコメントアウト

Jokuwikiをインストールすると、./lib/plugins/jokuwikiというディレクトリが生成されます。この中にscript.jsというファイルがあります。このファイルはDokuWikiを開いた時に、自動で実行されるjsファイルです。

script.jsの末尾にfade.jsが呼ばれているのですが、fade.jsは存在せず、jsエラーが出てしまいます。作者オリジナルのスクリプトなのかもしれません。

fade.jsはこのファイル以外のどこからも呼ばれていないのでコメントアウトしてしまいましょう。

jokuwiki.register('pjaxTitle', function(jw) {
    try {
        document.title=jw.title;
    } catch (e) {
    }
});

/* ------------ add a widget -------- */
/*
* jokuwiki.register('slideshow',function (jw) {
*            var i = new fadeSlideShow(jw);
* }, 'res/fader.js');
*/
/* ------ consol.log hack ---------- */
if (!window.console) console = {log: function() {}};

4. ファイル修正

ここからが本番です。少し多いように思えますが、一つずつ確認しながら進めれば難しくありません。主に./lib/tpl/dokuwiki/main.phpを修正します。

※行数は2017年1月現在のDokuWiki標準テンプレートの行数です。今後のアップデートで変わる可能性があります。

まず、<!DOCTYPE html>の上(元ソース:ll.15-16間)にpjax判定を挿入します。pjaxでは各ページ共通の情報を取得しないことで、通信データ量を減らします。pjaxでない場合はヘッダーも取得したいので、pjaxかどうかを判定し、pjaxでない場合のみhtmlヘッダーを表示させます。

$hasSidebar = page_findnearest($conf['sidebar']);
$showSidebar = $hasSidebar && ($ACT=='show');
?>
<?php
/**
 * pjaxアクセスかどうかの判別をします。
 * pjaxでは各ページ共通となる情報を読込こまないことで通信データ量を減らします。
 * pjaxかどうかを判定し、pjaxでない場合のみhtmlヘッダーを表示させます。
 */
if ('true'!=$_SERVER['HTTP_X_PJAX']):
?>
<!DOCTYPE html>
<html lang="<?php echo $conf['lang'] ?>" dir="<?php echo $lang['direction'] ?>" class="no-js">

次に、pjaxの対象範囲をdivで囲みます。<div class="wrapper group">の上(元ソース:ll.31-32間)にpjaxの対象範囲div開始タグを挿入します。

"ページ毎に内容が変化する部分"を囲む必要があるので、基本的にヘッダー、フッター以外のコンテンツを全て含めることになると思います。

追加したdiv開始タグの下(元ソース:ll.31-32間)にif文の閉じタグを挿入します。この閉じタグは<!DOCTYPE html>の上に追加したif文の閉じタグです。

    echo ($showSidebar) ? 'showSidebar' : ''; ?> <?php echo ($hasSidebar) ? 'hasSidebar' : ''; ?>">

    <?php
    /**
     * pjaxの対象範囲をdivで囲みます。
     * ページ毎に内容が変化する部分を囲む必要があるので、
     * 基本的にヘッダー、フッター以外のコンテンツを全て含めることになると思います。
     */
    ?>
    <div id="pjax_container">
<?php
/**
 * pjax判定の終了
 */
?>
<?php endif; ?>
    <?php include('tpl_header.php') ?>

続いて、Jokuwikiの処理を追加します。場所は<?php include('tpl_header.php') ?>の下(元ソース:ll.32-33間)に挿入します。JokuWikiの機能を使い、タイトルを更新する処理を設定します。

<?php include('tpl_header.php') ?>
<?php
/**
 * jokuWiki Pluginの機能を使い、タイトルを更新する処理を設定します。
 */
?>
<div id='pjaxTitle'
     data-jw='{ "jokuwiki" : "pjaxTitle", "data" : { "id" : "pjaxTitle", "title" : "<?php
        $pjaxTitle=htmlentities(tpl_pagetitle($ID, true) . ' [' . strip_tags($conf['title']). ']');
        echo $pjaxTitle;
      ?>"}}'
     class='pjaxTitle'></div>

<div class="wrapper group">

次にDokuWikiの後処理(元ソース:l.106)を</div><!-- /wrapper -->の下(元ソース:ll.101-102間)に移動します。

その下(元ソース:ll.102-103間)に再度、pjax判定処理を挿入します。こちらはpjaxかどうかを判定し、pjaxでない場合のみhtmlフッターを表示させます。

このif文の中で、<div id="pjax_container">の閉じタグを挿入します。このタグまでの範囲がpjaxで毎度取得するコンテンツ領域です。

        </div>
    </div><!-- /wrapper -->

    <div class="no"><?php tpl_indexerWebBug() /* provide DokuWiki housekeeping, required in all templates */ ?></div>
<?php if ('true'!==$_SERVER['HTTP_X_PJAX']) : ?>
    <?php
    /**
     * pjax対象範囲divの閉じタグです
     */
    ?>
    </div>
    <?php include('tpl_footer.php') ?>
    </div></div><!-- /site -->

次に</div></div><!-- /site -->の下(元ソース:ll.106-107間)に冒頭でコピーしてきたjquery.pjax.jsutil.jsを読み込みます。

<?php include('tpl_footer.php') ?>
</div></div><!-- /site -->
<script src="<?php print DOKU_TPL . 'jquery.pjax.js'; ?>" defer></script>
<script src="<?php print DOKU_TPL . 'util.js'; ?>" defer></script>
<div id="screen__mode" class="no"></div><?php /* helper to detect CSS media query in script.js */ ?>

最後にpjax判定のif文閉じタグを挿入します。(元ソース:l.110)

</body>
</html>
<?php endif;

4.5 util.jsの変更

DokuWiki標準テンプレートでは修正不要ですが、テンプレートによっては変更が必要です。

register_pagetools内のセレクタを確認し、テンプレートに合ったセレクタを指定しましょう。また、ページ読み込み時ののフェードインエフェクトを変更したい場合もこのファイルから変更することができます。

5. pjax確認

お疲れ様です。これで一通りpjax処理対応ができました。ここまでできたらブラウザで確認してみましょう。

ブラウザのdeveloperツールを開き「Network」タブを開きます。リンクをクリックした際に、Headersタブ内の「Request Headers」にX-PJAX:trueX-PJAX-Container:#pjax_containerが入っていることを確認します。併せて、"Response"タブを開いて、pjaxで再読込する箇所のhtmlが表示されていることを確認します。どちらも正常に表示されていればpjaxが実装できています。

一つ一つソースを追っていくと、大した処理ではないですし、難しくないのですが、テンプレートの内容が違うと整合性が取りづらいと思います。

まずは標準テンプレートでpjaxの処理を実装して、DokuWiki内でpjaxをする場合の処理を掴んでから、他のテンプレートで試すとやりやすいかもしれません。

ちなみに、サンプルで提供されているテンプレートの上部に、「Content-Security-Policy」の設定がありますが、今回は入れませんでした。

理由はテンプレートの修正だけではなく、いくつかのファイルの修正も必要になるからです。

dockuwikiにはscriptタグやstyleタグが動的にインラインで生成されている箇所があり、そのまま利用するとContent-Security-Policy違反でエラーが発生してしまいます。そのため、今回の対応では導入しませんでした。

次回以降に導入方法を解説したいと思います。

今回説明で利用したソースはこちらにあります。

参考にしたサイト

DokuWikiでのpjax対応方法が記載されています。(英語ブログ)
http://nerdyjs.com/script/834861