Blog Entry
Picasa Album mit JSON und AJAX Posted on September 23, 2007
Bei meinen letzten posting ging es über den Zugriff auf Picasa mit PHP/Atom Feeds. Die Picasa API unterstützt aber auch JSON, dies hat den Vorteil das kein XML Parser benötigt wird und die Verwendung ist besonders einfach in Kombination mit Javascript.
Zunächst definieren wir Variablen mit der URI um die JSON Daten unseres Picasa Albums zu bekommen.
index_url = 'http://picasaweb.google.com/data/feed/api/user/GOOGLE_ACCOUNT?kind=album&alt=json&callback={callback}' album_url = 'http://picasaweb.google.com/data/feed/api/user/GOOGLE_ACCOUNT/albumid/'
Der Parameter alt bewirkt das wir JSON statt XML bekommen, callbackist eine Funktion die anschließend aufgerufen wird. Welche Funktion das ist variiert je nachdem ob der Album Index oder der Inhalt eines Album Ordners abgezeigt werden soll, deshalb verwenden wir nur den Platzhalter {callback}
Wie können die Daten nun dynamisch in unsere Webseite integrieren werden? Javascript erlaubt aus Sicherheitsgründen nur den Zugriff innerhalb der selben Domain. Nun, es gibt eine Ausnahme, mit dem HTML Tag <script> ist es möglich auch Scripte von anderen Domains auf der eigenen Seite auszuführen.
Wir brauchen also eine Funktion die dynamisch ein <script> Element in die Seite einfügt (falls noch nicht vorhanden) und das src Attribute mit der richtigen URI setzt.
json = { callbacks: {} } function load_json(url, callback) { var script = document.getElementById('jsondata') var headID = document.getElementsByTagName("head")[0] if (script) { headID.removeChild(script) // Element löschen falls bereits vorhanden } var script = document.createElement('script') script.id = 'jsondata' script.type = 'text/javascript' script.src = url.replace(/{callback}/, callback) headID.appendChild(script) }
Der Platzhalter {callback} wird nun durch die Funktion ersetzt welche anschließend aufgerufen werden soll, die Funktion für den Index hat den Namen showGalleryIndex.
function showGalleryIndex(json_obj) { var feed = json_obj.feed var content = document.getElementById('gallery') for (var i in feed.entry) { var entry = feed.entry[i] var title = document.createElement('h4') content.appendChild(title) var title_txt = document.createTextNode(entry.title.$t) title.appendChild(title_txt) var summary = document.createElement('div') content.appendChild(summary) var summary_txt = document.createTextNode(entry.media$group.media$description.$t) summary.appendChild(summary_txt) summary.style.position = "absolute" summary.style.left = "12%" summary.style.marginTop = "1em" var albumid = entry.gphoto$id.$t album_link = document.createElement('a') album_link.id = albumid album_link.setAttribute('href', entry['id']['$t']) album_link.onclick= function() { feed_url = album_url + this.id + '?kind=photo&alt=json&callback={callback}' load_json(feed_url, 'showGalleryAlbum') return false } content.appendChild(album_link) var img = document.createElement('img') img.setAttribute('src', entry.media$group.media$thumbnail[0].url) img.setAttribute('width', '72') img.setAttribute('height', '72') album_link.appendChild(img) } }
Die Funktion erstellt im Prinzip nur die entsprechenden Nodes mit DOM, alternativ könnte man auch direkt HTML benutzen mit innerHTML - das würde den Quellcode um mind. 2/3 kürzer machen. Ich bevorzuge jedoch das DOM da dies im Gegensatz zu innerHTML auch mit XML funktioniert.
Bei einem Klick auf ein Foto wird das JSON aus der Webseite entfernt und durch eine neue Version für das entsprechende Album ersetzt. Sobald die Daten verfügbar sind wird diesmal die Funktion showGalleryAlbum aufgerufen. Unser <div> mit der id gallery enthält bereits den Index des Albums, deshalb löschen wir noch zuvor alle Child Nodes mit dem Aufruf von clearContent.
function clearContent() { var content = document.getElementById('gallery') while (content.hasChildNodes()) { content.removeChild(content.firstChild) } } function showGalleryAlbum(json_obj) { var feed = json_obj.feed var content = document.getElementById('gallery') var h3 = document.getElementsByTagName('h3')[0].firstChild h3.nodeValue = 'arbeiten ' + json_obj.feed.title.$t clearContent() for (i in feed.entry) { var entry = feed.entry[i] var title = entry.media$group.media$description.$t var albumid = entry.gphoto$id.$t var image_url = entry.media$group.media$content[0].url+'?imgmax=800' var album_link = document.createElement('a') album_link.setAttribute('href', image_url) album_link.setAttribute('title', title) album_link.setAttribute('rel', 'album') album_link.onclick= function() { myview = open('', this.title, 'width=800,height=600,left=100,top=20,status=no,scrollbars=no') var myview_body = myview.document.getElementsByTagName('body')[0] myview_body.style.background = 'url('+this.href+')' return false } content.appendChild(album_link) var img = document.createElement('img') img.setAttribute('src', entry.media$group.media$thumbnail[0].url) img.setAttribute('width', entry.media$group.media$thumbnail[0].width) img.setAttribute('height', entry.media$group.media$thumbnail[0].height) album_link.appendChild(img) } return false }
Hier passiert genau dasselbe wie bei showGalleryIndex, die Elemente für das Album werden per DOM dynamisch generiert.
Das war schon nahezu alles! Jetzt muss das Script nur noch nach dem Laden der Seite ausgeführt werden.
function init_gallery() { load_json(index_url, 'showGalleryIndex') } window.onload = init_gallery
Das HTML zum testen.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Picasa Web Album mit JSON</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Script-Type" content="text/javascript" /> <script src="gallery.js" defer="defer" type="text/javascript"></script> <style type="text/css"> /*<![CDATA[*/ img { border:0 } /*]]>*/ </style> </head> <body> <h1>Picasa Web Album mit JSON</h1> <h3>Index</h3> <p><a href="./">Index</a></p> <div id="gallery"></div> </body> </html>
Das gesamte Script gibt es auch als Download, eine lauffähige Demo ist ebenfalls vorhanden. Die erste Version habe ich mit JQuery programmiert und hier eingesetzt.
Enjoy! ;-)