Google Apps Script でガジェットを作成してみる

| コメントをどうぞ

前回に引き続きGoogle Apps Script活用のお話ですが、今回はGoogle Apps Scriptを使って簡単にガジェットを作成してみたいと思います。

Google Apps Scriptで作成したWebアプリをそのままinfoScoopにガジェットとして表示できたら便利ですが、X-Frame-OptionsというHTTPレスポンスヘッダにより他のサイトに直接表示することができないようになっています。クリックジャッキング対策のためだそうです。

x-frame-options:SAMEORIGIN

そこでJSONP(JSON with padding)の仕組みを使って、Googleカレンダーのイベントをガジェットに表示してみたいと思います。

サーバーサイドスクリプトの作成

Google Apps ScriptでJSONを返すサーバーサイドスクリプトを作成します。
自分が参照設定しているすべてのカレンダーから現在日のイベントを取得したいと思います。

■ 自分が参照設定しているカレンダー
my-calendar

スクリプトエディタを起動し、以下のスクリプトを作成します。

■ サーバーサイドスクリプト

function doGet(request) {  
  // 認証・認可後のコールバック処理
  if( request.parameters.callback_url ) {
    return HtmlService.createHtmlOutput('<a href="' + request.parameters.callback_url + '">Continue</a>');
  }
  // イベントデータの返却
  else {
    var events = getEvents();
    return ContentService.createTextOutput(
      request.parameters.prefix + '(' + JSON.stringify(events) + ')')
    .setMimeType(ContentService.MimeType.JAVASCRIPT);
  }
}

// 現在日のイベントデータの取得処理
function getEvents() {
  var rtnObj = [];
  var calendars = CalendarApp.getAllCalendars();
  for(var i=0; i<calendars.length; i++){
    var obj = {
      id: calendars[i].getId(),
      name: calendars[i].getName(),
      color: calendars[i].getColor(),
      events: []
    };
    var events = calendars[i].getEventsForDay(new Date());
    for(var j=0; j<events.length; j++){
      obj.events.push({
        id: events[j].getId(),
        title: events[j].getTitle(),
        startTime: events[j].getStartTime(),
        endTime: events[j].getEndTime(),
        location: events[j].getLocation(),
        description: events[j].getDescription()
      });
    }
    rtnObj.push(obj);
  }
  return rtnObj;  
}

実際にJSONPのコールバック関数名を指定してリクエストすると以下のようなJSONが返ってきます。

json_sample

ガジェットの作成

イベント一覧を表示するためのガジェットを作成します。

先ほど作成したサーバーサイドスクリプトを呼び出しJSONを取得するための
フロントサイドのスクリプトを作成します。

■ スクリプトファイル

var appUrl = 'your application url';

$(function () {
  $.ajax({
    url: appUrl,
    type:'GET',
    dataType: 'jsonp',
    jsonp : "prefix",
    timeout:10000,
    success: function(data) {
      showEvents(data);
    },
    error: function(data) {
      window.open(appUrl + '?callback_url=' + encodeURI(_GADGET_BASE_URL + '/callback.html'), 'auth', 'width=500,height=400,resizable=yes');
    },
    complete : function(data) {},
  });

  $('#accordion').on('shown.bs.collapse', function() {
    gadgets.window.adjustHeight();
  }).on('hidden.bs.collapse', function (e) {
    gadgets.window.adjustHeight();
  });
});

function showEvents(cals){
  var accordion = $('#accordion');

  var cnt = 0;
  $.each(cals, function() {
    cnt++;
    var cal = this;
    var eventItems = '';
    $.each(cal.events, function() {
      var startTime = new Date(this.startTime);
      var endTime = new Date(this.endTime);
      var startTimeStr = startTime.getHours() + ':' + ( startTime.getMinutes() < 10 ? '0' + startTime.getMinutes() : startTime.getMinutes());
      var endTimeStr = endTime.getHours() + ':' + ( endTime.getMinutes() < 10 ? '0' + endTime.getMinutes() : endTime.getMinutes());
      eventItems += '<div class="event-item">' + startTimeStr + '-' +  endTimeStr + ' ' + this.title + (this.location ? ' ('  + this.location + ')' : '') + '</div>';
    });
    var calendarItem = '<div class="panel panel-default">'
              + '<div class="panel-heading">'
              + '<div class="panel-title"><a data-toggle="collapse" data-parent="#accordion" href="#cal_' + cnt + '"><span class="square-item-container"><span class="square-item" style="background-color:' + cal.color + '"></span></span><span class="item-name">' + cal.name + ( cal.events.length > 0  ? '<span class="badge">' + cal.events.length + '</span>' : '') + '</span></a></div>'
              + '</div>'
              + '<div id="cal_' + cnt + '" class="panel-collapse collapse' + (cnt == 1 ? ' in' : '') + '">'
              + '<div class="panel-body">' + eventItems + '</div>'
              + '</div>'
              + '</div>';
    accordion.append(calendarItem);
  });
  gadgets.window.adjustHeight();
}

以下にはサーバーサイドスクリプトのURLを設定します。

var appUrl = 'your application url';

サーバーサイドスクリプトのURLはスクリプトエディタの「公開/ウェブアプリケーションとして導入」メニューから公開登録をすることで発行されます。

web-app-url

■ ガジェットXML
ガジェットXMLは以下のソースを記述します。

<?xml version="1.0" encoding="UTF-8"?><Module>
    <ModulePrefs height="0" title="今日のイベント">
        <Require feature="dynamic-height"/>
        <Icon>__IS_GADGET_BASE_URL__/calendar-day.png</Icon>
    </ModulePrefs>
    <Content type="html" view="home"><![CDATA[

  <link rel="stylesheet" href="__IS_GADGET_BASE_URL__/bootstrap/css/bootstrap.min.css"></link>
  <script>
    var _GADGET_BASE_URL = '__IS_GADGET_BASE_URL__';
  </script>
  <script src="__IS_GADGET_BASE_URL__/jquery-1.11.1.min.js"></script>
  <script src="__IS_GADGET_BASE_URL__/bootstrap/js/bootstrap.min.js"></script>
  <style type="text/css">
    .event-list{
      margin: 10px;
    }

    span.square-item {
      width: 18px;
      height: 18px;
      display: table-cell;
      vertical-align: middle;
    }

    span.item-name {
      display: table-cell;
      vertical-align: middle;
      padding-left: 5px;
    }

    span.square-item-container {
      display: table-cell;
      vertical-align: middle;
    }

    .panel-default>.panel-heading .badge {
      color: #f5f5f5;
      background-color: #C5C5C5;
      margin-left: 5px;
    }

    .event-item {
      margin: 0px 15px;
      font-size: 1.1em;
      padding: 15px 0px;
    }

    .event-item:not(:last-child) {
      border-bottom: #ddd 1px solid;
    }

    .panel-body {
        padding: 0;
    }
  </style>
  <script type="text/javascript" src="__IS_GADGET_BASE_URL__/event_list.js"></script>

  <div class="event-list">
    <div class="panel-group" id="accordion"></div>
  </div>
    ]]></Content>
</Module>

ガジェットのソース

作成したガジェットをinfoScoopにアップロードし、実際に表示してみると以下のようになります。

event_list_gadget

このようにGoogle Apps ScriptはJSONPの仕組みを利用してサーバーサイドとしても利用でき便利ですが、運用規模によっては呼び出しの回数などの制限もありますのでご注意ください。
https://developers.google.com/apps-script/guides/services/quotas

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>