JavaScript を使うとテーマに動きを持たせる様々な演出効果を追加できます。カスタム Javascript ファイルを追加するのに、多くの Drupal 開発者は jQuery が便利だと考えています。jQuery は軽量の JavaScript ライブラリで、Drupal にはデフォルトで組み込まれています。jQuery にはすべての共通の DOM、イベント、エフェクト、Ajax の機能が網羅されています。
Drupal 7 には jQuery 1.4.4 と jQuery UI 1.8.7、Drupal 6.0 から 6.2 には jQuery 1.2.3、そして Drupal 6.3 には jQuery 1.2.6 へのアップデートが同梱されています。モジュールの開発にあたってどうしても最新バージョンの jQuery が必要な場合は、jQuery update モジュールを使用してください。JavaScript が Drupal を介してページに追加されるとき、jQuery も自動的にそのページ追加されます。
jQuery についてさらに詳しい情報は jQuery API 、 Documentation をご覧ください。
テーマに JavaScript を追加する方法は2つあります。
テーマの .info ファイルに記述する方法で、スクリプトタグによって JavaScript を追加します。たとえば、Drupal サイトのすべてのページに foo.js というスクリプトを適用するには、テーマの .info ファイルに次のように記述します。
scripts[] = foo.js
テーマの .info ファイルに記述されたスクリプトは、ページ生成の過程においてテーマが処理されるタイミング(コア / ライブラリのスクリプト、そして各モジュールのスクリプトが追加された後)で追加されます。この順番をおさえておくことは重要です。というのはモジュールの JavaScript がページ内の機能を提供したあとで、テーマの JavaScript にその機会を与えられるということになるからです。
Drupal 6 では、テーマの中に「 script.js 」という名前でスクリプトを作成すれば、それはデフォルトのスクリプトファイルとして、特に .info ファイルで指定しなくても自動的にすべてのページに適用されます。Drupal 7 ではこういったものはなく、すべて .info ファイルに指定する必要があります。
templete.php ファイルで drupal_add_js() を使うことによってスクリプトを追加することもできます(もしくは、Drupal 7 ではdrupal_add_library() が使えます)。たとえば、テーマのルートディレクトリに置いた foo.js というスクリプトを追加したいとします。
Drupal 6 の場合:
<?php function example_preprocess_page(&$variables) { drupal_add_js(drupal_get_path('theme', 'example'). '/foo.js', 'theme'); // ここで追加する場合は、scripts 変数を再構築する必要があります。 $variables['scripts'] = drupal_get_js(); } ?>
Drupal 7 の場合:
<?php function example_preprocess_html(&$variables) { $options = array( 'group' => JS_THEME, ); drupal_add_js(drupal_get_path('theme', 'example'). '/foo.js', $options); } ?>
Drupal 7 では変数 $scripts は再構築の必要はありません。$scripts は次の工程、 template_preprocess_html で生成されます。
Drupal 7 ではライブラリの管理が取り入れられました。ライブラリとは、JavaScript、CSS、そして依存ライブラリの集合です。たとえば、Drupal 7 は jQuery UI を取り込みます。jQuery UI は内部で相互依存関係にあるライブラリの集合です。ui.autocomplete が取り込まれたとき、同時に依存関係にある ui.core と ui.position が必要になるわけですが、Drupal ライブラリはこういった依存関係の管理を担ってくれます。ui.autocomplete をそれが必要とするCSS、JS、依存ライブラリとともに追加するには、次のように記述します。:
<?php drupal_add_library('system', 'ui.autocomplete'); ?>
このたった1つのコマンドで、jquery.ui.autocomplete.js とjquery.ui.autocomplete.css、そしてそれが依存する jquery.ui.position.js、jquery.ui.widget.js、 jquery.ui.core.js、 jquery.ui.core.css、jquery.ui.theme.css を取り込みます。これについて詳しくは drupal_add_library see the API documentation をご覧ください。
スクリプトのコードをクロージャに収めることはベストプラクティスです。クロージャは変数のスコープを制限するのに役立つ単なる関数で、これによって誤ってグローバル変数を上書きしてしまうのを防ぎます。
// 新たな関数を定義します。 (function () { // ここで定義した変数はグローバルスコープには影響しません。 var window = "Whoops, at least I only broke my code."; console.log(window); // 次の括弧は今定義した関数をここで実行させます。 }()); // クロージャの中のコードは他には影響しません。 console.log(window);
クロージャを使うことの利点はもうひとつあります。この関数のパラメータに jQuery を渡して、それを「 $ 」にマッピングした場合、jQuery.noConflict() がコールされているかどうかを気にすることなく、$() といったショートカットの記述が出来るのです。
// パラメータを「 $ 」として受け取るように関数を定義します。 (function ($) { // jQuery はショートカット「 $ 」で記述できます。 console.log($.browser); // ここで引数に jQuery を渡します。 }(jQuery));
Drupal 7 では、ほかのJS ライブラリも使えるようにするため、jQuery.noConflict() をコールします。このため jQuery() といった書き方をするか、クロージャを使った記述をするようにします。
Drupal はページ上の要素に対する JavaScript の機能を単一のメカニズムとして提供するため、「ビヘイビア」というシステムを使います。ビヘイビアによって機能を1つに集約することの利点は、最初にページがロードされ、その後 AHAH/AJAX 等によって内容が変化しても、一貫性が保てることです。Drupal 7 においては、ビヘイビアは2つの関数を持ちます。1つは要素がページに追加されたとき、もうひとつは要素が削除されたときにコールされます。
ビヘイビアは Drupal.behaviors のプロパティとして定義することで登録されます。Drupal はそれぞれのビヘイビアをコールする際、第1引数として DOM 要素を渡します( Drupal 7 では第2引数として設定オブジェクトが渡されます)。効率化のため、ビヘイビアの関数では次の2つのことを念頭においてください。
簡単な例を見て見ましょう。例えば <a href="https://example.com">Example</a> を、 <a href="https://example.com">Example (Secure!)</a> といったように、ページ内のすべての https のリンクにそれがセキュアであることを示すテキストを表示したいとします。この場合、もし処理が2回行われてしまうと、「 Example (Secure!) (Secure!) 」のようになってしまうので、処理が重複しないようにすることが重要です。
Drupal 6 ではこのようにします。:
// クロージャを使って jQuery を「 $ 」にマップさせます。 (function ($) { // Drupal.behaviors のプロパティとして関数を登録します。 Drupal.behaviors.myModuleSecureLink = function (context) { // 処理がすんだことを示すクラスがまだ付いていないセキュアリンクを探す。 $('a[href^="https://"]:not(.secureLink-processed)', context) // 見つかったら処理済のクラスを追加します。 .addClass('secureLink-processed') // セキュアリンクであることを示すテキストを挿入します。 .append(' (Secure!)'); }; // ビヘイビアにさらに関数を追加したい場合はここに記述します。 Drupal.behaviors.myModuleMagic = function(context) {}; }(jQuery));
Drupal 7 では、ページに新たに要素が追加された際には新たに適用され、要素が無くなったときの動作も指定できるようにするため、記述のしかたが少し違います。
// クロージャを使って jQuery を「 $ 」にマップさせます。 (function ($) { // Drupal.behaviors のプロパティとして関数を登録します。 Drupal.behaviors.myModuleSecureLink = { attach: function (context, settings) { // 処理がすんだことを示すクラスがまだ付いていないセキュアリンクを探す。 $('a[href^="https://"]', context) // 要素の重複処理を避けます。 .once('secureLink') // セキュアリンクであることを示すテキストを挿入します。 .append(' (Secure!)'); } } // ビヘイビアにさらに関数を追加したい場合はここに記述します。 Drupal.behaviors.myModuleMagic = { attach: function (context, settings) { }, detach: function (context, settings) { } }; }(jQuery));
Drupal は通常のテーマのしくみと同様に、JavaScript にもテーマメカニズムを提供します。これにより JavaScript で生成されたマークアップをテーマでカスタマイズ出来るようになります。
モジュールはマークアップ生成のためのテーマ関数を提供することができます。たとえば次のコードは "powered by Drupal" アイコンを表示する powered というテーマ関数です。:
Drupal.theme.prototype.powered = function(color, height, width) { return '<img src="/misc/powered-'+ color +'-'+ height +'x'+ width +'.png" />'; }
モジュールがマークアップを挿入する場合はこのようになります。:
$('.footer').append(Drupal.theme('powered', 'black', 135, 42));
これで footer クラスを持つ要素内に次のようなマークアップが挿入されます。:
<img src="http://drupal.org/misc/powered-black-135x42.png" />
テーマがマークアップを変更したい場合は、テーマ関数を置き換えることが出来ます。次のコードはテーマが自身で使用するテーマ関数の例です。
Drupal.theme.powered = function(color, height, width) { return '<div class="powered-'+ color +'-'+ height +'x'+ width '"></div>'; }
モジュールのテーマ関数は「 Drupal.theme.prototype.powered 」ですが、テーマ内では「 Drupal.theme.powered 」のように記述します。テーマによるこのテーマ関数を JavaScript が読み込んだ場合、先ほどのコード
$('.footer').append(Drupal.theme('powered', 'black', 135, 42));
これは次のように表示されます。
<div class="powered-black-135x42"></div>
JavaScript のテーマ関数の戻り値は完全に自由です。単なる文字列だけでなくオブジェクトや配列、jQuery エレメントといった複雑なデータも返すことが出来ます。
Drupal における JavaScript や jQuery についてさらに詳しい情報は、デベロッパーガイドの JavaScript section をご覧ください。また、JavaScript や jQuery についてのアドバイスを受けるには、はコミュニティーである Groups.Drupal.org に参加してください。: http://groups.drupal.org/javascript