blob: 7f5df784a6a986c9aeb79853fba5ac72f3f1bc68 [file] [log] [blame]
Scott Main1e9129d2009-07-15 15:38:19 -07001videos=true
2page.title=Videos
3@jd:body
4
Scott Mainc9ac1072010-10-25 13:45:35 -07005<script src="http://swfobject.googlecode.com/svn/trunk/swfobject/swfobject.js" type="text/javascript"></script>
Scott Main1e9129d2009-07-15 15:38:19 -07006<script src="{@docRoot}assets/jquery-history.js" type="text/javascript"></script>
7<script type="text/javascript">
8// for debugging in FF, so other browsers ignore the console commands.
9var console;
10if (!console) console = { 'log': function() {} };
11
12/* This 'playlist' object defines the playlist IDs for each tab.
13 * Each name inside 'playlist' corresponds to class names for the tab that the playlists belong to (eg: "googleioTab" and "googleioBox" divs).
14 * Each string in 'ids' is the ID of a YouTube playlist that belongs in the corresponding tab.
15 */
16var playlists = {
17 'googleio' : {
18 'ids': ["734A052F802C96B9"]
19 },
20 'about' : {
21 'ids': ["D7C64411AF40DEA5","611F8C5DBF49CEC6"]
22 },
23 'developertips' : {
24 'ids': ["43E15866EF0033A2"]
25 },
26 'developersandbox' : {
27 'ids': ["77426907BBAD558E"]
28 }
29};
30
31/* Some playlists include the title in the description meta-data, so we need to account for this when building the thumbnail lists, so we don't show the title twice
32 * This string is read via indexOf(), so multiple IDs need only be comma-separated in this string.
33 */
34var playlistsWithTitleInDescription = "734A052F802C96B9";
35
Scott Mainc9ac1072010-10-25 13:45:35 -070036/* This 'featured' object defines the Feature Videos list.
Scott Main1e9129d2009-07-15 15:38:19 -070037 * Each playlist ID is paired with a custom video description.
38 */
39var featured = {
Scott Main5eba0e92011-05-16 10:18:06 -070040// Android Development Tools
41 'Oq05KqjXTvs' : "The team behind the Android Development Tools demonstrate several powerful features for app development, including new capabilities in the Eclipse layout editor.",
42// Android UIs for phones and tablets
43 'WGIU2JX1U5Y' : "This talk from the Android UI team explains several design patterns that the team recommends you use when designing your application for screens of all sizes.",
44// Android Protips
45 'twmuBbC_oB8' : "In this talk, you'll learn how to create a well polished app that abides by several key virtues, using advanced development techniques and some lesser known APIs."
Scott Main1e9129d2009-07-15 15:38:19 -070046};
Scott Mainc9ac1072010-10-25 13:45:35 -070047
Scott Main1e9129d2009-07-15 15:38:19 -070048/* When an event on the browser history occurs (back, forward, load),
Scott Mainc9ac1072010-10-25 13:45:35 -070049 * load the video found in the URL hash
50 */
51$(window).history(function(e, hash) {
52 if (location.href.indexOf("#v=") != -1) {
53 videoId = location.href.split("#v=");
54 clickVideo(videoId[1]); // click the link with a matching class
55 }
Scott Main1e9129d2009-07-15 15:38:19 -070056});
57
58/* Load a video into the player box.
59 * @param id The YouTube video ID
60 * @param title The video title to display in the player box (character escaped)
Scott Mainc9ac1072010-10-25 13:45:35 -070061 * @param autoplay Whether to automatically play the video
Scott Main1e9129d2009-07-15 15:38:19 -070062 */
63function loadVideo(id, title, autoplay) {
64 if($("." + id).hasClass("noplay")) {
Scott Main432fbcc2011-05-11 20:14:42 -070065 //console.log("noplay");
Scott Main1e9129d2009-07-15 15:38:19 -070066 autoplay = false;
67 $("." + id).removeClass("noplay");
68 }
Scott Mainc9ac1072010-10-25 13:45:35 -070069 swfobject.embedSWF('http://www.youtube.com/v/' + id + '&rel=1&border=0&fs=1&autoplay=' +
Scott Main1e9129d2009-07-15 15:38:19 -070070 (autoplay?1:0), 'player', '500', '334', '9.0.0', false, false, {allowfullscreen: 'true'});
71 $("#videoPlayerTitle").html("<h2>" + unescape(title) + "</h2>");
Scott Mainc9ac1072010-10-25 13:45:35 -070072
Scott Main1e9129d2009-07-15 15:38:19 -070073 $.history.add('v=' + id); // add the current video to the browser history
Scott Mainc9ac1072010-10-25 13:45:35 -070074 document.getElementById("doc-content").scrollTop = 0; // scroll the window to the top
Scott Main1e9129d2009-07-15 15:38:19 -070075}
76
77/* Draw all videos from a playlist into a 'videoPreviews' list
78 * @param data The feed data returned from the youtube request
79 */
Scott Mainc9ac1072010-10-25 13:45:35 -070080function renderPlaylist(data) {
Scott Main1e9129d2009-07-15 15:38:19 -070081 var MAX_DESC_LENGTH = 390; // the length at which we will trim the description
82 var feed = data.feed;
83 var entries = feed.entry || [];
84 var playlistId = feed.yt$playlistId.$t;
Scott Mainc9ac1072010-10-25 13:45:35 -070085
Scott Main1e9129d2009-07-15 15:38:19 -070086 var ul = $('<ul class="videoPreviews" />');
Scott Mainc9ac1072010-10-25 13:45:35 -070087
Scott Main1e9129d2009-07-15 15:38:19 -070088 // Loop through each entry (each video) and add it to the 'videoPreviews' list
89 for (var i = 0; i < entries.length; i++) {
90 var entry = entries[i];
Scott Mainc9ac1072010-10-25 13:45:35 -070091
Scott Main1e9129d2009-07-15 15:38:19 -070092 var title = entry.title.$t;
93 var id = entry.media$group.yt$videoid.$t;
94 var thumbUrl = entry.media$group.media$thumbnail[0].url;
95 var fullDescription = entry.media$group.media$description.$t;
96 var playerUrl = entry.media$group.media$content[0].url;
Scott Mainc9ac1072010-10-25 13:45:35 -070097
Scott Main1e9129d2009-07-15 15:38:19 -070098 // Check whether this playlist includes the video title inside the description meta-data, so we can remove it
99 if (playlistsWithTitleInDescription.indexOf(playlistId) != -1) {
100 var lines = fullDescription.split("\n");
Elliott Hughes7f877062009-07-30 17:00:34 -0700101 // If the first line includes the first 17 chars from the title, let's use the title from the description instead (because it's a more complete title)
Scott Main1e9129d2009-07-15 15:38:19 -0700102 // This accounts for, literally, "Google I/O 2009 -", which is (so far) the min AND max for properly identifying a title in the only playlist with titles in the description
Scott Mainc9ac1072010-10-25 13:45:35 -0700103 if (lines[0].indexOf(title.slice(0,16)) != -1) {
104 h3Title = "<h3>" + lines[0] + "</h3>";
Scott Main1e9129d2009-07-15 15:38:19 -0700105 if (lines[2].length < 30) lines = lines.slice(3); // also, if the second line is very short (the speaker name), slice it out too
106 else lines = lines.slice(1); // otherwise, slice after the first line
107 }
108 fullDescription = lines.join("");
Scott Mainc9ac1072010-10-25 13:45:35 -0700109 }
110
Scott Main1e9129d2009-07-15 15:38:19 -0700111 var shortDescription = fullDescription.substr(0, MAX_DESC_LENGTH);
112 shortDescription += shortDescription.length == MAX_DESC_LENGTH ? "..." : ""; // add ellipsis if we've chopped the description
Scott Mainc9ac1072010-10-25 13:45:35 -0700113
Scott Main1e9129d2009-07-15 15:38:19 -0700114 var img = $('<img src="' + thumbUrl + '" width="120" height="90"/>');
115 var a = $('<a class="' + id + '" href="#" onclick="loadVideo(\'' + id + '\',\'' + escape(title) + '\',true); return setSelected(this);" />');
116 var pShortDescription = $('<p class="short">' + shortDescription + '</p>');
117 var pFullDescription = $('<p class="full">' + fullDescription + '</p>');
118 var h3Title = "<h3>" + title + "</h3>";
119 var pToggle = "<p class='toggle'><a href='#' onclick='return toggleDescription(this)'><span class='more'>more</span><span class='less'>less</span></a></p>";
120 var li = $('<li/>');
Scott Mainc9ac1072010-10-25 13:45:35 -0700121
Scott Main1e9129d2009-07-15 15:38:19 -0700122 li.append(a);
123 a.append(img).append(h3Title).append(pShortDescription);
Scott Mainc9ac1072010-10-25 13:45:35 -0700124
Scott Main1e9129d2009-07-15 15:38:19 -0700125 // Add the full description and "more/less" toggle, if necessary
126 if (fullDescription.length > MAX_DESC_LENGTH) {
127 a.append(pFullDescription);
128 li.append(pToggle);
129 }
Scott Mainc9ac1072010-10-25 13:45:35 -0700130
Scott Main1e9129d2009-07-15 15:38:19 -0700131 ul.append(li);
132 }
Scott Mainc9ac1072010-10-25 13:45:35 -0700133
Scott Main1e9129d2009-07-15 15:38:19 -0700134 // Now add the 'videoPreviews' list to the page, and be sure we put it in the right tab
135 // This is the part that allows us to put multiple playlists in one tab
136 for (var x in playlists) {
137 var ids = playlists[x].ids;
138 for (var i in ids) {
139 if (ids[i] == playlistId) {
140 $("#"+x+"Box").append(ul);
141 break;
142 }
143 }
Scott Mainc9ac1072010-10-25 13:45:35 -0700144 }
Scott Main1e9129d2009-07-15 15:38:19 -0700145}
146
Scott Mainc9ac1072010-10-25 13:45:35 -0700147/* Draw a featured video into the existing 'videoPreviews' list
Scott Main1e9129d2009-07-15 15:38:19 -0700148 * @param data The video data returned from the youtube request
149 */
Scott Mainc9ac1072010-10-25 13:45:35 -0700150function renderFeatured(data) {
Scott Main1e9129d2009-07-15 15:38:19 -0700151 var MAX_TITLE_LENGTH = 48;
152 var entry = data.entry || [];
153 var id = entry.media$group.yt$videoid.$t;
154 var description = featured[id];
155 var title = entry.title.$t;
156 var thumbUrl = entry.media$group.media$thumbnail[0].url;
157 var playerUrl = entry.media$group.media$content[0].url;
Scott Mainc9ac1072010-10-25 13:45:35 -0700158
Scott Main1e9129d2009-07-15 15:38:19 -0700159 var ellipsis = title.length > MAX_TITLE_LENGTH ? "..." : "";
Scott Mainc9ac1072010-10-25 13:45:35 -0700160
Scott Main1e9129d2009-07-15 15:38:19 -0700161 var h3Title = "<h3>"+ title.substr(0,MAX_TITLE_LENGTH) + ellipsis + "</h3>";
162 var img = $('<img src="' + thumbUrl + '" width="120" height="90"/>');
163 var p = $('<p>' + description + '</p>');
164 var a = $('<a class="' + id + '" href="#" onclick="loadVideo(\'' + id + '\',\'' + title + '\',true); return setSelected(this);" />');
165 var li = $("<li/>");
Scott Mainc9ac1072010-10-25 13:45:35 -0700166
Scott Main1e9129d2009-07-15 15:38:19 -0700167 a.append(h3Title).append(img).append(p);
168 li.append(a);
169
170 $("#mainBodyRight .videoPreviews").append(li);
171}
172
173/* Request the playlist feeds from YouTube */
174function showPlaylists() {
175 for (var x in playlists) {
176 var ids = playlists[x].ids;
177 for (var i in ids) {
Scott Mainc9ac1072010-10-25 13:45:35 -0700178 var script = "<script type='text/javascript' src='http://gdata.youtube.com/feeds/api/playlists/"
179 + ids[i] +
Scott Main5eba0e92011-05-16 10:18:06 -0700180 "?v=2&alt=json-in-script&max-results=50&callback=renderPlaylist'><\/script>";
Scott Main1e9129d2009-07-15 15:38:19 -0700181 $("body").append(script);
182 }
183 }
184}
185
186/* Request the featured videos from YouTube */
187function showFeatured() {
188 for (var id in featured) {
Scott Mainc9ac1072010-10-25 13:45:35 -0700189 var script = "<script type='text/javascript' src='http://gdata.youtube.com/feeds/api/videos/"
190 + id +
Scott Main1e9129d2009-07-15 15:38:19 -0700191 "?v=2&alt=json-in-script&callback=renderFeatured'><\/script>";
192 $("body").append(script);
193 }
194}
195
Scott Mainc9ac1072010-10-25 13:45:35 -0700196/* Reveal a tab (playlist) box
Scott Main1e9129d2009-07-15 15:38:19 -0700197 * @param name The name of the tab
198 */
199function showBox(name) {
200 $("#"+name+"Box").addClass("selected").siblings().removeClass("selected");
201 $("#"+name+"Tab").addClass("selected").siblings().removeClass("selected");
202 return false;
203}
204
Scott Mainc9ac1072010-10-25 13:45:35 -0700205/* Highlight a video thumbnail, including all duplicates that there may be
Scott Main1e9129d2009-07-15 15:38:19 -0700206 * @param link The link <a> object that was clicked
207 */
208function setSelected(link) {
209 var videoId = $(link).attr("class");
210 if (videoId.indexOf("selected") != -1) { // this means this video is already selected and playing, so bail out
211 return false;
212 }
213 $(".videoPreviews .selected").removeClass("selected");
214 $("a." + videoId).addClass("selected").each( function (i) {
215 if ($(this).is(":hidden")) {
216 var boxName = $(this).parent().parent().parent().attr("id").split("Box");
217 $("#"+boxName[0]+"Tab a").click();
218 }
219 });
220 return false;
221}
222
Scott Mainc9ac1072010-10-25 13:45:35 -0700223/* Reveal and hide the long/short descriptions for a video in the playlist
224 * @param link The link <a> object that was clicked
Scott Main1e9129d2009-07-15 15:38:19 -0700225 */
226function toggleDescription(link) {
227 var aToggle = $(link);
228 $("span", aToggle).toggle();
229 var aDescription = $(">a", aToggle.parent().parent());
230 $("p.short", aDescription).toggle();
231 $("p.full", aDescription).toggle();
232 if ($("span.less", aToggle).is(":visible")) {
233 aDescription.css("height", "auto");
234 } else {
235 aDescription.css("height", "90px");
236 }
237 return false;
238}
239
240/* Add actions to the page onload event so that we load a video right away */
Scott Mainc9ac1072010-10-25 13:45:35 -0700241addLoadEvent(function () {
242 // if there's a video url in the hash, click that video
243 if (location.href.indexOf("#v=") != -1) {
Scott Main1e9129d2009-07-15 15:38:19 -0700244 var videoId = location.href.split("#v=");
245 clickVideo(videoId[1]);
246 } else { // otherwise, click the default video
247 clickDefaultVideo();
248 }
249});
250
251
252var clickVideoAttempts = 0; // Used with clickVideo()
253
Scott Mainc9ac1072010-10-25 13:45:35 -0700254/* Click a video in order to load it and select it
Scott Main1e9129d2009-07-15 15:38:19 -0700255 * @param videoId The ID of the video to click
256 */
257function clickVideo(videoId) {
Scott Main432fbcc2011-05-11 20:14:42 -0700258 if (!isAlphaNumeric(videoId)) {
259 clickDefaultVideo();
260 return;
261 }
262
Scott Main1e9129d2009-07-15 15:38:19 -0700263 if ($("." + videoId).length != 0) { // if we find the video, click it and return
Scott Main432fbcc2011-05-11 20:14:42 -0700264 $("." + videoId).addClass("noplay"); // add class to indicate we should NOT autoplay (class removed by loadVideo)
265 $("." + videoId + ":first").click();
266 return;
Scott Main1e9129d2009-07-15 15:38:19 -0700267 } else { // if we don't find it, increment clickVideoAttempts
Scott Main432fbcc2011-05-11 20:14:42 -0700268 console.log("video NOT found: " + videoId);
269 clickVideoAttempts++;
Scott Main1e9129d2009-07-15 15:38:19 -0700270 }
Scott Mainc9ac1072010-10-25 13:45:35 -0700271
272 // if we don't find it after 20 attempts (2 seconds), click the first feature video
Scott Main1e9129d2009-07-15 15:38:19 -0700273 if (clickVideoAttempts > 10) {
Scott Main432fbcc2011-05-11 20:14:42 -0700274 console.log("video never found, clicking default...");
Scott Main1e9129d2009-07-15 15:38:19 -0700275 clickVideoAttempts = 0;
276 clickDefaultVideo();
277 } else { // try again after 100 milliseconds
Scott Main432fbcc2011-05-11 20:14:42 -0700278 setTimeout('clickVideo("' + videoId + '")', 100);
279 }
280}
281
282/* returns true if the provided text is alphanumeric, false otherwise
283 TODO: move this to the dev site js library */
284function isAlphaNumeric(text){
285 var regex=/^[0-9A-Za-z]+$/; //^[a-zA-z]+$/
286 if(regex.test(text)){
287 return true;
288 } else {
289 console.log("Bogus video ID");
290 return false;
Scott Main1e9129d2009-07-15 15:38:19 -0700291 }
292}
293
294/* Click the default video that should be loaded on page load (the first video in the featured list) */
295function clickDefaultVideo() {
Scott Main432fbcc2011-05-11 20:14:42 -0700296 if ($("#mainBodyRight .videoPreviews a:first").length != 0) {
297 var videoId = $("#mainBodyRight .videoPreviews a:first").attr("class");
Scott Mainc9ac1072010-10-25 13:45:35 -0700298 $("." + videoId).addClass("noplay"); // add class to indicate we should NOT autoplay (class removed by loadVideo)
Scott Main432fbcc2011-05-11 20:14:42 -0700299 $("." + videoId + ":first").click();
300 return;
Scott Main1e9129d2009-07-15 15:38:19 -0700301 } else { // if we don't find it, increment clickVideoAttempts
Scott Main432fbcc2011-05-11 20:14:42 -0700302 console.log("default video NOT found");
303 clickVideoAttempts++;
Scott Main1e9129d2009-07-15 15:38:19 -0700304 }
Scott Mainc9ac1072010-10-25 13:45:35 -0700305
306 // if we don't find it after 50 attempts (5 seconds), just fail
Scott Main1e9129d2009-07-15 15:38:19 -0700307 if (clickVideoAttempts > 50) {
Scott Main432fbcc2011-05-11 20:14:42 -0700308 console.log("default video never found...");
Scott Main1e9129d2009-07-15 15:38:19 -0700309 } else { // try again after 100 milliseconds
Scott Main432fbcc2011-05-11 20:14:42 -0700310 setTimeout('clickDefaultVideo()', 100);
Scott Main1e9129d2009-07-15 15:38:19 -0700311 }
312}
313</script>
314
315 <div id="mainBodyFixed">
Scott Mainc9ac1072010-10-25 13:45:35 -0700316
317 <div id="mainBodyLeft" class="videoPlayer" >
Scott Main1e9129d2009-07-15 15:38:19 -0700318 <div id="videoPlayerBox">
319 <div id="videoBorder">
320 <div id="videoPlayerTitle"></div>
321 <div id="objectWrapper">
322 <object id="player"></object>
323 </div>
324 </div>
325 </div>
326 </div><!-- end mainBodyLeft -->
Scott Mainc9ac1072010-10-25 13:45:35 -0700327
Scott Main1e9129d2009-07-15 15:38:19 -0700328 <div id="mainBodyRight" class="videoPlayer">
329 <h2>Featured Videos</h2>
330 <ul class="videoPreviews"></ul>
331 </div><!-- end mainBodyRight -->
Scott Mainc9ac1072010-10-25 13:45:35 -0700332
Scott Main1e9129d2009-07-15 15:38:19 -0700333 <ul id="videoTabs">
334 <li id="aboutTab" class="selected"><a onclick="return showBox('about');" href="#">About the Platform</a></li>
335 <li id="developertipsTab"><a onclick="return showBox('developertips');" href="#">Developer Tips</a></li>
336 <li id="googleioTab"><a onclick="return showBox('googleio');" href="#">Google I/O Sessions</a></li>
337 <li id="developersandboxTab"><a onclick="return showBox('developersandbox');" href="#">Developer Sandbox</a></li>
338 </ul>
Scott Mainc9ac1072010-10-25 13:45:35 -0700339
Scott Main1e9129d2009-07-15 15:38:19 -0700340 <div id="videos">
341 <div id="aboutBox" class="selected"></div>
342 <div id="developertipsBox"></div>
343 <div id="googleioBox"></div>
344 <div id="developersandboxBox"></div>
345 </div>
Scott Mainc9ac1072010-10-25 13:45:35 -0700346
Scott Main1e9129d2009-07-15 15:38:19 -0700347 </div><!-- end mainBodyFixed -->
Scott Mainc9ac1072010-10-25 13:45:35 -0700348
Scott Main1e9129d2009-07-15 15:38:19 -0700349<script type="text/javascript">
350// Initialization actions
351showFeatured(); // load featured videos
Elliott Hughes7f877062009-07-30 17:00:34 -0700352showPlaylists(); // load playlists
Scott Main1e9129d2009-07-15 15:38:19 -0700353</script>
354
Scott Mainc9ac1072010-10-25 13:45:35 -0700355