As I said earlier, Quite a few presentations from Google I/O have been posted for your viewing pleasure. I'll be glued to these this weekend while I'm on call.
Topics include
Ajax
KML
Sketchup
Android
OpenSocial
Appengine
Data APIs
Theory Talks
Youtube
Gears
Mashups
Maps
and more!
Monday, June 16, 2008
Google I/O session videos posted with slides
- LinkMonday, November 5, 2007
October Speedlinking
I haven't been able to post as often or as in depth as I'd like to have this past month. I chalk it up mostly to work, we all love 12 hour days right? But now that sign-off has passed and our last release of 2007 is calmly approaching (its on Friday), things have settled down a bit. Below are some great links from October, most of which I wanted to mention at some point and haven't gotten a chance to until now. Enjoy.
-
The JavaScript Library for Google Calendar was released. This allows for authenticated, cross domain access. Hopefully Picasa Web will follow suit.
-
GWT goes to the iPhone
-
The Python Client Library came out with version 1.0.8
-
The Digg Oracle demonstrates Gears' Worker Pool
-
Google's Stock broke $600. It is now well over $700
-
Orkut ramps up for a US push
-
Vortex combines the know-how of Dojo and Gears
-
LabeledMarker v1.1 in Google Maps comes out with Marker and Label toggling
-
Google Reader comes out with Subscriber stats. Read about the controversy here. Google responds here
-
Google Maps Goes Social
-
The AJAX Search API gives direct access to YouTube Channels
-
Blogger GData JavaScript client library released with offline Blogger client example
-
Google Code Search goes to SiteMaps
-
The Ajax API gets Dynamic Feed Control
-
You can now play Youtube videos in Google Earth
-
Summer of code wrapped up with Graduation
-
Google Finance adds new Gadgets and an API
-
YouTubes player becomes Customizable
-
A Greasemonkey script lets you have nested folders in Gmail
-
Blogger adds Comment Notification
-
Google cracks down on pages selling PageRank links
-
Google contributes to MySQL
-
Google Mac updates Leopard
-
Gmail enables IMAP
-
Google Maps gets Clickable Polygons
-
There is now a wizard for adding Google Gadgets to your blog
-
Webmaster central fixes the Cross Domain Sitemap errors
-
Google maps adds Flash Content into KLM
-
Google Notebook adds labels and bookmarks
-
Blog Search is now included in Google History
-
A cheap "Google PC" is on the market
-
A new Photo Picker for Gmail and Orkut pulls from Picasa
-
GTalk may soon be able to connect to other networks like AIM and Yahoo! Talk
-
The new version of Gmail comes out
-
Google Code gets a facelift
-
Webmaster Tools gets Geographic Targeting
-
The Google Gadget Directory gets a facelift
-
Microsoft is going to release the Microsoft Sync Framework to compete with Gears
-
Picasa Web gets opened. (Flikr can transfer a picasa album to itself)
-
Webmasters can now provide feedback on sitelinks
-
Blog.gears comes out
-
Mapplets gets a documentation and example update
-
New articles are posted for KML
-
The Ajax slideshow gets a full Control Panel
- Map of the Dead!! Google Maps overlay shooting game!
Posted by
Tim Broder
at
6:17 PM
Labels:
blogger,
calendar,
Docs Spreadsheets,
gadgets,
gdata,
gears,
GME,
Mashups,
picasa web
Tuesday, August 21, 2007
Gadgets now on Google Calendar!
- LinkGoogle Gadgets can now be added to your calendar. Previously the only gadgets I had on my calendar were Google Doodles, Weather, phases of the moon, and PicasaWeb Photo of the day. Now just about anything is going to be possible. I briefly played around with it this morning and added horoscopes and Sudoku to my calendar.

Other new gadgets include Movie Release dates and famous people's birthdays. I expect that very soon there will be video game releases as well. Documentation is out for the gadgets, so get coding!
Saturday, August 4, 2007
First Google Gadget
- LinkAfter being inspired about Google Gadgets from the Google Developer Podcast I came up with on that my old crew team can use. We have a shared google calendar that some of us use to keep track of races, meetings, etc. This gadget pulls and formats it nicely for the google IG or desktop.
![]()
Javascript code for the gadget:
<style type="text/css">
div.exp{
padding: 0;
margin: 0;
}
div.loc{
margin-left: 19px;
}
</style>
<script type="text/javascript">
<!--
/**
* Season info *
* 0 Fall: Aug 26 - Nov 1
* 1 Winter Training: Nov 2 - March 1
* 2 Spring: March 2 - May 25
* 3 Summer: May 26 - Aug 25
**/
/**
* Callback function for the GData json-in-script call
* Inserts the supplied list of events into a div of a pre-defined name
*
* @param {json} root is the JSON-formatted content from GData
*/
function processRaces(root) {
displayRaces(root.feed, 'races');
}
//meow
function displayRaces(feed, divId){
var now = new Date();
var season = getSeason(now);
var events = document.getElementById(divId);
//clear "Loading..."
if (events.childNodes.length > 0){
events.removeChild(events.childNodes[0]);
}
//display season
var d = document.createElement('div');
d.appendChild(document.createTextNode(getSeasonText(season)));
events.appendChild(d);
//loop races
for (var i=0; i<feed.entry.length; i++){
var entry = feed.entry[i];
var d = getDate(entry['gd$when'][0].startTime);
if(isCurrSeason(now, d)){
var title = entry.title.$t;
var desc = entry.content.$t;
//set up image and clicking to expand
var div = document.createElement('div');
div.className = 'exp';
var toggle = document.createElement('img');
toggle.src= 'http://timothy.broder.googlepages.com/p.jpg';
toggle.align = 'absmiddle';
toggle.id = i;
toggle.onclick = function() {toggleDiv(this); }
div.appendChild(toggle);
div.appendChild(document.createTextNode(' ' + d.getMonth() + "/" + d.getDay() + ' - '));
// get the href to link to the event
for(var j=0; j<entry['link'].length; j++){
if (entry['link'][j]['type'] == 'text/html' && entry['link'][j]['rel'] == 'alternate'){
var href = entry['link'][j]['href'];
}
}
//we can link to the cal
if (typeof href != 'undefined'){
var link = document.createElement('a');
link.href = href;
link.target = '_blank';
link.appendChild(document.createTextNode(title));
div.appendChild(link);
}
else{ //shouldn't get here but just in case
div.appendChild(document.createTextNode(title));
}
div.appendChild(document.createElement('br'));
events.appendChild(div);
var where = entry['gd$where'][0].valueString;
var tDiv = document.createElement('div'); //div that will be hidden initially
tDiv.id ='id' + i;
tDiv.style['display'] = 'none';
tDiv.className = 'loc';
events.appendChild(tDiv);
if(desc != null && desc != ""){ //we have a desc (should be the teams we're competing against)
var dDiv = document.createElement('span');
dDiv.appendChild(document.createTextNode(desc + " "));
tDiv.appendChild(dDiv);
}
//the location field is populated (hidden at start)
if(where != null && where != ""){ //we have a location
var it = document.createElement('i');
var map = document.createElement('a');
map.target = '_blank';
//link to location on google maps
map.href = 'http://maps.google.com/maps?f=q&hl=en&&q=' + spaceLink(entry['gd$where'][0].valueString);
map.appendChild(document.createTextNode(entry['gd$where'][0].valueString));
it.appendChild(document.createTextNode(" ("));
it.appendChild(map);
it.appendChild(document.createTextNode(")"));
tDiv.appendChild(it);
}
}
}
}
//format the date a little
function getDate(when){
var data = when.split("-");
return new Date(data[0], data[1], data[2]);
}
//return int representation of season
function getSeason(d){
var month = d.getMonth();
var day = d.getDate();
var year = d.getFullYear();
var aug = new Date(year, 8, 25);
var nov = new Date(year, 11, 1);
var mar = new Date(year, 3, 1);
var may = new Date(year, 5, 25);
if(aug < d && d <= nov) return 0; //fall
else if(mar < d && d <= may) return 2; //spring
else if(may < d && d <= aug) return 3; //summer
else return 1; //winter
}
//figure out the current season
function isCurrSeason(now, d){
currSeason = getSeason(now);
season = getSeason(d);
if(currSeason == season){ //same season yes
if(now.getFullYear() == d.getFullYear()){ //same year also, match
return true;
}
if(season == 1 && (d.getFullYear() == now.getFullYear()-1)){ //diff year, prob winter
return true;
}
}
return false;
}
//return text for season
function getSeasonText(season){
if(season == 0) return "Fall Season";
if(season == 1) return "Winter Training";
if(season == 2) return "Spring Season";
if(season == 3) return "Summer Season";
return "no season"; //really shouldn't get here
}
//if the div is hidden show it, if not, hide it
function toggleDiv(where_id){
var div = document.getElementById('id' + where_id.id);
var img = document.getElementById(where_id.id);
if(div != null){
if(div.style.display != 'none'){
div.style.display = 'none';
img.src= 'http://timothy.broder.googlepages.com/p.jpg';
}
else{
div.style.display = 'block';
img.src= 'http://timothy.broder.googlepages.com/m.jpg';
}
}
}
//convert the location so it can be used in a link to google maps
function spaceLink(name){
return name.replace(' ', ',+');
}
//-->
</script>
<div id="races"><p>Loading...</p></div>
<script type="text/javascript" src="http://www.google.com/calendar/feeds/rpicrew@gmail.com/public/full?alt=json-in-script&callback=processRaces&orderby=starttime&singleevents=true&sortorder=ascending&start-min=2007-01-01T00:00:00"></script>
And the XML for the gadget
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="RPI Crew Schedule"
title_url="http://gpowered.net"
author="Tim Broder"
height="150"
width="250"
author_email="timothy.broder@gmail.com"
thumbnail="http://timothy.broder.googlepages.com/RPICrewScheduleThumb.jpg"
description="RPI Crew Race Schedule, links to the RPICrew shared google calendar"
author_photo="http://timothy.broder.googlepages.com/timothybrodersimpsons.png"
author_location="NYC"
author_affiliation="gPowered"
author_link="http://www.gpowered.net"
screenshot="http://timothy.broder.googlepages.com/RPICrewScheduleScreen.jpg"
>
<Require feature="dynamic-height"/>
<Require feature="analytics"/>
</ModulePrefs>
<Content type="html"><![CDATA[
<script>
// Track this gadget using Google Analytics.
_IG_Analytics("UA-793489-6", "/RPICrewScheduleG");
</script>
<style type="text/css">
div.exp{
padding: 0;
margin: 0;
}
div.loc{
margin-left: 19px;
}
</style>
<script type="text/javascript">
<!--
/**
* Season info *
* 0 Fall: Aug 26 - Nov 1
* 1 Winter Training: Nov 2 - March 1
* 2 Spring: March 2 - May 25
* 3 Summer: May 26 - Aug 25
**/
/**
* Callback function for the GData json-in-script call
* Inserts the supplied list of events into a div of a pre-defined name
*
* @param {json} root is the JSON-formatted content from GData
*/
function processRaces(root) {
displayRaces(root.feed, 'races');
}
//meow
function displayRaces(feed, divId){
var now = new Date();
var season = getSeason(now);
var events = document.getElementById(divId);
//clear "Loading..."
if (events.childNodes.length > 0){
events.removeChild(events.childNodes[0]);
}
//display season
var d = document.createElement('div');
d.appendChild(document.createTextNode(getSeasonText(season)));
events.appendChild(d);
//loop races
for (var i=0; i<feed.entry.length; i++){
var entry = feed.entry[i];
var d = getDate(entry['gd$when'][0].startTime);
if(isCurrSeason(now, d)){
var title = entry.title.$t;
var desc = entry.content.$t;
//set up image and clicking to expand
var div = document.createElement('div');
div.className = 'exp';
var toggle = document.createElement('img');
toggle.src= 'http://timothy.broder.googlepages.com/p.jpg';
toggle.align = 'absmiddle';
toggle.id = i;
toggle.onclick = function() {toggleDiv(this); }
div.appendChild(toggle);
div.appendChild(document.createTextNode(' ' + d.getMonth() + "/" + d.getDay() + ' - '));
// get the href to link to the event
for(var j=0; j<entry['link'].length; j++){
if (entry['link'][j]['type'] == 'text/html' && entry['link'][j]['rel'] == 'alternate'){
var href = entry['link'][j]['href'];
}
}
//we can link to the cal
if (typeof href != 'undefined'){
var link = document.createElement('a');
link.href = href;
link.target = '_blank';
link.appendChild(document.createTextNode(title));
div.appendChild(link);
}
else{ //shouldn't get here but just in case
div.appendChild(document.createTextNode(title));
}
div.appendChild(document.createElement('br'));
events.appendChild(div);
var where = entry['gd$where'][0].valueString;
var tDiv = document.createElement('div'); //div that will be hidden initially
tDiv.id ='id' + i;
tDiv.style['display'] = 'none';
tDiv.className = 'loc';
events.appendChild(tDiv);
if(desc != null && desc != ""){ //we have a desc (should be the teams we're competing against)
var dDiv = document.createElement('span');
dDiv.appendChild(document.createTextNode(desc + " "));
tDiv.appendChild(dDiv);
}
//the location field is populated (hidden at start)
if(where != null && where != ""){ //we have a location
var it = document.createElement('i');
var map = document.createElement('a');
map.target = '_blank';
//link to location on google maps
map.href = 'http://maps.google.com/maps?f=q&hl=en&&q=' + spaceLink(entry['gd$where'][0].valueString);
map.appendChild(document.createTextNode(entry['gd$where'][0].valueString));
it.appendChild(document.createTextNode(" ("));
it.appendChild(map);
it.appendChild(document.createTextNode(")"));
tDiv.appendChild(it);
}
}
}
}
//format the date a little
function getDate(when){
var data = when.split("-");
return new Date(data[0], data[1], data[2]);
}
//return int representation of season
function getSeason(d){
var month = d.getMonth();
var day = d.getDate();
var year = d.getFullYear();
var aug = new Date(year, 8, 25);
var nov = new Date(year, 11, 1);
var mar = new Date(year, 3, 1);
var may = new Date(year, 5, 25);
if(aug < d && d <= nov) return 0; //fall
else if(mar < d && d <= may) return 2; //spring
else if(may < d && d <= aug) return 3; //summer
else return 1; //winter
}
//figure out the current season
function isCurrSeason(now, d){
currSeason = getSeason(now);
season = getSeason(d);
if(currSeason == season){ //same season yes
if(now.getFullYear() == d.getFullYear()){ //same year also, match
return true;
}
if(season == 1 && (d.getFullYear() == now.getFullYear()-1)){ //diff year, prob winter
return true;
}
}
return false;
}
//return text for season
function getSeasonText(season){
if(season == 0) return "Fall Season";
if(season == 1) return "Winter Training";
if(season == 2) return "Spring Season";
if(season == 3) return "Summer Season";
return "no season"; //really shouldn't get here
}
//if the div is hidden show it, if not, hide it
function toggleDiv(where_id){
var div = document.getElementById('id' + where_id.id);
var img = document.getElementById(where_id.id);
if(div != null){
if(div.style.display != 'none'){
div.style.display = 'none';
img.src= 'http://timothy.broder.googlepages.com/p.jpg';
}
else{
div.style.display = 'block';
img.src= 'http://timothy.broder.googlepages.com/m.jpg';
}
}
}
//convert the location so it can be used in a link to google maps
function spaceLink(name){
return name.replace(' ', ',+');
}
//-->
</script>
<div id="races"><p>Loading...</p></div>
<script type="text/javascript" src="http://www.google.com/calendar/feeds/rpicrew@gmail.com/public/full?alt=json-in-script&callback=processRaces&orderby=starttime&singleevents=true&sortorder=ascending&start-min=2007-01-01T00:00:00"></script>
]]></Content>
</Module>
















