8つのJavaScriptファイルを呼び出すHTML
ここからはサンプルアプリの解説に入ります。初めに、HTMLファイルを見てみましょう。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>YouTube Live Searcher</title>
<script type="text/javascript"
src="javascripts/prototype.js"></script>
<script type="text/javascript"
src="javascripts/jsr_class.js"></script>
<script type="text/javascript"
src="javascripts/scriptaculous.js?load=effects"></script>
<script type="text/javascript"
src="javascripts/lightwindow.js"></script>
<script type="text/javascript"
src="javascripts/swfobject.js"></script>
<script type="text/javascript" src="javascripts/controllers/youtube/live_search_controller.js">
</script>
<script type="text/javascript" src="javascripts/models/youtube/live_search.js"></script>
<script type="text/javascript" src="javascripts/views/youtube/live_search_view.js"></script>
<link rel="stylesheet" type="text/css"
href="stylesheets/application.css"></link>
<link rel="stylesheet" type="text/css"
href="stylesheets/lightwindow.css"></link>
</head>
<body>
キーワード: <input type='text' name='keyword' id='keyword' />
<div id='search_results'></div>
<div id='player'></div>
</body>
</html>
このHTMLファイルは、<script>タグで次の8つのJavaScriptファイルを読み込んでいます。
- prototype.js
今回使用するAjaxライブラリ。次期安定版となる予定の1.6.0 rc0を使用。prototype.jsの新機能を試してみたい方にお勧めだが、安定版ではないことに十分注意すること - jsr_class.js
汎用のJSONP用ライブラリ。「XML.com: JSON and the Dynamic Script Tag: Easy, XML-less Web Services for JavaScript」からダウンロードできる - lightwindow.js
LightWindow用のJavaScriptファイル - scriptaculous.js
Ajaxライブラリscript.aculo.usのJavaScriptファイル。LightWindowがscript.aculo.usに依存しているため。今回はLightWindowに付属されていた1.7.1 beta2をそのまま使用 - swfobject.js
JavaScriptを使ってHTMLにswfを埋め込むライブラリ(参考:「deconcept > SWFObject: Javascript Flash Player detection and embed script」 - controllers/youtube/live_search_controller.js
コントローラー - models/youtube/live_search.js
モデル - views/youtube/live_search_view.js
ビュー
また、下記のように検索キーワード入力用の入力ボックスや、検索結果を埋め込む<div>要素、LightWindow内のコンテンツを埋め込む<div>要素などが含まれています。
<form id='youtube_live_search_form'>
キーワード: <input type='text' name='keyword' id='keyword' />
</form>
<div id='search_results'></div>
<div id='player'></div>
コントローラー:prototype.js 1.6.0 rc0の新機能を使用
次に、コントローラー「live_search_controller.js」のコードを見てみましょう。
//名前空間オブジェクト
var youtube = new Object();
youtube.LiveSearchController = Class.create({
/**
* コンストラクタ
* A:ページがロードされた
* A-1:0.5秒置きの実行タイマーを設定
*/
initialize: function() {
document.observe("contentloaded", function() {
youtube.controller.liveSearch =
new youtube.LiveSearch($F('keyword'));
youtube.controller.pe =
new PeriodicalExecuter(
youtube.controller.checkPeriodically, 0.5);
});
},
/**
* B:0.5秒が経過した
* B-1:検索結果の取得を依頼
*/
checkPeriodically: function() {
youtube.controller.liveSearch.search($F('keyword'), 'youtube.controller.reflesh');
},
/**
* C:YouTubeから検索結果が取得された
* C-1:検索結果の描画を依頼
* C-2:描画された各動画のonClickイベントへのハンドラの登録
*/
reflesh: function(videos) {
youtube.LiveSearchView.update(videos);
$('search_results').getElementsByClassName('video').each(
function(element, index) {
element.observe("click", youtube.controller.select);
});
},
/**
* D:検索結果のうち1つが選択された
* D-1:クリックされた動画の詳細情報の描画を依頼
*/
select: function() {
var video;
if (this.className != 'video') {
video = this.parentNode.parentNode;
}else{
video = this;
}
youtube.LiveSearchView.show(video);
}
});
youtube.controller = new youtube.LiveSearchController();
下記で、いくつかポイントとなる個所について説明していきます。
prototype.js 1.6.0 rc0はクラス定義が変わった
1.6.0 rc0になって、クラス定義の仕方が、次のようになりました。
youtube.LiveSearchController = Class.create({
……(略)……
});
継承する場合は、次のように記述できます。
youtube.LiveSearchController = Class.create(親クラス, {
……(略)……
});
このように記述すると、constructor、superclass、subclassesというプロパティがクラスに設定されるようになったそうです。
DOM要素が読み込まれた段階で実行を開始可能になった
また1.6.0 rc0では、DOM要素がロードされると同時にハンドラ関数を実行するcontentloadedイベントが利用できるようになりました。
document.observe("contentloaded", function() {
youtube.controller.liveSearch =
new youtube.LiveSearch($F('keyword'));
youtube.controller.pe =
new PeriodicalExecuter(
youtube.controller.checkPeriodically, 0.5);
});
ここでは、DOMがロードされたら、まずモデルクラスを生成しています。
$F()は、フォーム要素のvalue値を簡単に参照するための、prototype.jsが用意したユーティリティ関数です(参考)。その後、prorotype.jsのPeriodicalExecuterクラスを使ってタイマーを設定しています。
0.5秒置きにモデル側で検索判定をさせる
checkPeriodically()メソッドでは、モデルに現在のキーワードを与えて0.5秒前のキーワードと違っているなら、callback関数として「youtube.controller.reflesh」を指定して、YouTubeに対する検索を行わせます。
youtube.controller.liveSearch.search($F('keyword'), 'youtube.controller.reflesh');
ビューが追加した要素にコントローラーがハンドラを設定
reflesh()メソッドでは、YouTubeからの検索結果を受け取り、動画情報の部分をビューに渡して描画をさせます。
youtube.LiveSearchView.update(videos);
描画される動画個々のHTMLの構造は次のようになります。
<div id="XXXXXXXX" class="video">
<a href="#">
<img class="thumbnail" width="130" height="97" alt="XXXXX"
src="xxx.jpg"/>
</a>
<a href="#">
<div class="title">XXXXX</div>
</a>
</div>
このように追加された<div class="video">の要素を、getElementsByClassNameメソッドによって取得し、eachメソッドで、それぞれの要素に対して、onclickイベントのハンドラをセットしています。
$('search_results').getElementsByClassName('video').each(
function(element, index) {
element.observe("click", youtube.controller.select);
});
このように、動的に生成された要素に対してハンドラをセットする必要がある場合は、ビューの処理が終わった後に、コントローラー側で行うようにすると、ハンドラに関する記述がコントローラーに集まるようになってよいと思います。
選択された動画の描画
reflesh()メソッド内で、<div class="video">のonclickイベントが発生すると、select()メソッドが呼び出されるようにしました。このとき、クリックされる部分のマークアップは下記のようになっています。
<div id="動画ID" class="video">
<a href="#">
<img class="thumbnail" ……(略)…… />
</a>
<a href="#">
<div class="title"> ……(略)…… </div>
</a>
</div>
クリックされた要素はthisオブジェクトから取得できます。この場合のthisオブジェクトは、<div class="video">か、その子要素である、<img class="thumbnail">か<div class="title">のいずれかになります。子要素の方がthisオブジェクトとして渡された場合は、次のように親要素までたどって、それをビューに渡して描画をさせます。
video = this.parentNode.parentNode;
さらに次ページでは、モデルとビュー部分のソースコードを解説します。
Copyright © ITmedia, Inc. All Rights Reserved.