つゆだくJavaScript・スタイルシ

ート

 
 
メールを管理人に送信
メールアドレス:
コメント*:
*書いた内容は公開されません

メニュー

トップページ
JavaScriptトップページ
SQLiteトップページ
ライブラリー
個人的サンプル
AJAXのおすすめ書籍
ご意見ご要望
スポンサードリンク

Spry framework for Ajax - SpryData

SpryDataとは

SpryDataとは、Ajaxを行うためのユーティリティーでもありますが、他のライブラリーとは違いHTMLにわずかな修正を加えるだけで、動的にページを表示する機能まで有しています。さらにXMLデータをXPathで指定することで煩わしいDOMプログラムが軽減できるのが大きな魅力です。

詳しくはダウンロードしたzipファイルを解凍して articles/data_set_overview/index.html を読まれるのがよいと思います

SpryDataを使う前準備

必要なのは2つのファイルです。もちろんインストールは済ませておく必要があります。

<script type="text/javascript" src="your install path/xpath.js"></script>
<script type="text/javascript" src="your install path/SpryData.js"></script>

ネームスペースの指定

<html xml:lang="ja" xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">

*xpath.js は http://sourceforge.net/projects/goog-ajaxslt/ のようだ。

XML(RSS)の内容を表示する

Yahoo!のhttp://my.yahoo.co.jp/promo_jp/rss_reader/4.html にあるRSSを表示させたいと思います。毎回yahooのサイトにリクエストを投げるのも意味がないので、wgetを使ってデイリーで自分のサーバに取ってきたものを使います。実物→RSS

wget -q -O quote.xml http://biz.yahoo.co.jp/column/company/ead/rss/index.xml

XMLデータの表示 spry:region

1. XMLの取得

new Spry.Data.XMLDataSetで、RSSファイル(他のサイトのXMLの場合はクロスドメイン対応が必要) とXPath で取り出したい要素を指定。もちろん非同期(Ajax)です。

2. Dynamic Regionの作成

spry:region="DataSet名"属性をつけると、その要素の内側はデータセットと結びつきます。この領域のことをDynamic Regionといいます。(Spry動的領域かな?)

3. データの表示

Dynamic Regionの中で、{エレメント名}と書くことで、フレームワークが表示してくれます。アトリビュートの場合は、{@アトリビュート名}です。

4. Dynamic Regionを隠す

データ表示までの間にDynamic Regionが一瞬ブラウザ上に表示されてしまいますので、これを防ぐ為の手段が用意されています。

両方ともvisibility: hidden;で画面に表示されないようにするという意味でやっていることは同じですが、"SpryHiddenRegion" の方がより多くのブラウザで正しく動作しますので、ここではこちらを使います。

<style>
.SpryHiddenRegion {
    visibility: hidden;
}
</style>
<script type="text/javascript">
var dsRss = new Spry.Data.XMLDataSet('rss/quote.xml', '/rss');
var dsItem = new Spry.Data.XMLDataSet('rss/quote.xml', '/rss/channel/item');
</script>
...
...
<div spry:region="dsRss" class="SpryHiddenRegion">
RSSのバージョンは{@version}です。
</div>
<div spry:region="dsItem" class="SpryHiddenRegion">
<table border="1">
<thead>
  <tr>
    <th>#</th>
    <th>タイトル</th>
    <th>説明</th>
    <th>更新日</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td>{dsItem::ds_RowID}</td>
    <td><a href="{dsItem::link}">{dsItem::title}</a></td>
    <td>{dsItem::description}</td>
    <td>{pubDate}</td> <-- dsItem:: は省略できる -->
  </tr>
</tbody>
</table>
</div>

View sample HTML

RSSと見比べると分かりやすいと思います。

ループ spry:repeat, spry:repeatchildren

上のサンプルを下のように書き換えるだけで、/rss/channel/item要素の数だけ勝手にループして表示してくれます。

ループさせるにはspry:repeat もしくは spry:repeatchildren属性を指定します。2つの属性の違いはどの要素でループさせるかの違いだけで、spry:repeatは属性をつけたタグでループ、spry:repeatchildrenは属性をつけたタグの子供でループします。

<tbody>
  <tr spry:repeat="dsItem">
    <td>{ds_RowID}</td>
    <td><a href="{link}">{title}</a></td>
    <td>{description}</td>
    <td>{pubDate}</td>
  </tr>
</tbody>


<tbody spry:repeatchildren="dsItem">
  <tr>
    <td>{ds_RowID}</td>
    <td><a href="{link}">{title}</a></td>
    <td>{description}</td>
    <td>{pubDate}</td>
  </tr>
</tbody>

View sample HTML (サンプルページはspry:repeatchildrenを使っていますが結果は同じになります)

条件分岐 spry:if, spry:test

spry:ifspry:testの2つの属性は機能的に同じですが、spry:ifはループ属性の内側に記述、spry:testはループ属性と同じ場所に記述します。

条件はJavaScriptで記述します。(SpryData.jsの中ではeval で式を実行していました)。

下のサンプルでは、'{title}'.match(/為末大/)が正の場合(titleに'為末大'が含まれる場合)に表示処理が行われます。

<tbody spry:repeatchildren="dsItem">
  <tr spry:if="'{title}'.match(/為末大/)">
    <td>{ds_RowID}</td>
    <td style="width: 200px;"><a href="{link}">{title}</a></td>
    <td style="width: 500px;">{description}</td>
    <td>{pubDate}</td>
  </tr>
</tbody>


<tbody spry:repeatchildren="dsItem" spry:test="'{title}'.match(/為末大/)">
  <tr>
    <td>{ds_RowID}</td>
    <td style="width: 200px;"><a href="{link}">{title}</a></td>
    <td style="width: 500px;">{description}</td>
    <td>{pubDate}</td>
  </tr>
</tbody>

View sample HTML

条件分岐 spry:choose

spry:choose属性は、if/else のようなことができます。まず、spry:chooseの子エレメントでいくつかのspry:when属性を記述します。これはspry:ifと同じでJavaScriptで条件文を記述し、正の場合表示処理が行われます。次に、 ひとつのspry:defaultを記述することで、spry:whenがすべて負だった場合の記述をします。

下のサンプルでは、3で割ったあまりで、if, elsif, else のようなことをやって1行ずつ色を変えています。

<tbody spry:repeatchildren="dsItem" spry:choose>
  <tr spry:when="{ds_RowID} % 3 == 0" style="color: blue;">
    <td>{ds_RowID}</td>
    <td style="width: 200px;"><a href="{link}">{title}</a></td>
    <td style="width: 500px;">{description}</td>
    <td>{pubDate}</td>
  </tr>
  <tr spry:when="{ds_RowID} % 3 == 1" style="color: green;">
    <td>{ds_RowID}</td>
    <td style="width: 200px;"><a href="{link}">{title}</a></td>
    <td style="width: 500px;">{description}</td>
    <td>{pubDate}</td>
  </tr>
  <tr spry:default style="color: red;">
    <td>{ds_RowID}</td>
    <td style="width: 200px;"><a href="{link}">{title}</a></td>
    <td style="width: 500px;">{description}</td>
    <td>{pubDate}</td>
  </tr>
</tbody>

View sample HTML

状態のハンドリング spry:state

spry:state属性は、spry:state="loading" (XMLデータ読み込み中), spry:state="error" (XMLデータの読み込み失敗), spry:state="ready" (表示準備完了) の3つが記述可能です。

下のサンプルでは、10秒間まってからレスポンスを返すCGI/cgi-bin/sleep.cgiを使ってわざと遅延させloadingの表示を分かりやすくします。また、/cgi-bin/sleep.cgiはXMLではなくテキストデータを返しますので、XMLの読み込みに失敗します。よって、errorが最終的には表示されます。

<script type="text/javascript">
var dsRss = new Spry.Data.XMLDataSet('/cgi-bin/sleep.cgi', '/rss/channel/item');
</script>
...
...
<div spry:region="dsItem">
<div spry:state="loading">現在読み込み中です。</div>
<div spry:state="error">読み込みに失敗しました。</div>
<div spry:state="ready">
foo
</div>
</div>

"現在読み込み中です" がしばらく表示されてから、"読み込みに失敗しました" が表示されるのが分かると思います。

View sample HTML

詳細表示 spry:detailregion

spry:detailregion属性は、JavaScriptをちょっと書くだけで自動的に現在行を再描画してくれます。その名の通り詳細表示の時につかうと便利な機能です。

下のサンプルでは、RSSリーダーのようにタイトルをクリックすると本分が表示されます。

<div spry:region="dsItem" style="font-size: 70%; width: 300px; float: left;">
<ul spry:repeatchildren="dsItem">
  <li>
    <a href="javascript:;" onclick="dsItem.setCurrentRow({ds_RowID})">{title}</a>
  </li>
</ul>
</div>

<div spry:detailregion="dsItem">
<fieldset>
  <legend>{title}</legend>
  <div>{description}</div>
  <div style="text-align: right;"><a href="{link}">続きを読む</a></div>
</fieldset>
</div>

View sample HTML

スタイルの指定 spry:hover, spry:select, spry:selectgroup

spry:hover属性は、スタイルシートの":hover" 定義と同じです。マウスが上にのったときに適応するクラスを定義できます。spry:select属性は、 クリックした後に適応するクラスを定義できます。また、spry:selectgroup属性を指定することで、spry:selectの適用範囲を指定することが可能になります。

下のサンプルでは、マウスを乗せると.hoverClassが有効になって背景色が変わるのと、クリックすると.selectClassが有効になって文字が太字になりサイズも大きくなります。

あと直接Spryの機能とは関係ありませんが、XPathの指定のところで、position()を使って件数を指定しています。これによってページ送りの機能が実現可能になります。(ページ送りのサンプルはもうちょっと下のほうで)

<script type="text/javascript">
var dsItem1 = new Spry.Data.XMLDataSet('rss/quote.xml', '/rss/channel/item[position() > 0 and position() <= 10]');
var dsItem2 = new Spry.Data.XMLDataSet('rss/quote.xml', '/rss/channel/item[position() > 10 and position() <= 20]');
</script>
<style type="text/css">
.selectClass {
    font-weight: bold; font-size: 120%;
}
.hoverClass {
    background-color: azure;
}
</style>
...
...
<div spry:region="dsItem1" style="font-size: 70%; border: 1px solid green;">
Title1:
<ul spry:repeatchildren="dsItem1">
  <li spry:hover="hoverClass" spry:select="selectClass" spry:selectgroup="group1">{title}</li>
</ul>
</div>

<div spry:region="dsItem2" style="font-size: 70%; border: 1px solid green;">
Title2:
<ul spry:repeatchildren="dsItem2">
  <li spry:hover="hoverClass" spry:select="selectClass" spry:selectgroup="group2">{title}</li>
</ul>
</div>

View sample HTML

ソート

実用的なソートを行うための機能もDataSetには備わっています。コンストラクタでソートを指定することで、最初の表示時のソートを指定することが可能なのと、onclickなどのイベント発生時にsort()メソッドを呼ぶことで、表示後にも動的にソートを行うことが可能です。

書式(コンストラクタ):
{ sortOnLoad: "要素名", sortOrderOnLoad: "[ascending | descending]"}

書式(sortメソッド):
sort('要素名', 'toggle') #toggleは ascending/descending を自動で切り替え

*注意: デフォルトでは文字列でソートを行うので、下のサンプルのように更新日でソートを行う時は、setColumnType('pubDate', 'date')を呼んで日付でソートできるようにしておかなければならない。型は'date', 'number', 'string' の3種類。

var dsItem = new Spry.Data.XMLDataSet('rss/quote.xml', '/rss/channel/item', 
    { sortOnLoad: "title", sortOrderOnLoad: "ascending"} );
dsItem.setColumnType('pubDate', 'date');
...
...
<thead>
  <tr>
    <th onclick="dsItem.sort('ds_RowID', 'toggle');">#</th>
    <th onclick="dsItem.sort('title', 'toggle')">タイトル</th>
    <th onclick="dsItem.sort('description', 'toggle')">説明</th>
    <th onclick="dsItem.sort('pubDate', 'toggle')">更新日</th>
  </tr>
</thead>

tableの見出しの部分をクリックするとソートします

View sample HTML

ページング

静的なRSSを読み込むのに、ページ送りをやってみます。色々な方法があるとは思いますが、ここでは、positionを用いて行っています。

var size=3;  // 表示件数
var start=0; // 表示開始行数
var dsItem1 = new Spry.Data.XMLDataSet('rss/quote.xml', '/rss/channel/item[position() > ' +start+ ' and position() <= ' +(start+size)+ ']');

function next(){
    start+=size;
    dsItem1.setXPath('/rss/channel/item[position() < ' +start+ ' and position() >= ' +(start+size)+ ']');
    if (dsItem1.getData().length==0){
        prev();
    }
};
function prev(){
    start-=size;
    if(start<0) start=0;
    dsItem1.setXPath('/rss/channel/item[position() < ' +start+ ' and position() >= ' +(start+size)+ ']');
};

<input type="button" name="Prev" value="Prev" onclick="prev()"/>
<input type="button" name="Next" value="Next" onclick="next()"/>

View sample HTML

ページングを行うのに再度XMLを読み込むことはない(キャッシュされている)ので素早い反応になっていると思います。

複数のXML(RSS)の内容を表示する

動的に読み込むXMLを変更します。さらに下のサンプルではXMLではなく、配列をDataSetに自分でセットする方法を使っています。

<script type="text/javascript">
/* XMLではなくて配列を使う ds_RowIDを連番でふっておくのがミソ */
var afile = [
    {ds_RowID: 0, file: "quote.xml", title: "Yahoo!ファイナンス - 有名人のお金の使い方"},
    {ds_RowID: 1, file: "insurance.xml", title: "Yahoo!保険 - 保険通信"},
    {ds_RowID: 2, file: "mobile.xml", title: "Yahoo!モバイル - お知らせ"}
];

/* XMLDataSetではなくDataSetを使う */
var dsRSS = new Spry.Data.DataSet();
dsRSS.data = afile;
dsRSS.dataHash = afile;
dsRSS.loadData();

/* dsRSSの内容によって読み込むファイルを変える */
var dsItem = new Spry.Data.XMLDataSet('rss/{dsRSS::file}', '/rss/channel/item');
</script>
...
...
<div spry:region="dsRSS">
RSS:
<select spry:repeatchildren="dsRSS" onchange="dsRSS.setCurrentRow(this.value)">
  <option value="{ds_RowID}">{title}</option>
</select>
</div>

<div spry:region="dsItem" style="font-size: 70%; width: 300px; float: left;">
<ul spry:repeatchildren="dsItem">
  <li>
    <a href="javascript:;" onclick="dsItem.setCurrentRow({ds_RowID})">{title}</a>
  </li>
</ul>
</div>

<div spry:detailregion="dsItem">
<fieldset>
  <legend>{title}</legend>
  <div>{description}</div>
  <div style="text-align: right;"><a href="{link}">続きを読む</a></div>
</fieldset>
</div>

View sample HTML

Spryの力で、あとデザインさえ整えればRRSリーダーっぽいというところまでいきました。