スクリプトを書く
今回は前回の続きでWikipedia検索のガジェットの実装です。前回はガジェット本体の見た目の部分を作ったので、
SimpleAPIのWikipedia検索を使ってみる
SimpleAPIとWikipediaAPIの説明
Wikipediaを検索するガジェットであるため、
そのため
SimpleAPIとは、
今回はこのサービスをありがたく利用させていただき、
- 注意)
- SimpleAPIのサービスはAPIの説明にあるとおり無保証であり、
予告なく終了する可能性があります。
検索結果を取得する関数を作る
まずは、
具体的な処理内容は検索文字列を受け取って、
関数が返す値はSimpleAPIはレスポンス形式にJSONを選択できるので、
- XMLHttpRequestって何?
Ajaxがどうと話題だった昨今、
XMLHttpRequestを知らないという人はあまりいないのではないかと思いますが、 JavaScriptからHTTPのリクエストを行うための仕組みのことです。なお、 Webブラウザから利用する場合には同ドメイン内のみへリクエストできるという制限がありますが、 ガジェットから利用する場合にはその制限は受けません。 - JSONって何?
JSONとはJavaScript Object Notationの略称で
「JavaScriptの文法を使ったデータ構造表現方法」 です。実際にはJavaScriptそのものではなくサブセットなのですが、 JavaScriptの形をとるデータを返せばJavaScriptで簡単に読み込むことができるようになるのが特徴です。 例えば、
JSONのデータは以下のような形になります。 { "foo": "hogehoge", "bar": { "gaogao": "hauhau" }, "baz": [ 1, 2, 3 ] }
このようなテキストをJavaScriptで受け取って、
var o; eval("o = " + json); // json変数には上記の文字列が入っている
などという形でevalを利用して文字列を評価すると、
スクリプトから o.
foo // "hogehoge" o. baz[1] // 1 という形で簡単に利用できるようになります。
JavaScript以外の言語からJSONを読み書きするためのライブラリはすでに多く実装されているため、
JavaScript以外からも扱いやすくなっています。
実装
ではXMLHttpRequestとJSONの簡単な説明が済んだところで、
なお今回も、
(略)
</style>
<script type="text/javascript">
</script>
<body>
(略)
まず、
function search(keyword) {
}
はじめにXMLHttpRequestクラスを使うのでインスタンスを作ります。
var xhr = new XMLHttpRequest();
次にWikipediaAPIを呼び出すリクエストのための指定を行います。
WikipediaAPIの使い方はhttp://
- APIのURI : http://
wikipedia. simpleapi. net/ api パラメータは、
GETあるいはPOSTで指定します。文字コードは入力は現在UTF-8のみ。出力はUTF-8固定。
- keyword:キーワード。エイリアスとして、
qも指定可能 - output:出力方式
(xml,rss,json,html,javascript,php,tsvを指定可能。デフォルトはxml) - callback:出力形式がJSONP時の名称を指定可能
- lang:現在未実装。現在は日本語
(ja) のみ。 - search:現在未実装につき1のみ。
(0.その特定キーワードのみを取り出す、 1.前方一致、 2.後方一致、 3.前後方一致、 4. FULLTEXT)
引用:SimpleAPI Wikipedia 入力仕様
ベースとなるURIはhttp://
肝心のパラメータはlangとsearchは利用できないので不要として、
ということで、
http://wikipedia.simpleapi.net/api?keyword=[検索文字列]&output=json
にリクエストを投げればよいということになります。
試しにhttp://
[{"language":"ja","id":"3030","url":"http:\/\/wikipedia.simpleapi.net\/ja\/3030\/","title":"Windows","body":"\u300eMicrosoft Windows\u300f\u3(略)
これがレスポンスのJSONです。正しく返ってこなかった場合にはリクエストの文字列を確認するか、
どこにリクエストを投げればよいのかわかったところで、
- 第一引数:HTTPメソッド
(HEAD,GET,POST) - 第二引数:URL
- 第三引数:同期・
非同期かどうかのフラグ (リクエストが完了するまでブロックする)
以上を踏まえてここのコードは以下のようになります。なお今回は非同期処理としないので第三引数はfalseにします。
xhr.open("GET", "http://wikipedia.simpleapi.net/api?keyword="+ keyword +"&output=json", false);
URLのkeywordパラメータに関数の引数のkeyword変数
xhr.open("GET", "http://wikipedia.simpleapi.net/api?keyword="+ encodeURI(keyword) +"&output=json", false);
次にリクエストを実際に送信します。送信にはsendメソッドを使います。sendメソッドは第一引数に送信するデータを取りますが、
xhr.send(null);
リクエストの実行後、
return eval(xhr.responseText);
以上がWikipediaAPIを呼び出す流れになります。まとめると以下のようになります。
function search(keyword) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://wikipedia.simpleapi.net/api?keyword="+ encodeURI(keyword) +"&output=json", false);
xhr.send(null);
return eval(xhr.responseText);
}
エラー時の処理などは今回省略していますが、
動作確認
ところでこれ、
alert(search("Windows Vista")[0].body);
このコードはWindows VistaでWikipediaのページを検索して一件目のページのサマリをalertで表示しています。
何かサマリのようなものが表示されれば、
取得できることを確認したら今書いたalertの行は不要なので削除してください。
これで取得の関数は終わりです。XMLHttpRequestとWikipediaAPIの説明でちょっと長くなってしまいました。
検索結果を表示する部分を作る
次に検索結果を表示する部分を作ります。検索結果を表示する部分の動作に関してはここでは作らず、
Flyoutの説明
検索結果の表示は完成スクリーンショットにある通り、

Flyoutはガジェット本体とは別のHTMLファイルで、
今回のようにガジェット部分だけでは表示しきれないような情報などを表示するのに利用します。
HTMLを書く
それでは、
検索結果はガジェット側から差し込むことにしたいので、

以上を踏まえて、
<title>Wikipedia Search Results</title>
<style type="text/css">
* { margin: 0; padding: 0; }
body { width: 480px; height: 300px; overflow: auto; }
li { margin: 0.5em; }
h1 { background-color: black; color: white; font-size: 1em; font-weight: normal; }
</style>
<body>
<h1>Wikipedia 検索(Powered by SimpleAPI): <span id="resultInfo">-</span></h1>
<ul id="results">
</ul>
</body>
配置や見た目の細かい部分に関しての説明はあまり必要ないと思うので省きますが、
ガジェット側から操作する必要があるため、
一つ目はh1要素下にある、
二つ目はul要素のresultsです。これは検索結果を表示するための要素です。検索結果のヒットごとをひとつのli要素としてul要素に追加して表示することを考え、
今回のFlyoutではスクリプトを使わないため、
Flyoutを表示設定と表示方法
Flyoutの利用方法を知る意味でも、
まず、
先ほど作ったFlyoutの名前はFlyout.
System.Gadget.Flyout.file = "Flyout.html";
そして実際に表示するにはSystem.
System.Gadget.Flyout.show = true;
試しにこの行をファイル指定の後に追加して、
そして別のアプリケーションなどにフォーカスを移すとシュルシュルと消えてゆきます。Flyoutはフォーカスが外れると自動的に非表示となります。
表示できることを確認したら、
なおここで出てきたSystem.
これでFlyoutの準備はできました。あとは検索して結果を反映して、
ボタンを押して検索できるようにする
今度はまたガジェット本体にコードを書いていきます。そもそも、
イベントハンドラをつける
ボタンを押したら検索されるようにするには、
それではイベント発生時に処理を行うために、
onsubmit="doSearch(); return false;"
onsubmitイベントではdoSearch関数を呼んで、
次にfalseを返している理由ですが、
検索文字列入力にidをつけておく
入力された検索文字列をスクリプトから取得できるようにしなければいけません。そのためinput要素にkeywordというidを振っておきます。
<input type="text" id="keyword" style="width: 145px">
検索ボタンを押されたときの処理を書く
ボタンが押され、
doSearch関数で行うことは次のようになります。
- 入力文字列の取得
- 検索
- Flyoutの表示と検索結果更新
(Flyoutが表示されていない場合) - Flyoutの検索結果更新
(Flyoutが表示されている場合)
Flyoutの検索結果更新処理は若干長めで、
この処理のコードは短いですが、
// Flyoutが表示されるタイミングで検索結果を更新します
System.Gadget.Flyout.onShow = function () { updateFlyout(); };
// 検索結果をdoSearchからupdateFlyoutに引き渡すための変数
var searchResult;
// 検索文字列をdoSearchからupdateFlyoutに引き渡すための変数
var keyword;
// 検索ボタンを押したときに呼ばれる関数
function doSearch () {
// 検索文字列を取得してkeyword変数に保持しておく
keyword = document.getElementById("keyword").value;
// 入力された文字列を元にsearch関数を呼んで検索し、
// その結果をsearchResultに保持する
searchResult = search(keyword);
// Flyoutは既に表示されているかどうかを取得します。
if (System.Gadget.Flyout.show) {
// Flyoutは現在表示中なので検索結果を更新します。
updateFlyout();
} else {
// Flyoutは表示されていないので表示を指示します。
// 検索結果の反映は表示されるタイミングで行われます
System.Gadget.Flyout.show = true;
}
}
// Flyoutの検索結果を更新するための関数
function updateFlyout () {
// 変数fDにFlyoutのドキュメントオブジェクトを保持しておく
var fD = System.Gadget.Flyout.document;
// 検索結果を反映するためのul要素をあらかじめつけておいたidで取得する
var results = fD.getElementById('results');
// ulの中身を削除する(既存結果の削除)
results.innerHTML = "";
// 検索結果の件数などを表示するためのspan要素をIDで取得する
var resultInfo = fD.getElementById('resultInfo');
// searchResultがnullかどうか。検索ヒット数が0件ならnullとなる。
if (searchResult == null) {
// ヒット数は0件だったのでその旨を表示して終了する。
resultInfo.innerText = keyword + "は見つかりませんでした。";
return;
} else {
// ヒット数が1件以上合ったので検索文字列とヒット件数を表示する。
resultInfo.innerText = keyword + " (" + searchResult.length + "件)";
}
// 検索結果を見つかった個数分、一つずつul要素に追加する
for (var i = 0; i < searchResult.length; i++) {
// li要素を作る
// li要素の中にリンクとページ内容が入る
var li = fD.createElement('li'); // ヒット一つの結果
// ページ内容
var p = fD.createElement('p');
// 返ってきたページ内容はHTMLが含まれるのでタグはすべて削除する
var summary = searchResult[i].body.replace(/<[^>]+>/g, '');
// 長すぎたら切り詰めて...をつけるようにしておく
if (summary.length > 255) { summary = summary.substring(0, 255) + "..."; }
// 内容をp要素にセットする
p.innerHTML = summary;
// リンク
var a = fD.createElement('a');
// リンク先をセットする
a.href = searchResult[i].url;
// リンク文字列をセットする
a.innerText = searchResult[i].title;
// li要素にリンクとページ内容を追加する
li.appendChild(a);
li.appendChild(p);
// Flyoutの検索結果(ul要素)に1件を追加する
results.appendChild(li);
}
}
それでは重要そうなところを解説します。まず、
System.Gadget.Flyout.onShow = function () { updateFlyout(); };
System.
- 補足)
- System.
Gadget. Flyout. showをtrueにした後、 updateFlyout関数を呼んでも同じように思えるのですが、 そうはいかないのです。なぜなら 「showをtrueにした」 は 「Flyoutが表示された」 とイコールにならず、 Flyoutはシステムに処理が返ったタイミングで表示されるためです。showをtrueにした直後はFlyoutのドキュメントにアクセスできず内容の更新に失敗します。それを回避するために 「表示された」 というイベントで始めて内容の更新をかけるようにしています。
onShowイベントを使う都合上、
var searchResult;
var keyword;
その後doSearch関数は大体コメントの通りです。その次はFlyoutの検索結果を更新するupdateFlyout関数です。関数の頭の一文はFlyoutを操作するために必要な文です。
var fD = System.Gadget.Flyout.document;
前のFlyoutの節でも触れましたが、
そして検索結果の追加周りはほぼDOM操作ですが、
検索した結果返ってくるものはWikipediaAPIのJSONを評価したそのものなので、
[
// 1件目
{
url: "URL",
title: "ページのタイトル",
body: "ページの内容",
/* その他情報 */
},
// 2件目
{
url: "URL",
title: "ページのタイトル",
body: "ページの内容",
/* その他情報 */
},
// ...
// n件目
{
...
}
]
配列なので検索個数はsearchResult.
また結果が一件もない場合にはnullが返ってきます。それを踏まえてupdateFlyout関数内でFlyoutに検索結果を表示するべく要素を組み立てて、
一通りできたので確認
後半大分駆け足感がありましたが、
なお、
次回は、