ここからはサンプルアプリの解説に入ります。初めに、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ファイルを読み込んでいます。
また、下記のように検索キーワード入力用の入力ボックスや、検索結果を埋め込む<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>
次に、コントローラー「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();
下記で、いくつかポイントとなる個所について説明していきます。
1.6.0 rc0になって、クラス定義の仕方が、次のようになりました。
youtube.LiveSearchController = Class.create({ ……(略)…… });
継承する場合は、次のように記述できます。
youtube.LiveSearchController = Class.create(親クラス, { ……(略)…… });
このように記述すると、constructor、superclass、subclassesというプロパティがクラスに設定されるようになったそうです。
また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クラスを使ってタイマーを設定しています。
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.