目次
JavaScript
DokuWikiは、ユーザーエクスペリエンス(機能や操作性)を向上させるため、JavaScriptを利用しています。すべてのJavaScriptのファイルはHTTPリクエストを最小限に抑えるために、ひとつのディスパッチャを通してクライアントへ送られます。この方法はstylesheetsと同様で、まとめられたファイルはキャッシュ・圧縮(minify)されます。
このページではDokuWikiコアやプラグイン、テンプレートでどのようにJavaScriptがロードされるかについて概要を説明します。また、DokuWiki内でのJavaScriptをコードする際の、イベント処理やコーディングスタイルについても説明します。
JavaScript のロード
すべてのJavaScriptはlib/exe/js.php
で集められ、クライアントへ送信されます。このスクリプトはすべてのファイルを繋ぎ、空白を除去して圧縮し(圧縮する 設定の場合)、できたファイルをキャッシュします。また、ヘッダ情報によってブラウザにキャッシュするように指示するので、もし新しいJavaScriptを書いた場合にはその都度、ブラウザのキャッシュを更新する必要があります。(Shift+F5やShift+CTRL+Rなど)
DokuWikiはつぎの場所からJavaScriptを集めます。
- 自動生成されたJavaScript (language strings, config settings, toolbar)
- lib/scripts/*.js 1)
- lib/plugins/*/script.js
- lib/tpl/<現在のテンプレート名>/script.js
- conf/userscript.js
このように、あなたのJavaScriptをDokuWikiで使うには、個々のtemplatesやpluginsディレクトリにscript.jsという名前で保存するか、conf/userscript.js内に挿入します。
また、lib/tpl/<現在のテンプレート名>/main.phpのHTMLコードの<head></head>内に直接挿入することもできます。
Include Syntax
DokuWikiのJavaScriptディスパッチャは、特別なJavaScriptコメントを使って他のスクリプトファイルをincludeすることができます。これはテンプレートやプラグインなどのように、ひとつのJavaScript(script.js)しかパースされない場合には便利です。
includeされたファイルはキャッシュロジックでチェックされません。もとのファイルをtouchしてキャッシュを更新させる必要があります。
Includeは循環参照を避けることができません。
Includeパスは半角英数、アンダースコア、スラッシュ、ピリオドのみ使用してください。
include
/* DOKUWIKI:include somefile.js */
この文法は指定されたJavaScriptファイルをコメント部分にincludeします。ファイル名はこのinclude文のあるファイルパスからの相対パスです。スラッシュで始まる場合はファイルシステム上の絶対パスとなります。
include_once
/* DOKUWIKI:include_once common_library.js */
この文法は指定されたJavaScriptファイルをコメント部分にincludeします。ファイル名はこのinclude文のあるファイルパスからの相対パスです。スラッシュで始まる場合はファイルシステム上の絶対パスとなります。
すでにinclude_onceによって同じ名前のファイルが読み込まれている場合はロードされません。この名前はすべてのスクリプトファイル(すべてのプラグインも含めて)で共有されるので、名前の付け方には注意して意味のあるファイル名にしなければいけません。
この文法は、同一のJavaScriptライブラリを別々のプラグインで使う場合に役に立つでしょう。同じ名前(basename)を使ってinclude_once
でincludeすることで、あなたのプラグインが複数インストールされていても一回だけロードされるからです。
コーディングガイドライン
DokuWiki内で使うJavaScriptを書くときには、2,3のルールに従わなければいけません。JavaScriptの性質上、あなたのスクリプトだけなく、すべてのDokuWikiスクリプトが壊れるかもしれません。
1. 文法が正しいか確かめる
上でも述べたように、DokuWikiはデフォルトのcompress設定によってJavaScriptを小さくまとめます。文法エラーが入り込まずにまとめるために、圧縮しない場合よりも厳しくチェックしなければいけません。
オンラインサービスのJSLintなどを使ってください。
2. 控えめなJavaScriptにする
DokuWikiの新しい機能を追加する場合、すべての人々がJavaScriptを使っていると思ってはいけません。万が一JavaScriptが利用できない環境でも通常のページ表示ができるようにする必要があります。
DokuWikiには定義済みの関数や変数が用意されています。Event Handling
3. 不適切に混ぜない
HTMLに直接JavaScriptを埋め込むやり方は古くからあります。しかし、JavaScriptと(X)HTMLは混ぜるべきではありません。実際、DokuWikiでは混ぜられないケースが多くあります。ここでは「不適切に混ぜるやりかた」の例を挙げます。2)
<body onload="refreshPage()"> <p>some html</p> <script language="JavaScript"> doSomethingHere(); </script> <p>more <a href="http://example.com" onclick="doSomethingElse()">HTML</a></p> </body>
これは哲学的に問題があるのではなく、JavaScriptが動きません。上の例では、DokuWikiと<body>
タグどちらもがページのonload
に別々の関数でアサインしようとしています。ブラウザはこの衝突を正しく処理できないし、結果が予測不能です。
厳密に言えば、HTML内にJavaScriptを埋め込むことは可能ですが、DokuWikiで動いているJavaScriptとコンフリクトしないことをあなたが十分に知っている必要があります。DokuWikiの実装に関する知識を必要としますし、DokuWikiの実装自体が変わる場合もあるので、不用意にJavaScriptを埋め込むのはやめた方が良いでしょう。
4. IDを使用する
DOMオブジェクトを変更するために、JavaScriptはオブジェクトを認識できなければいけません。もっとも簡単な方法はHTMLタグをIDで指定することです。このIDは正確に正しいDOMオブジェクトを参照できるように、ページ内のすべてのIDの間でユニークな値でなければなりません。
HTMLを生成するときに(たとえばテンプレートやプラグインから)、それはあとからJavaScriptがアクセス出来るようにしておくべきです。また、すでに存在するIDとかぶらないように確かめなければいけません。特に、自動的に指定される見出しのヘッダなどとコンフリクトしてはいけません。あなたの生成するオブジェクトのIDを2つのアンダースコア(__
)を使うのが最も簡単な方法です。見出しのIDはいつもpagenamesのはずなので、2つのアンダースコアを持たないことが保証されているからです。
5. インラインスクリプト
JavaScriptとXHTMLを混ぜないように、というルールはもう述べました。しかし、どうしてもインラインJavaScriptを使わなければいけない場合、次のように括ってください。
<script type="text/javascript"><!--//--><![CDATA[//><!-- ... //--><!]]></script>
この方法は最も互換性高くスクリプトが動作するやり方です。これに関する情報は、 XHTML 1.0: Script and Style elements仕様や、CDATA section interface定義を参照してください。
もし、インラインJavaScriptを<head>セクションに追加しなければならない場合は、action_pluginを書いてTPL_METAHEADER_OUTPUTイベントを捕捉してください。
DokuWiki JavaScript ライブラリ
DokuWikiはPrototype,Dojo,JQueryといった大きなライブラリを使用していません。その代わり、DokuWiki用のJavaScriptコードを書くために便利なクラスや関数を集めた小さなライブラリを持っています。
イベント処理
3. 不適切に混ぜないで述べたように、イベントハンドラーはHTMLコードに混ぜてはいけません。イベントハンドラーはDocument Object Model (DOM)がロードされた時に指定されるべきです。DOMはHTMLをツリー構造で表現したもので、JavaScriptスクリプトで参照できます。あなたのJavaScriptはどのオブジェクトがどの関数と結びついているか、また、どの関数がどのオブジェクトに結びついているかを把握できていなければなりません。
どのブラウザでも動くように関数をDOMオブジェクトに結びつけるために、addEvent()
関数が用意されています。これはDOMオブジェクト、イベント名('click'等)、コールバック関数(ハンドラー)を引数にとります。この関数は、同一のDOMオブジェクトのイベントに、複数のプラグインが登録することもサポートします。
なお、AddEvent()
はInternet Explorerでのイベントにおけるプロパティやメソッドを変えます。そのため、target
プロパティを使えますし、preventDefault()
やstopPropagation()
メソッドを呼び出すことができます。
不幸なことに、script.js
のJavaScriptはHTMLのロード終了前、つまりDOMツリーが出来ていない段階でロードされてしまいます。JavaScriptが必要とするオブジェクトが存在しないのです。(script.js
ロード時にDOMを参照しないJavaScriptなら、実行することはできます。)
この問題を解決するため、DokuWikiはaddInitEvent()
関数を用意しています。この関数は、DOMが準備できた直後に実行するコールバック関数を登録します。
以上の関数の例 (summary_enforcement tip)
function enforceSummary() { /*...*/ } function installSummaryEnforcement() { var summary_input = document.getElementById('edit__summary'); if(summary_input !== null) { /*...*/ addEvent(summary_input, 'change', enforceSummary); addEvent(summary_input, 'keyup', enforceSummary); } } addInitEvent(installSummaryEnforcement);
この例では、summary input fieldのためにenforceSummary()
関数をonchange
とonkeyup
イベントハンドラーに結びつける必要があります。installSummaryEnforcement()
がこれを受け持っています。
addInitEvent()
の呼び出しでinstallSummaryEnforcement()
関数がDOMロード直後に実行されるように登録されます。
installSummaryEnforcement()
自体がどのように動作しているか見てみましょう。まず1番目に、この関数はIDによるDOMオブジェクトを取得します(他のやり方もありますが)。この場合、ページの編集時にsummaryフィールドだけが表示されてからこのオブジェクトは存在しないかもしれません。だからこの関数は最初にオブジェクトを参照できるか確かめるテストをしています。もしあればaddEvent()
を呼び出してイベントハンドラーをenforceSummary()
へ結びつけます。
このDokuWikiイベント処理群のオリジナルはDean Edwards (here・here)によって作成されました。
- イベントシステムについてより深く知りたい場合は、ソースを参照してください。
定義済みのグローバル変数
あなたのスクリプト内でも利用できる定義済みJavaScript変数
DOKU_BASE
– DokuWikiルートディレクトリのフルパスDOKU_TPL
– 使用されているTemplateのフルパスLANG
– 言語文字列の配列
SACK (AJAX) Library
DokuWikiはGregory Wild-SmithによるSACK
と呼ばれるAJAXライブラリを持っています。
- 詳しくは Source tw-sack.js
$()
$()関数は、よく使われるDOMのdocument.getElementById()
の代替関数です。DOM関数と同様、これは引数にIDをとり、要素オブジェクトを返します。DOM関数と異なるのは、1つ以上のidを渡してオブジェクトの配列を得られることです。
その他の関数
DokuWikiは他にもいろいろなメソッドを用意しています。特に、あなたの開発を助けてくれるのは次のようなものでしょう:isset, getElementsByClass, findPosX, findPosY, jsEscape, prependChild.
- これらに関して詳しくチェックしたい場合は: