この章では、Part5で準備したEclipseによる開発環境を前提に、OpenSocial Development Environment(OSDE)を使った、より実践的なOpenSocialアプリを作成する方法を解説している(執筆:五十川匡 ウノウ株式会社)。

本誌の該当ページはp56から。

fig.1

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs
        title="My First Gadget"
        author_email="anonymous@example.org">
    <Require feature="opensocial-0.8" />
    <Require feature="dynamic-height" />
  </ModulePrefs>
  <Content type="html" view="canvas"><![CDATA[
    <script type="text/javascript"
        src="http://localhost:8080/MyFirstGadget/canvas.js"></script>
    <script type="text/javascript">
      gadgets.util.registerOnLoadHandler(init);
    </script>
    <div id="send-gift-form">
      <p id="greeting"></p>
      <form>
        <table>
          <tbody>
            <tr>
              <th>友達を選択</th>
              <td><select id="friends-list">友達リスト</select></td>
            </tr>
            <tr>
              <th>ギフトを選択</th>
              <td><select id="gifts-list">ギフトリスト</select></td>
            </tr>
            <tr>
              <th>&nbsp;</th>
              <td><input type="button" value="贈る"
                  onclick="send_gift();return false;"></td>
            </tr>
          </tbody>
        </table>
      </form>
    </div>
    <p>友達に贈ったギフトリスト</p>
    <div id="sent-gifts"></div>
    <p>友達から贈られたギフトリスト</p>
    <div id="received-gifts"></div>
  ]]></Content>
</Module>

fig.2

/**
 * ギフトリスト
 */
var global_available_gifts = ['ビール', 'ギフト券', '現金'];
/**
 * VIEWERのギフトリスト
 */
var global_viewer_gifts;
/**
 * VIEWERの友達リスト
 */
var global_viewer_friends;

fig.3

/**
 * ビューのロード時に実行されるファンクション
 *
 * @return void
 */
function init() {
    // フォームのギフトリストを更新
    update_gifts_list();

    // VIEWERとVIEWERの友達情報などのリクエストを発行
    load_friends();
}

fig.4

/**
 * フォームのギフトリストを更新
 * 
 * @return void
 */
function update_gifts_list() {
    var arr = new Array();
    for ( var i in global_available_gifts)
        arr.push('<option value="' + i + '">' + global_available_gifts[i]
                + '</option>');
    document.getElementById('gifts-list').innerHTML = arr.join('');
}

fig.5

/**
 * VIEWERとVIEWERの友達情報などのリクエストを発行
 * 
 * @return void
 */
function load_friends() {
    // リクエストを初期化
    var req = opensocial.newDataRequest();

    // VIEWERの情報取得をリクエストに追加
    // レスポンスではキーワード「viewer」で参照される
    req.add(req.newFetchPersonRequest('VIEWER'), 'viewer');

    // VIEWERの識別子
    var viewer = opensocial.newIdSpec( {
        'userId' : 'VIEWER'
    });
    // VIEWERの友達の識別子
    var viewer_friends = opensocial.newIdSpec( {
        'userId' : 'VIEWER',
        'groupId' : 'FRIENDS'
    });
    // リクエストのオプションパラメータ(友達の情報は上限100件で取得)
    var option_params = {};
    option_params[opensocial.DataRequest.PeopleRequestFields.MAX] = 100;

    // VIEWERのギフト情報(キーワード「gifts」で参照される永続データ)取得をリクエストに追加
    // レスポンスではキーワード「viewer_gifts」で参照される
    req.add(req.newFetchPersonAppDataRequest(viewer, 'gifts'), 'viewer_gifts');
    // VIEWERの友達情報取得をリクエストに追加
    // レスポンスではキーワード「viewer_friends」で参照される
    req.add(req.newFetchPeopleRequest(viewer_friends, option_params),
            'viewer_friends');
    // VIEWERの友達のギフト情報(キーワード「gifts」で参照される永続データ)取得をリクエストに追加
    // レスポンスではキーワード「viewer_friends_gifts」で参照される
    req.add(req.newFetchPersonAppDataRequest(viewer_friends, 'gifts',
            option_params), 'viewer_friends_gifts');
    // リクエストを送信
    // リクエストの応答時に実行されるコールバックファンクションにload_friends_callbackを指定
    req.send(load_friends_callback);
}

fig.6

req.add(req.newFetchPersonRequest('VIEWER'), 'viewer');

fig.7

var viewer = opensocial.newIdSpec({'userId': 'VIEWER'});
req.add(req.newFetchPersonAppDataRequest(viewer, 'gifts'), 'viewer_gifts');

fig.8

    var viewer_friends = opensocial.newIdSpec({'userId': 'VIEWER', 'groupId': 'FRIENDS'});
    var option_params = {};
    option_params[opensocial.DataRequest.PeopleRequestFields.MAX] = 100;
    req.add(req.newFetchPeopleRequest(viewer_friends, option_params), 'viewer_friends');

fig.9

eq.add(req.newFetchPersonAppDataRequest(viewer_friends, 'gifts', option_params), 'viewer_friends_gifts');

fig.10

/**
 * load_friendsとsend_giftでのリクエストの応答時に実行されるコールバックファンクション
 * 
 * @param res
 * @return void
 */
function load_friends_callback(res) {
    // VIEWERの情報をキーワード「viewer」で参照
    var viewer = res.get('viewer').getData();
    // VIEWERのギフト情報をキーワード「viewer_gifts」で参照
    var viewer_gifts = res.get('viewer_gifts').getData();
    // VIEWERの友達情報をキーワード「viewer_friends」で参照
    var viewer_friends = res.get('viewer_friends').getData();
    // VIEWERの友達のギフト情報をキーワード「viewer_friends_gifts」で参照
    var viewer_friends_gifts = res.get('viewer_friends_gifts').getData();

    document.getElementById('greeting').innerHTML = viewer.getDisplayName()
            + 'さん、こんにちは';

    // フォームの友達リストを更新
    global_viewer_friends = viewer_friends;
    update_friends_list();

    // VIEWERが友達に贈ったギフトリストの一覧表示を更新
    update_sent_gifts_list(viewer, viewer_gifts, viewer_friends);
    // VIEWERが友達から贈られたギフトリストの一覧表示を更新
    update_received_gifts_list(viewer, viewer_friends_gifts, viewer_friends);

    // ガジェットの表示サイズを調整する
    gadgets.window.adjustHeight();
}

fig.11

/**
 * フォームの友達リストを更新
 * 
 * @return void
 */
function update_friends_list() {
    if (global_viewer_friends.size() == 0) {
        document.getElementById('send-gift-form').innerHTML = '<p>友達がいません!</p>';
        return;
    }

    var arr = new Array();
    global_viewer_friends.each(function(friend) {
        if (friend.getId())
            arr.push('<option value="' + friend.getId() + '">'
                    + friend.getDisplayName() + '</option>');
    });
    document.getElementById('friends-list').innerHTML = arr.join('');
}

fig.12

/**
 * VIEWERが友達に贈ったギフトリストの一覧表示を更新
 * 
 * @param viewer
 * @param viewer_gifts
 * @param viewer_friends
 * @return void
 */
function update_sent_gifts_list(viewer, viewer_gifts, viewer_friends) {
    // グローバル変数を初期化
    global_viewer_gifts = {};

    // レスポンスにVIEWERのギフト情報がない場合
    if (!viewer_gifts[viewer.getId()])
        return;

    // VIEWERのギフト情報(文字列)をエスケープを解除してハッシュに復元
    // グローバル変数にコピーする
    var str = viewer_gifts[viewer.getId()]['gifts'];
    if (!str)
        return;
    str = gadgets.util.unescapeString(str);
    try {
        global_viewer_gifts = gadgets.json.parse(str);
    } catch (e) {
        return;
    }

    // グローバル変数を展開してVIEWERが友達に贈ったギフトリストの一覧表示を更新
    var arr = new Array();
    for ( var i in global_viewer_gifts)
        if (i.hasOwnProperty)
            for ( var j in global_viewer_gifts[i])
                if (j.hasOwnProperty
                        && global_available_gifts[global_viewer_gifts[i][j]])
                    arr.push('<li>'
                            + viewer_friends.getById(i).getDisplayName()
                            + ' さんに '
                            + global_available_gifts[global_viewer_gifts[i][j]]
                            + ' を贈りました' + '</li>');
    if (arr.length > 0) {
        var html = '<ul>' + arr.join('') + '</ul>';
        document.getElementById('sent-gifts').innerHTML = html;
    }
}

fig.13

/**
 * VIEWERが友達から贈られたギフトリストの一覧表示を更新
 * 
 * @param viewer
 * @param viewer_friends_gifts
 * @param viewer_friends
 * @return void
 */
function update_received_gifts_list(viewer, viewer_friends_gifts,
        viewer_friends) {
    var arr = new Array();
    viewer_friends.each(function(friend) {
        if (viewer_friends_gifts[friend.getId()]) {
            // 各友達のギフト情報(文字列)をエスケープを解除してハッシュに復元
            var gifts = {};
            var str = viewer_friends_gifts[friend.getId()]['gifts'];
            if (!str)
                return;
            str = gadgets.util.unescapeString(str);
            try {
                gifts = gadgets.json.parse(str);
            } catch (e) {
                return;
            }

            // ギフトの贈り先がVIEWERならVIEWERが友達から贈られたギフトリストに追加
            for ( var i in gifts)
                if (i.hasOwnProperty && i == viewer.getId())
                    for ( var j in gifts[i])
                        if (j.hasOwnProperty
                                && global_available_gifts[gifts[i][j]])
                            arr.push('<li>' + friend.getDisplayName()
                                    + ' さんから '
                                    + global_available_gifts[gifts[i][j]]
                                    + ' が贈られました' + '</li>');
        }
    });
    if (arr.length > 0) {
        var html = '<ul>' + arr.join('') + '<ul>';
        document.getElementById('received-gifts').innerHTML = html;
    }
}

fig.14

/**
 * ギフトを贈る
 * 
 * @return void
 */
function send_gift() {
    // リクエストを初期化
    var req = opensocial.newDataRequest();

    // 選択されているギフトのID
    var gift_id = document.getElementById('gifts-list').value;
    // 選択されている友達のID
    var friend_id = document.getElementById('friends-list').value;

    // VIEWERが友達に贈ったギフトリストにギフトを追加
    if (!global_viewer_gifts)
        global_viewer_gifts = {};
    if (!global_viewer_gifts[friend_id])
        global_viewer_gifts[friend_id] = new Array();
    global_viewer_gifts[friend_id].push(gift_id);

    // VIEWERのギフト情報(キーワード「gifts」で参照される永続データ)の更新をリクエストに追加
    // 永続データに保存するハッシュはgadgets.json.stringify()ユーティリティで文字列化しておく
    var str = gadgets.json.stringify(global_viewer_gifts);
    req.add(req.newUpdatePersonAppDataRequest('VIEWER', 'gifts', str));

    // VIEWERの情報取得をリクエストに追加
    // レスポンスではキーワード「viewer」で参照される
    req.add(req.newFetchPersonRequest('VIEWER'), 'viewer');

    // VIEWERの識別子
    var viewer = opensocial.newIdSpec( {
        'userId' : 'VIEWER'
    });
    // VIEWERの友達の識別子
    var viewer_friends = opensocial.newIdSpec( {
        'userId' : 'VIEWER',
        'groupId' : 'FRIENDS'
    });
    // リクエストのオプションパラメータ(友達の情報は上限100件で取得)
    var option_params = {};
    option_params[opensocial.DataRequest.PeopleRequestFields.MAX] = 100;

    // VIEWERのギフト情報(キーワード「gifts」で参照される永続データ)取得をリクエストに追加
    // レスポンスではキーワード「viewer_gifts」で参照される
    req.add(req.newFetchPersonAppDataRequest(viewer, 'gifts'), 'viewer_gifts');
    // VIEWERの友達情報取得をリクエストに追加
    // レスポンスではキーワード「viewer_friends」で参照される
    req.add(req.newFetchPeopleRequest(viewer_friends, option_params),
            'viewer_friends');
    // VIEWERの友達のギフト情報(キーワード「gifts」で参照される永続データ)取得をリクエストに追加
    // レスポンスではキーワード「viewer_friends_gifts」で参照される
    req.add(req.newFetchPersonAppDataRequest(viewer_friends, 'gifts',
            option_params), 'viewer_friends_gifts');
    // リクエストを送信
    // リクエストの応答時に実行されるコールバックファンクションにload_friends_callbackを指定
    req.send(load_friends_callback);

    // アクティビティを送信
    post_activity(gift_id, friend_id);
}

fig.15

var gift_id = document.getElementById('gifts-list').value;
var friend_id = document.getElementById('friends-list').value;
if (!global_viewer_gifts) global_viewer_gifts = {};
if (!global_viewer_gifts[friend_id]) global_viewer_gifts[friend_id] = new Array();
global_viewer_gifts[friend_id].push(gift_id);

fig.16

var str = gadgets.json.stringify(global_viewer_gifts);
req.add(req.newUpdatePersonAppDataRequest('VIEWER', 'gifts', str));

fig.17

/**
 * アクティビティを送信
 * 
 * @param gift_id
 * @param friend_id
 * @return void
 */
function post_activity(gift_id, friend_id) {
    var title = global_viewer_friends.getById(friend_id).getDisplayName()
            + ' さんに ' + global_available_gifts[gift_id] + ' を贈りました';
    var params = {};
    params[opensocial.Activity.Field.TITLE] = title;
    opensocial.requestCreateActivity(opensocial.newActivity(params),
            opensocial.CreateActivityPriority.LOW);
}