|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<style type="text/css"> |
|
.skeleton { |
|
display: none; |
|
visibility: hidden; |
|
} |
|
</style> |
|
<script src="http://d3js.org/d3.v3.min.js"></script> |
|
<script src="//apis.google.com/js/client.js?onload=init"></script> |
|
|
|
<script type="text/javscript" src="//apis.google.com/js/api.js"></script> |
|
<script type="text/javscript" src="https://apis.google.com/js/auth.js?onload=init"></script> |
|
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> |
|
<script type="text/javascript"> |
|
var key = "AIzaSyDNpgpDX4hLq2TdiBqvrKKyqmuLxqeY-L4"; |
|
var appId = 'glucose-calendar'; |
|
var clientId = '244880377962.apps.googleusercontent.com'; |
|
|
|
|
|
</script> |
|
</head> |
|
<body> |
|
<h1>javascript only fetch google calendar events</h1> |
|
<img src="1x1.gif" /> |
|
<h2>Howdy, <span class="username">???</span></h2> |
|
<p> |
|
This demo doesn't implement glucose fetching, just the google auth + google |
|
query seps. |
|
I'd like to know your email address |
|
<span class="email">, so I can look up your calendars</span>. |
|
In later demos, I'm also going to inspect your profile to see if I can find any |
|
glucose records. Then I'm going to graph both events from your calendar and |
|
your glucose records together. This assumes your are a google plus user, and |
|
have a git <tt>phr</tt> link with a file called sugars.csv. |
|
We use d3 to create a results row in a table for each calendar event. |
|
</p> |
|
<div id="content"></div> |
|
<div id="events"> |
|
<div id="range"> |
|
<h4>Start: <span id="start"></span></h4> |
|
<h4>End: <span id="end"></span></h4> |
|
|
|
</div> |
|
<table id="list"> |
|
<tbody class="skeleton"> |
|
<tr class="event"> |
|
<td><span class="v start"></span></td> |
|
<td><span class="v end"></span></td> |
|
<td><span class="v summary"></span></td> |
|
<td><span class="v location"></span></td> |
|
<td><span class="v detail"></span> |
|
<a class="more htmlLink">more</a> |
|
</td> |
|
<td><span class=""></span></td> |
|
<td> </td> |
|
</tr> |
|
</tbody> |
|
<tbody="target"> |
|
</tbody> |
|
</table> |
|
</div> |
|
<script type="text/javascript"> |
|
|
|
// The default "private/full" feed is used to retrieve events from |
|
// the primary private calendar with full projection |
|
var feedUri = 'https://www.google.com/calendar/feeds/bewest@gmail.com/private/full'; |
|
var scope = "https://www.google.com/calendar/feeds/"; |
|
scope = scope + ' ' + "https://www.googleapis.com/auth/plus.me"; |
|
scope = scope + ' ' + "https://www.googleapis.com/auth/userinfo.email"; |
|
scope = scope + ' ' + "https://www.googleapis.com/auth/userinfo.profile"; |
|
var loginUrl = 'https://accounts.google.com/o/oauth2/auth'; |
|
var cb_url = "http://localhost:4545/#oauthCallback"; |
|
var opts = { |
|
|
|
}; |
|
gapi.load('auth', init); |
|
function init ( ) { |
|
// console.log('init', 'setting api key', this, arguments, gapi); |
|
handleClientLoad( ); |
|
// gapi.client.setApiKey(key); |
|
// $(document).trigger('auth'); |
|
|
|
} |
|
$(document).on('auth', function ( ) { |
|
console.log('got auth event from head'); |
|
checkAuth( ); |
|
}); |
|
|
|
|
|
// Error handler to be invoked when getEventsFeed() produces an error |
|
var handleError = function(error) { |
|
console.log(error); |
|
} |
|
// google.setOnLoadCallback(setup_login); |
|
|
|
function handleClientLoad() { |
|
// console.log('setting api key'); |
|
gapi.client.setApiKey(key); |
|
window.setTimeout(checkAuth,1); |
|
} |
|
|
|
function checkAuth() { |
|
// console.log('checking auth... performing auth'); |
|
gapi.auth.authorize({client_id: clientId, scope: scope }, handleAuthResult); |
|
} |
|
|
|
function handleAuthResult(authResult) { |
|
// console.log('auth result', this, arguments); |
|
if (authResult && !authResult.error) { |
|
// console.log('success logging in'); |
|
makeApiCall(); |
|
} else { |
|
// console.log('error logging in', authResult.error); |
|
} |
|
} |
|
|
|
function handleAuthClick(event) { |
|
gapi.auth.authorize({client_id: clientId, scope: scope, immediate: false}, handleAuthResult); |
|
return false; |
|
} |
|
|
|
var user = { }; |
|
|
|
function makeApiCall( ) { |
|
// console.log("hooray, can fetch events?"); |
|
gapi.client.load('plus', 'v1', function() { |
|
var request = gapi.client.plus.people.get({ |
|
'userId': 'me' |
|
}); |
|
request.execute(function(resp) { |
|
// console.log('resp', resp); |
|
var heading = document.createElement('h4'); |
|
var image = document.createElement('img'); |
|
image.src = resp.image.url; |
|
heading.appendChild(image); |
|
heading.appendChild(document.createTextNode(resp.displayName)); |
|
|
|
document.getElementById('content').appendChild(heading); |
|
}); |
|
}); |
|
gapi.client.load('oauth2', 'v2', function() { |
|
var request = gapi.client.oauth2.userinfo.v2.me.get( ); |
|
request.execute(function (resp) { |
|
// console.log('user info', resp); |
|
user.info = resp; |
|
jQuery('.username').text(resp.result.email); |
|
jQuery('.email').text(resp.result.email).trigger('email'); |
|
}); |
|
}); |
|
gapi.client.load('calendar', 'v3', function() { |
|
// console.log('loaded google calendar support?', this, arguments); |
|
var request = gapi.client.calendar.calendarList.list( ); |
|
request.execute(function (resp) { |
|
// console.log('got a calendars list response', resp ); |
|
}); |
|
}); |
|
} |
|
jQuery(document).on('email', function ( ) { |
|
// console.log('email known, fetching calendar data', 'user', user); |
|
var email = user.info.email; |
|
gapi.client.load('calendar', 'v3', function() { |
|
var opts = { |
|
calendarId: email, |
|
singleEvents: 'true', |
|
orderBy: 'startTime', |
|
timeMin: '2010-01-01T00:00:00Z' |
|
}; |
|
// console.log('entry list opts', opts); |
|
var events_list = gapi.client.calendar.events.list(opts); |
|
events_list.execute(function (resp) { |
|
// console.log('got a events list response', resp); |
|
user.events = resp.result.items; |
|
list_events(user.events); |
|
}); |
|
}); |
|
}); |
|
|
|
|
|
function dup_row(skel) { |
|
// console.log('return factory for dup row', this, arguments); |
|
return (function (data, i) { |
|
// console.log('dup row', this, arguments); |
|
var row = skel.clone(true).addClass('row'); |
|
for (x in data) { |
|
if (data[x].toString( ) != '[object Object]') { |
|
row.find('.v.' + x).text(data[x]); |
|
} else { |
|
// console.log('???', x, data[x]); |
|
} |
|
} |
|
row.find('.end').text(data.end.dateTime || data.end.date); |
|
row.find('.start').text(data.start.dateTime || data.start.date); |
|
row.find('A.htmlLink').attr('href', data.htmlLink); |
|
// console.log('done with row', row); |
|
|
|
return d3.select(jQuery(this).append(row)[0]); |
|
|
|
}); |
|
|
|
} |
|
|
|
var iso_day = d3.time.format("%Y-%m-%d"); |
|
var parse_dt = /(.*)-(\d\d):(\d\d)$/; |
|
var iso_daytime = d3.time.format("%Y-%m-%dT%H:%M:%S"); |
|
function parse_date(d) { |
|
if (d.start.dateTime) { |
|
var p = d.start.dateTime.match(parse_dt); |
|
var s = p[1]; |
|
return iso_daytime.parse(s); |
|
} |
|
return iso_day.parse(d.start.date); |
|
}; |
|
|
|
function list_events(list) { |
|
// console.log('working with list', list); |
|
list.forEach(function (d) { d.ts = parse_date(d); }); |
|
var skeleton = jQuery('#list .skeleton').clone(true).removeClass('skeleton'); |
|
var duper = dup_row(skeleton); |
|
var timeRange = d3.extent(list, function(d) { |
|
// console.log(this, arguments); |
|
return d.ts; }); |
|
jQuery('#range #start').text(timeRange[0]); |
|
jQuery('#range #end').text(timeRange[1]); |
|
var rows = d3.select('#list').selectAll('.row').data(list).enter( ).select(duper); |
|
} |
|
|
|
</script> |
|
</body> |
|
</html> |
|
|
This is a "live" version of the static demo
Running over http is not recommended... need to host this somewhere proper.