次に、モデルクラスを見てみましょう。
youtube.LiveSearch = Class.create({ /** * コンストラクタ */ initialize: function(keyword) { this.previousKeyword = keyword; }, /** * 前回のキーワードと異なればJSONPで検索 */ search: function(keyword, callback) { if (this.previousKeyword != keyword) { var url = 'http://gdata.youtube.com/feeds/videos?' + 'vq=#{keyword}&alt=json-in-script&'+ 'callback=#{callback}&max-results=9'; url = url.interpolate( {keyword: encodeURIComponent(keyword), callback: callback}); jsonp = new JSONscriptRequest(url); jsonp.buildScriptTag(); jsonp.addScriptTag(); this.previousKeyword = keyword } }, });
このクラスはメンバ変数として、前回のキーワード「previousKeyword」を持っています。
searchメソッドで、今回のキーワードと前回のキーワードが異なったら、GData YouTube APIの動画検索用URLを作り、JSONscriptRequestクラスを使って、JSONPの処理を行っています。
URLを作るために、String#interpolate()を使用していますが、これについてはビューのところで解説します。
最後にビューのコードを見てみます。
youtube.LiveSearchView = { /** * 検索結果一覧の更新 */ update: function(videos) { var entries = videos.feed.entry; var html = ""; if (! entries) { html = '<span class="not_found">' + '検索結果が見つかりませんでした。</span>'; }else { entries.each( function(entry, index) { var template = '<div id="#{id}" class="video">' + ' <a href="javascript:void(0)">' + ' <img class="thumbnail" src="#{thumbnail}"' + ' width="#{width}" height="#{height}"' + ' alt="#{title}" />' + ' </a>' + ' <a href="javascript:void(0)">' + ' <div class="title">#{title}</div>' + ' </a>' + '</div>'; html += template.interpolate({ id:entry.id.$t.match(/\/([^\/]+)$/)[1], thumbnail:entry.media$group.media$thumbnail[0].url, width:entry.media$group.media$thumbnail[0].width, height:entry.media$group.media$thumbnail[0].height, title:entry.title.$t }); if (index % 3 == 2) { html += '<br class="clear" />'; } }); } $('search_results').update(html); }, /** * クリックされた動画をLightWindowで表示 */ show: function(video) { var so = new SWFObject("http://www.youtube.com/v/"+video.id, "video", "425", "353", "7", "#FFFFFF"); so.write("player"); myLightWindow.activateWindow({ href: document.location + '#player', width: 425, height: 353, title: video.getElementsByClassName('title')[0].innerHTML }); } };
Googleから受け取るJSONの形式は大まかに次のようになります。
{feed: {entry: [ {id: ……(略)……, media$group: {media$thumbnail: [ {height: ……(略)……, url: ……(略)……, width: ……(略)……}, {height: ……(略)……} ], ……(略)……}, ……(略)……}, {……(略)……} ] }, ……(略)……, }
1.6.0 rc0では、1.5.0にあったTemplateクラスの機能と同等の機能が、Stringクラスのinterpolate()メソッドとしても利用できるようになりました。
update()メソッドでは、受け取ったJSON内の動画配列それぞれに対して、テンプレートを使って実際に表示されるHTMLを生成し、最終的にそれらでsearch_resultsの内容を更新しています。
show()メソッドでは、SWFObjectを使って受け取ったvideo要素からswfファイル(YouTubeで主に使われているFlash動画の実行ファイル)を<div id='player'>の中に埋め込んだ後、LightWindowの「Inline Content」方式で、その内容を描画させています(参考)。
再度、今回使用したAjaxデザインパターンをまとめます。
パターン名 | 説明 |
---|---|
Live Searchパターン | ユーザーが検索条件を入力している間も随時検索結果を表示 |
Submission Throttlingパターン | イベントが発生するたびにサーバに情報を送信するのではなく、一定の間隔を置いて送信することでサーバの負荷や回線の負荷を軽減 |
Popupパターン | 既存のコンテンツに一時的に前面にレイヤーを重ねて、レイアウトを変更せずに追加情報などを表示したり、ちょっとした作業領域を提供できる |
これ以外に、前回紹介した、「On-Demand Javascriptパターン」「Periodic Refreshパターン」「Page Rearrengementパターン」も使用されています。
パターンを組み合わせていけば、今回のようなサンプルアプリもかみ砕いて理解できますし、外部APIやライブラリをフル活用すればだいぶ短く書くことができると感じていただけたでしょうか?
また、MVCに役割を分担すれば可読性を保ちながら、どんどん機能拡張ができることを、イメージしていただけたら幸いです。
次回も、また新しいAjaxデザインパターンやAjaxライブラリを使い楽しいサンプルをご紹介できればと思っています。
今回のソースはこちらからダウンロードできます(こちらのアプリケーションは2007年10月に、当時のYou TubeのWeb APIを使って作成したものです。その後、You Tube側の仕様の変更などによりアプリケーションが動作しなくなる場合もありますが、あらかじめご了承ください。また、サンプルのライセンスはGPL 2となります)。
プロフィール:志田 裕樹(しだ ゆうき)
株式会社アークウェブ取締役。Webシステムのシステムエンジニアとして開発に従事している。
Ajax、Ruby on Rails等を使用したWeb 2.0的システムの開発実績を持つ。
オープンソースのECサイト用CMS、Zen Cartの日本語コミュニティでコミッターとして活動している。
Copyright © ITmedia, Inc. All Rights Reserved.