blob: ddb9f861fae2ebc030510a678b0dde8f2be584a2 [file] [log] [blame]
Scott Main1e9129d2009-07-15 15:38:19 -07001videos=true
2page.title=Videos
3@jd:body
4
5<script src="http://swfobject.googlecode.com/svn/trunk/swfobject/swfobject.js" type="text/javascript"></script>
6<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
36/* This 'featured' object defines the Feature Videos list.
37 * Each playlist ID is paired with a custom video description.
38 */
39var featured = {
Scott Main94443322009-09-11 09:39:40 -070040// Android 1.6 Release
41 'MBRFkLKRwFw' : "The Android 1.6 release includes new features and improvements to the Android platform. Here's an introduction to what's new in Android 1.6.",
Scott Main1e9129d2009-07-15 15:38:19 -070042// How to Make your Android UI Fast..
43 'N6YdwzAvwOA' : "Make your user interface fast, with more efficient AdapterViews, better bitmap scaling, faster redrawing, ViewStub layouts, fewer Views, and more.",
44// Coding for Life: Battery Life
Scott Main94443322009-09-11 09:39:40 -070045// 'OUemfrKe65c' : "Learn what kinds of operations consume the most battery and how you can reduce your usage, with tips for parsing and zipping data, using wakelocks, and running a Service.",
Scott Main1e9129d2009-07-15 15:38:19 -070046// How Do I Code Thee?
47 'GARMe7Km_gk' : "If you'd like to augment your Android applications with pieces written in JavaScript or native code, watch this video."
48};
49
50/* When an event on the browser history occurs (back, forward, load),
51 * load the video found in the URL hash
52 */
53$(window).history(function(e, hash) {
54 if (location.href.indexOf("#v=") != -1) {
55 videoId = location.href.split("#v=");
56 clickVideo(videoId[1]); // click the link with a matching class
57 }
58});
59
60/* Load a video into the player box.
61 * @param id The YouTube video ID
62 * @param title The video title to display in the player box (character escaped)
63 * @param autoplay Whether to automatically play the video
64 */
65function loadVideo(id, title, autoplay) {
66 if($("." + id).hasClass("noplay")) {
67 console.log("noplay");
68 autoplay = false;
69 $("." + id).removeClass("noplay");
70 }
71 swfobject.embedSWF('http://www.youtube.com/v/' + id + '&rel=1&border=0&fs=1&autoplay=' +
72 (autoplay?1:0), 'player', '500', '334', '9.0.0', false, false, {allowfullscreen: 'true'});
73 $("#videoPlayerTitle").html("<h2>" + unescape(title) + "</h2>");
74
75 $.history.add('v=' + id); // add the current video to the browser history
76 document.getElementById("doc-content").scrollTop = 0; // scroll the window to the top
77}
78
79/* Draw all videos from a playlist into a 'videoPreviews' list
80 * @param data The feed data returned from the youtube request
81 */
82function renderPlaylist(data) {
83 var MAX_DESC_LENGTH = 390; // the length at which we will trim the description
84 var feed = data.feed;
85 var entries = feed.entry || [];
86 var playlistId = feed.yt$playlistId.$t;
87
88 var ul = $('<ul class="videoPreviews" />');
89
90 // Loop through each entry (each video) and add it to the 'videoPreviews' list
91 for (var i = 0; i < entries.length; i++) {
92 var entry = entries[i];
93
94 var title = entry.title.$t;
95 var id = entry.media$group.yt$videoid.$t;
96 var thumbUrl = entry.media$group.media$thumbnail[0].url;
97 var fullDescription = entry.media$group.media$description.$t;
98 var playerUrl = entry.media$group.media$content[0].url;
99
100 // Check whether this playlist includes the video title inside the description meta-data, so we can remove it
101 if (playlistsWithTitleInDescription.indexOf(playlistId) != -1) {
102 var lines = fullDescription.split("\n");
103 // If the first line includes the first 17 chars from the title, let's use the title from the desciption instead (because it's a more complete title)
104 // 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
105 if (lines[0].indexOf(title.slice(0,16)) != -1) {
106 h3Title = "<h3>" + lines[0] + "</h3>";
107 if (lines[2].length < 30) lines = lines.slice(3); // also, if the second line is very short (the speaker name), slice it out too
108 else lines = lines.slice(1); // otherwise, slice after the first line
109 }
110 fullDescription = lines.join("");
111 }
112
113 var shortDescription = fullDescription.substr(0, MAX_DESC_LENGTH);
114 shortDescription += shortDescription.length == MAX_DESC_LENGTH ? "..." : ""; // add ellipsis if we've chopped the description
115
116 var img = $('<img src="' + thumbUrl + '" width="120" height="90"/>');
117 var a = $('<a class="' + id + '" href="#" onclick="loadVideo(\'' + id + '\',\'' + escape(title) + '\',true); return setSelected(this);" />');
118 var pShortDescription = $('<p class="short">' + shortDescription + '</p>');
119 var pFullDescription = $('<p class="full">' + fullDescription + '</p>');
120 var h3Title = "<h3>" + title + "</h3>";
121 var pToggle = "<p class='toggle'><a href='#' onclick='return toggleDescription(this)'><span class='more'>more</span><span class='less'>less</span></a></p>";
122 var li = $('<li/>');
123
124 li.append(a);
125 a.append(img).append(h3Title).append(pShortDescription);
126
127 // Add the full description and "more/less" toggle, if necessary
128 if (fullDescription.length > MAX_DESC_LENGTH) {
129 a.append(pFullDescription);
130 li.append(pToggle);
131 }
132
133 ul.append(li);
134 }
135
136 // Now add the 'videoPreviews' list to the page, and be sure we put it in the right tab
137 // This is the part that allows us to put multiple playlists in one tab
138 for (var x in playlists) {
139 var ids = playlists[x].ids;
140 for (var i in ids) {
141 if (ids[i] == playlistId) {
142 $("#"+x+"Box").append(ul);
143 break;
144 }
145 }
146 }
147}
148
149/* Draw a featured video into the existing 'videoPreviews' list
150 * @param data The video data returned from the youtube request
151 */
152function renderFeatured(data) {
153 var MAX_TITLE_LENGTH = 48;
154 var entry = data.entry || [];
155 var id = entry.media$group.yt$videoid.$t;
156 var description = featured[id];
157 var title = entry.title.$t;
158 var thumbUrl = entry.media$group.media$thumbnail[0].url;
159 var playerUrl = entry.media$group.media$content[0].url;
160
161 var ellipsis = title.length > MAX_TITLE_LENGTH ? "..." : "";
162
163 var h3Title = "<h3>"+ title.substr(0,MAX_TITLE_LENGTH) + ellipsis + "</h3>";
164 var img = $('<img src="' + thumbUrl + '" width="120" height="90"/>');
165 var p = $('<p>' + description + '</p>');
166 var a = $('<a class="' + id + '" href="#" onclick="loadVideo(\'' + id + '\',\'' + title + '\',true); return setSelected(this);" />');
167 var li = $("<li/>");
168
169 a.append(h3Title).append(img).append(p);
170 li.append(a);
171
172 $("#mainBodyRight .videoPreviews").append(li);
173}
174
175/* Request the playlist feeds from YouTube */
176function showPlaylists() {
177 for (var x in playlists) {
178 var ids = playlists[x].ids;
179 for (var i in ids) {
180 var script = "<script type='text/javascript' src='http://gdata.youtube.com/feeds/api/playlists/"
181 + ids[i] +
182 "?v=2&alt=json-in-script&callback=renderPlaylist'><\/script>";
183 $("body").append(script);
184 }
185 }
186}
187
188/* Request the featured videos from YouTube */
189function showFeatured() {
190 for (var id in featured) {
191 var script = "<script type='text/javascript' src='http://gdata.youtube.com/feeds/api/videos/"
192 + id +
193 "?v=2&alt=json-in-script&callback=renderFeatured'><\/script>";
194 $("body").append(script);
195 }
196}
197
198/* Reveal a tab (playlist) box
199 * @param name The name of the tab
200 */
201function showBox(name) {
202 $("#"+name+"Box").addClass("selected").siblings().removeClass("selected");
203 $("#"+name+"Tab").addClass("selected").siblings().removeClass("selected");
204 return false;
205}
206
207/* Highlight a video thumbnail, including all duplicates that there may be
208 * @param link The link <a> object that was clicked
209 */
210function setSelected(link) {
211 var videoId = $(link).attr("class");
212 if (videoId.indexOf("selected") != -1) { // this means this video is already selected and playing, so bail out
213 return false;
214 }
215 $(".videoPreviews .selected").removeClass("selected");
216 $("a." + videoId).addClass("selected").each( function (i) {
217 if ($(this).is(":hidden")) {
218 var boxName = $(this).parent().parent().parent().attr("id").split("Box");
219 $("#"+boxName[0]+"Tab a").click();
220 }
221 });
222 return false;
223}
224
225/* Reveal and hide the long/short descriptions for a video in the playlist
226 * @param link The link <a> object that was clicked
227 */
228function toggleDescription(link) {
229 var aToggle = $(link);
230 $("span", aToggle).toggle();
231 var aDescription = $(">a", aToggle.parent().parent());
232 $("p.short", aDescription).toggle();
233 $("p.full", aDescription).toggle();
234 if ($("span.less", aToggle).is(":visible")) {
235 aDescription.css("height", "auto");
236 } else {
237 aDescription.css("height", "90px");
238 }
239 return false;
240}
241
242/* Add actions to the page onload event so that we load a video right away */
243addLoadEvent(function () {
244 // if there's a video url in the hash, click that video
245 if (location.href.indexOf("#v=") != -1) {
246 var videoId = location.href.split("#v=");
247 clickVideo(videoId[1]);
248 } else { // otherwise, click the default video
249 clickDefaultVideo();
250 }
251});
252
253
254var clickVideoAttempts = 0; // Used with clickVideo()
255
256/* Click a video in order to load it and select it
257 * @param videoId The ID of the video to click
258 */
259function clickVideo(videoId) {
260 if ($("." + videoId).length != 0) { // if we find the video, click it and return
261 $("." + videoId).addClass("noplay"); // add class to indicate we should NOT autoplay (class removed by loadVideo)
262 $("." + videoId + ":first").click();
263 return;
264 } else { // if we don't find it, increment clickVideoAttempts
265 console.log("video NOT found: " + videoId);
266 clickVideoAttempts++;
267 }
268
269 // if we don't find it after 20 attempts (2 seconds), click the first feature video
270 if (clickVideoAttempts > 10) {
271 console.log("video never found, clicking default...");
272 clickVideoAttempts = 0;
273 clickDefaultVideo();
274 } else { // try again after 100 milliseconds
275 setTimeout('clickVideo("'+videoId+'")', 100);
276 }
277}
278
279/* Click the default video that should be loaded on page load (the first video in the featured list) */
280function clickDefaultVideo() {
281 if ($("#mainBodyRight .videoPreviews a:first").length != 0) {
282 var videoId = $("#mainBodyRight .videoPreviews a:first").attr("class");
283 $("." + videoId).addClass("noplay"); // add class to indicate we should NOT autoplay (class removed by loadVideo)
284 $("." + videoId + ":first").click();
285 return;
286 } else { // if we don't find it, increment clickVideoAttempts
287 console.log("default video NOT found");
288 clickVideoAttempts++;
289 }
290
291 // if we don't find it after 50 attempts (5 seconds), just fail
292 if (clickVideoAttempts > 50) {
293 console.log("default video never found...");
294 } else { // try again after 100 milliseconds
295 setTimeout('clickDefaultVideo()', 100);
296 }
297}
298</script>
299
300 <div id="mainBodyFixed">
301
302 <div id="mainBodyLeft" class="videoPlayer" >
303 <div id="videoPlayerBox">
304 <div id="videoBorder">
305 <div id="videoPlayerTitle"></div>
306 <div id="objectWrapper">
307 <object id="player"></object>
308 </div>
309 </div>
310 </div>
311 </div><!-- end mainBodyLeft -->
312
313 <div id="mainBodyRight" class="videoPlayer">
314 <h2>Featured Videos</h2>
315 <ul class="videoPreviews"></ul>
316 </div><!-- end mainBodyRight -->
317
318 <ul id="videoTabs">
319 <li id="aboutTab" class="selected"><a onclick="return showBox('about');" href="#">About the Platform</a></li>
320 <li id="developertipsTab"><a onclick="return showBox('developertips');" href="#">Developer Tips</a></li>
321 <li id="googleioTab"><a onclick="return showBox('googleio');" href="#">Google I/O Sessions</a></li>
322 <li id="developersandboxTab"><a onclick="return showBox('developersandbox');" href="#">Developer Sandbox</a></li>
323 </ul>
324
325 <div id="videos">
326 <div id="aboutBox" class="selected"></div>
327 <div id="developertipsBox"></div>
328 <div id="googleioBox"></div>
329 <div id="developersandboxBox"></div>
330 </div>
331
332 </div><!-- end mainBodyFixed -->
333
334<script type="text/javascript">
335// Initialization actions
336showFeatured(); // load featured videos
337showPlaylists(); // load playslists
338</script>
339
340