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