WebOS Goodies

WebOS の未来を模索する、ゲームプログラマあがりの Web 開発者のブログ。

WebOS Goodies へようこそ! WebOS はインターネットの未来形。あらゆる Web サイトが繋がり、共有し、協力して創り上げる、ひとつの巨大な情報システムです。そこでは、あらゆる情報がネットワーク上に蓄積され、我々はいつでも、どこからでも、多彩なデバイスを使ってそれらにアクセスできます。 WebOS Goodies は、さまざまな情報提供やツール開発を通して、そんな世界の実現に少しでも貢献するべく活動していきます。
Subscribe       

Google Apps API Japan キックオフミーティングの資料を公開します

もう一週間以上前になってしまいましたが、 Google Apps API Japan グループの立ち上げに伴うキックオフイベントで LT をしてきました。本日はその資料を公開します。ほんとはイベント終了後すぐに公開するべきだったのですが、本業が忙しくて時間が取れなかったのと、突貫工事で作ったサンプルプログラムにいくつか問題があって、その解決に時間がかかってしまいました。申し訳ありません m(_ _)m

プレゼン自体は以下の URL で閲覧できます。 Google のスライドテンプレートを使っているんですが、これは画面サイズが固定されるのがイマイチですね…。以前自分で作った奴に戻そうかな (^^;

http://webos-goodies.jp/attachments/apps_api_japan...

LT では簡単なデモをいくつか行ったので、以降にスクリーンショットと簡単な説明を書いておきます。

シンプルな Google ガジェット

「Google ガジェットについて」のところでソースを出しているのは、超初歩的な Hello World ガジェットです。一応、ユーザー設定でメッセージを変更できるようになっています。 iGoogle で表示するとこんな感じ。

Google ガジェットの開発方法の詳細については、公式のスタートガイドをご参照ください。

Gmail サイドバーガジェット

Gmail サイドバーガジェットの例として、 Twitgether をご紹介しました。 Gmail を Twitter クライアントにしてしまおうというガジェットです。

が、現在は CANVAS モードでのガジェットサイズの変更がうまく動いていないらしく、デベロッパーツールで無理やり IFRAME のサイズを変更するはめに orz 実行直後の gadgets.adjustHeight() は危険です。 1 秒くらい待ってから実行するのが無難だと思います。

Gmail コンテキストガジェット

メール中に含まれている PDF や SVG などのリンクをプレビューするガジェットをデモをしました。メール中に既定のファイルタイプ(単に拡張子で判定 ^^;)のリンクがあるとガジェットが表示され、メール本文の下にプレビューが表示されます。

ソースは以下のようになっています。

http://webos-goodies.jp/attachments/apps_api_japan...
http://webos-goodies.jp/attachments/apps_api_japan...

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
  <ModulePrefs title="Document Viewer" height="350" scrolling="false">
    <Require feature="dynamic-height" />

    <!-- 使用するExtractorのリスト -->
    <Require feature="google.contentmatch">
      <Param name="extractors">google.com:HttpLinkExtractor</Param>
    </Require>

  </ModulePrefs>

  <Content type="html" view="card"><![CDATA[
    <!DOCTYPE html>

    <style type="text/css">
      #files-outer { width:100%; overflow:hidden; }
      #viewer      { display:block; width:100%; height:300px;
                     border:none; padding:0; margin:0; }
    </style>

    <!-- ファイル選択コントロールを表示する場所 -->
    <div id="files-outer"></div>

    <!-- プレビューを表示するiframe -->
    <iframe id="viewer" src="about:blank" frameborder="0"></iframe>

    <script type="text/javascript">
      gadgets.util.registerOnLoadHandler(function() {
        // エクストラクタの出力を取得
        var matches = google.contentmatch.getContentMatches();

        // ファイルを選択するSELECT要素を生成
        var selector = ['<select id="files">'];
        for(var i = 0 ; i < matches.length ; ++i) {
          var value = gadgets.util.escapeString(matches[i].url);
          selector.push(
            '<option value="' + value + '">' + value + '</option>');
        }
        selector.push('</select>')
        document.getElementById('files-outer').innerHTML = selector.join('');

        // SELECT要素のイベントを設定(同時にイベントハンドラを一回実行)
        document.getElementById('files').onchange = changeFile;
        changeFile();

        // ガジェットの高さを調整
        gadgets.window.adjustHeight();
      });

      function changeFile() {
        var url = document.getElementById('files').value;
        document.getElementById('viewer').src =
          'https://docs.google.com/viewer?embedded=true&url=' +
          encodeURIComponent(url);
      }
    </script>

  ]]></Content>

</Module>

Gmail コンテキストガジェットについては、こちらの記事をご参照ください。また、最近ではカスタム・エクストラクタも使えるようになっています。

Google カレンダー サイドバーガジェット

コンテキストガジェットと同様に、イベントの説明から PDF 等へのリンクを抽出してプレビューするガジェットをデモしました。イベントを選択すると、説明中のリンクがサイドバーに表示されます。

そして、リンクをクリックすると CANVAS ビューで内容が閲覧できます。 PDF 等は Google Docs Viewer で、それ以外は単純に IFRAME 埋め込みで表示します。

ソースは以下です。

http://webos-goodies.jp/attachments/apps_api_japan...

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
  <ModulePrefs title="Link Preview" height="1" scrolling="false">
    <Require feature="dynamic-height" />
    <Require feature="views" />
    <Require feature="google.calendar-0.5" />
    <Require feature="google.calendar-0.5.read" />
  </ModulePrefs>

  <Content type="html" view="home,profile"><![CDATA[
    <!DOCTYPE html>

    <style>
      #content { font-size:12px; overflow:hidden; }
      #content ul { margin-left: 2em; padding-left:0; white-space:pre; }
    </style>
    <div id="content" onclick="onClickContent(event); return false;"></div>

    <script type="text/javascript">
// カレンダーイベント選択の監視を開始
gadgets.util.registerOnLoadHandler(function() {
  google.calendar.read.subscribeToEvents(onSelectCalendarEvent);
});

// calendar.time を指定秒数だけずらす
function addTimeDelta(time, delta) {
  return google.calendar.utils.fromDate(
    google.calendar.utils.toDate(time, delta * 1000));
}

// カレンダーイベントが選択されたときに呼ばれる関数
function onSelectCalendarEvent(event) {
  google.calendar.read.getEvents(
    function(results) {
      var ev = null;
      for(var i = 0 ; i < results.length ; i++) {
        var events = results[i].events;
        for(var j = 0 ; j < events.length ; j++) {
          if(events[j].id == event.id) {
            ev = events[j];
            break;
          }
        }
      }
      if(ev) {
        var links = [];
        (ev.details||'').replace(/(?:^|[^0-9a-zA-Z_])(https?:\/\/[^\s\x22'<>(){}\[\]]+)/mg,
          function(m0, m1) {
            links.push(m1);
            return m0;
          });
        var html = ['<ul>']
        for(var i = 0 ; i < links.length ; i++) {
          var l = gadgets.util.escapeString(links[i]);
          var m = /([^\/\?]+)(?:\?|$)/.exec(links[i]), t = l;
          if(m) {
            t = gadgets.util.escapeString(m[1]);
          }
          html.push('<li><a href="', l, '">', t, '</a></li>');
        }
        html.push('</ul>');
        if(html.length > 2) {
          document.getElementById('content').innerHTML = html.join('');
          gadgets.window.adjustHeight();
        } else {
          document.getElementById('content').innerHTML = '';
          gadgets.window.adjustHeight(1);
        }
      }
    },
    'selected',
    addTimeDelta(event.startTime, -60),
    addTimeDelta(event.startTime, +60),
    { requestedFields: ['details'] });
}

// CANVASビューを開く
function onClickContent(event) {
  var el = event.target;
  if(el.tagName.toLowerCase() == 'a' && el.href) {
    // CANVASビューに対応するビューを検索
    var views  = gadgets.views.getSupportedViews();
    var canvas = (views[gadgets.views.ViewType.CANVAS] ||
                  views[gadgets.views.ViewType.CANVAS.toLowerCase()] ||
                  views[gadgets.views.ViewType.CANVAS.toUpperCase()]);
    // ビューを切り替える
    gadgets.views.requestNavigateTo(canvas, { url:el.href });
  }
}
    </script>

  ]]></Content>

<Content type="html" view="default,canvas"><![CDATA[
  <!DOCTYPE html>

  <style type="text/css">
    #viewer {
      display:block; width:100%; height:500px;
      border:none; margin:0; padding:0
    }
  </style>

  <iframe id="viewer" src="about:blank" frameborder="0"></iframe>

  <script type="text/javascript">
    gadgets.util.registerOnLoadHandler(function() {
      // パラメータを取得
      var viewParams = gadgets.views.getParams() || {};
      var url        = viewParams.url;

      // iframeに表示するURLを指定
      if(/\.(pdf|doc|xls|ppt|svg)$/.test(url)) {
        document.getElementById('viewer').src =
          'https://docs.google.com/viewer?embedded=true&url=' +
          encodeURIComponent(url);
      } else {
        document.getElementById('viewer').src = url;
      }

      // ガジェットの高さを調整
      gadgets.window.adjustHeight();
    });
  </script>

]]></Content>
</Module>

Google カレンダー サイドバーガジェットについては、こちらの記事を参照してください。

ビジュアライゼーションガジェット

各県の人口を日本地図で可視化するデモを行いました。

単に Geochart を使っているだけですが、ガジェット自体は特別に作っています。県名、平成 12 年人口、平成 17 年人口が並んでいるだけのシートを、ガジェット内で Geochart に適したカラム構成に変換して表示しています。本当は DataView を使ったほうが効率がいいんですが、諸般の都合で DataTable だけで処理しています (^^;

ソースはこちら。

http://webos-goodies.jp/attachments/apps_api_japan...

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
  <ModulePrefs title="都道府県別の人口" />
  <UserPref name="_table_query_url" display_name="データソース URL" required="true" />
  <UserPref name="_table_query_refresh_interval" display_name="更新頻度 (分)"
            default_value="0" datatype="enum" required="false">
    <EnumValue value="0" display_value="Do not refresh"/>
    <EnumValue value="60" display_value="1"/>
    <EnumValue value="300" display_value="5"/>
    <EnumValue value="1800" display_value="30"/>
  </UserPref>
  <Content type="html"><![CDATA[
    <!DOCTYPE html>

    <div id="chart"></div>

    <script src="https://www.google.com/jsapi"></script>
    <script>
      var prefs  = new gadgets.Prefs();
      var helper = null;
      var query  = null;
      var geomap = null;
      var table  = null;

      // Visualization APIを読み込む
      gadgets.util.registerOnLoadHandler(function() {
        google.load('visualization', '1', { 'packages':['geomap'] });
        google.setOnLoadCallback(function() {
          helper = new google.visualization.GadgetHelper();
          query  = helper.createQueryFromPrefs(prefs);
          sendQuery();
        });
      });

      // クエリーの送信
      function sendQuery() {
        query.setQuery("select A,B,C");
        query.send(handleResponse);
      }

      // レスポンスの処理
      function handleResponse(response) {
        // エラー処理
        if(!helper.validateResponse(response)) {
          return;
        }

        // Bカラムを削除したDataTableを作成
        table    = response.getDataTable();
        var view = table.clone();
        view.removeColumn(1);

        // Geomapを描画
        geomap = new google.visualization.GeoMap(document.getElementById('chart'));
        geomap.draw(view, { 'region': 'JP' });
        google.visualization.events.addListener(geomap, 'select', selectHandler);
      }

      // クリックされたときの処理
      function selectHandler(e) {
        var selection = geomap.getSelection();
        if(selection && selection[0]) {
          var row = selection[0].row;
          alert(
            table.getFormattedValue(row, 0) + 'の平成12年人口は' +
            table.getFormattedValue(row, 1) + '人です。');
        }
      }
    </script>
  ]]></Content>
</Module>

ビジュアライゼーションガジェットについては、少々情報が古いですがこちらの記事をご参照ください。公式のドキュメントはこちら

デモを行ったのは以上です。 LT はかなり駆け足だったのですが(それでも時間がなくて、プライベートガジェット以降は説明できませんでした orz)、ガジェットを使うことで Google Apps をいろいろ拡張できることがわかっていただけたのではないかな、と思っています。皆さん、ぜひ試してみてください。

関連記事

この記事にコメントする

Recommendations
Books
「Closure Library」の入門書です。
詳しくはこちらの記事をどうぞ!
Categories
Recent Articles