blob: 12221ebc14b90761f5f86aeccb5749bdb36421db [file] [log] [blame]
Scott Maine4d8f1b2012-06-21 18:03:05 -07001var classesNav;
2var devdocNav;
3var sidenav;
4var cookie_namespace = 'android_developer';
5var NAV_PREF_TREE = "tree";
6var NAV_PREF_PANELS = "panels";
7var nav_pref;
Scott Maine4d8f1b2012-06-21 18:03:05 -07008var isMobile = false; // true if mobile, so we can adjust some layout
Scott Mainf6145542013-04-01 16:38:11 -07009var mPagePath; // initialized in ready() function
Scott Maine4d8f1b2012-06-21 18:03:05 -070010
Scott Main1b3db112012-07-03 14:06:22 -070011var basePath = getBaseUri(location.pathname);
12var SITE_ROOT = toRoot + basePath.substring(1,basePath.indexOf("/",1));
Scott Main7e447ed2013-02-19 17:22:37 -080013var GOOGLE_DATA; // combined data for google service apis, used for search suggest
Scott Main3b90aff2013-08-01 18:09:35 -070014
Scott Main25e73002013-03-27 15:24:06 -070015// Ensure that all ajax getScript() requests allow caching
16$.ajaxSetup({
17 cache: true
18});
Scott Maine4d8f1b2012-06-21 18:03:05 -070019
20/****** ON LOAD SET UP STUFF *********/
21
22var navBarIsFixed = false;
23$(document).ready(function() {
Scott Main7e447ed2013-02-19 17:22:37 -080024
Scott Main0e76e7e2013-03-12 10:24:07 -070025 // load json file for JD doc search suggestions
26 $.getScript(toRoot + 'reference/jd_lists.js');
Scott Main7e447ed2013-02-19 17:22:37 -080027 // load json file for Android API search suggestions
28 $.getScript(toRoot + 'reference/lists.js');
29 // load json files for Google services API suggestions
Scott Main9f2971d2013-02-26 13:07:41 -080030 $.getScript(toRoot + 'reference/gcm_lists.js', function(data, textStatus, jqxhr) {
Scott Main7e447ed2013-02-19 17:22:37 -080031 // once the GCM json (GCM_DATA) is loaded, load the GMS json (GMS_DATA) and merge the data
32 if(jqxhr.status === 200) {
Scott Main9f2971d2013-02-26 13:07:41 -080033 $.getScript(toRoot + 'reference/gms_lists.js', function(data, textStatus, jqxhr) {
Scott Main7e447ed2013-02-19 17:22:37 -080034 if(jqxhr.status === 200) {
35 // combine GCM and GMS data
36 GOOGLE_DATA = GMS_DATA;
37 var start = GOOGLE_DATA.length;
38 for (var i=0; i<GCM_DATA.length; i++) {
39 GOOGLE_DATA.push({id:start+i, label:GCM_DATA[i].label,
40 link:GCM_DATA[i].link, type:GCM_DATA[i].type});
41 }
42 }
43 });
44 }
45 });
46
Scott Main0e76e7e2013-03-12 10:24:07 -070047 // setup keyboard listener for search shortcut
48 $('body').keyup(function(event) {
49 if (event.which == 191) {
50 $('#search_autocomplete').focus();
51 }
52 });
Scott Main015d6162013-01-29 09:01:52 -080053
Scott Maine4d8f1b2012-06-21 18:03:05 -070054 // init the fullscreen toggle click event
55 $('#nav-swap .fullscreen').click(function(){
56 if ($(this).hasClass('disabled')) {
57 toggleFullscreen(true);
58 } else {
59 toggleFullscreen(false);
60 }
61 });
Scott Main3b90aff2013-08-01 18:09:35 -070062
Scott Maine4d8f1b2012-06-21 18:03:05 -070063 // initialize the divs with custom scrollbars
64 $('.scroll-pane').jScrollPane( {verticalGutter:0} );
Scott Main3b90aff2013-08-01 18:09:35 -070065
Scott Maine4d8f1b2012-06-21 18:03:05 -070066 // add HRs below all H2s (except for a few other h2 variants)
Scott Maindb3678b2012-10-23 14:13:41 -070067 $('h2').not('#qv h2').not('#tb h2').not('.sidebox h2').not('#devdoc-nav h2').not('h2.norule').css({marginBottom:0}).after('<hr/>');
Scott Maine4d8f1b2012-06-21 18:03:05 -070068
69 // set up the search close button
70 $('.search .close').click(function() {
71 $searchInput = $('#search_autocomplete');
72 $searchInput.attr('value', '');
73 $(this).addClass("hide");
74 $("#search-container").removeClass('active');
75 $("#search_autocomplete").blur();
Scott Main0e76e7e2013-03-12 10:24:07 -070076 search_focus_changed($searchInput.get(), false);
77 hideResults();
Scott Maine4d8f1b2012-06-21 18:03:05 -070078 });
79
80 // Set up quicknav
Scott Main3b90aff2013-08-01 18:09:35 -070081 var quicknav_open = false;
Scott Maine4d8f1b2012-06-21 18:03:05 -070082 $("#btn-quicknav").click(function() {
83 if (quicknav_open) {
84 $(this).removeClass('active');
85 quicknav_open = false;
86 collapse();
87 } else {
88 $(this).addClass('active');
89 quicknav_open = true;
90 expand();
91 }
92 })
Scott Main3b90aff2013-08-01 18:09:35 -070093
Scott Maine4d8f1b2012-06-21 18:03:05 -070094 var expand = function() {
95 $('#header-wrap').addClass('quicknav');
96 $('#quicknav').stop().show().animate({opacity:'1'});
97 }
Scott Main3b90aff2013-08-01 18:09:35 -070098
Scott Maine4d8f1b2012-06-21 18:03:05 -070099 var collapse = function() {
100 $('#quicknav').stop().animate({opacity:'0'}, 100, function() {
101 $(this).hide();
102 $('#header-wrap').removeClass('quicknav');
103 });
104 }
Scott Main3b90aff2013-08-01 18:09:35 -0700105
106
Scott Maine4d8f1b2012-06-21 18:03:05 -0700107 //Set up search
108 $("#search_autocomplete").focus(function() {
109 $("#search-container").addClass('active');
110 })
111 $("#search-container").mouseover(function() {
112 $("#search-container").addClass('active');
113 $("#search_autocomplete").focus();
114 })
115 $("#search-container").mouseout(function() {
116 if ($("#search_autocomplete").is(":focus")) return;
117 if ($("#search_autocomplete").val() == '') {
118 setTimeout(function(){
119 $("#search-container").removeClass('active');
120 $("#search_autocomplete").blur();
121 },250);
122 }
123 })
124 $("#search_autocomplete").blur(function() {
125 if ($("#search_autocomplete").val() == '') {
126 $("#search-container").removeClass('active');
127 }
128 })
129
Scott Main3b90aff2013-08-01 18:09:35 -0700130
Scott Maine4d8f1b2012-06-21 18:03:05 -0700131 // prep nav expandos
132 var pagePath = document.location.pathname;
133 // account for intl docs by removing the intl/*/ path
134 if (pagePath.indexOf("/intl/") == 0) {
135 pagePath = pagePath.substr(pagePath.indexOf("/",6)); // start after intl/ to get last /
136 }
Scott Mainac2aef52013-02-12 14:15:23 -0800137
Scott Maine4d8f1b2012-06-21 18:03:05 -0700138 if (pagePath.indexOf(SITE_ROOT) == 0) {
139 if (pagePath == '' || pagePath.charAt(pagePath.length - 1) == '/') {
140 pagePath += 'index.html';
141 }
142 }
143
Scott Main01a25452013-02-12 17:32:27 -0800144 // Need a copy of the pagePath before it gets changed in the next block;
145 // it's needed to perform proper tab highlighting in offline docs (see rootDir below)
146 var pagePathOriginal = pagePath;
Scott Maine4d8f1b2012-06-21 18:03:05 -0700147 if (SITE_ROOT.match(/\.\.\//) || SITE_ROOT == '') {
148 // If running locally, SITE_ROOT will be a relative path, so account for that by
149 // finding the relative URL to this page. This will allow us to find links on the page
150 // leading back to this page.
151 var pathParts = pagePath.split('/');
152 var relativePagePathParts = [];
153 var upDirs = (SITE_ROOT.match(/(\.\.\/)+/) || [''])[0].length / 3;
154 for (var i = 0; i < upDirs; i++) {
155 relativePagePathParts.push('..');
156 }
157 for (var i = 0; i < upDirs; i++) {
158 relativePagePathParts.push(pathParts[pathParts.length - (upDirs - i) - 1]);
159 }
160 relativePagePathParts.push(pathParts[pathParts.length - 1]);
161 pagePath = relativePagePathParts.join('/');
162 } else {
163 // Otherwise the page path is already an absolute URL
164 }
165
Scott Mainac2aef52013-02-12 14:15:23 -0800166 // Highlight the header tabs...
167 // highlight Design tab
168 if ($("body").hasClass("design")) {
169 $("#header li.design a").addClass("selected");
170
171 // highlight Develop tab
172 } else if ($("body").hasClass("develop") || $("body").hasClass("google")) {
173 $("#header li.develop a").addClass("selected");
Scott Mainac2aef52013-02-12 14:15:23 -0800174 // In Develop docs, also highlight appropriate sub-tab
Scott Main01a25452013-02-12 17:32:27 -0800175 var rootDir = pagePathOriginal.substring(1,pagePathOriginal.indexOf('/', 1));
Scott Mainac2aef52013-02-12 14:15:23 -0800176 if (rootDir == "training") {
177 $("#nav-x li.training a").addClass("selected");
178 } else if (rootDir == "guide") {
179 $("#nav-x li.guide a").addClass("selected");
180 } else if (rootDir == "reference") {
181 // If the root is reference, but page is also part of Google Services, select Google
182 if ($("body").hasClass("google")) {
183 $("#nav-x li.google a").addClass("selected");
184 } else {
185 $("#nav-x li.reference a").addClass("selected");
186 }
187 } else if ((rootDir == "tools") || (rootDir == "sdk")) {
188 $("#nav-x li.tools a").addClass("selected");
189 } else if ($("body").hasClass("google")) {
190 $("#nav-x li.google a").addClass("selected");
Dirk Dougherty4f7e5152010-09-16 10:43:40 -0700191 } else if ($("body").hasClass("samples")) {
192 $("#nav-x li.samples a").addClass("selected");
Scott Mainac2aef52013-02-12 14:15:23 -0800193 }
194
195 // highlight Distribute tab
196 } else if ($("body").hasClass("distribute")) {
197 $("#header li.distribute a").addClass("selected");
198 }
199
Scott Mainf6145542013-04-01 16:38:11 -0700200 // set global variable so we can highlight the sidenav a bit later (such as for google reference)
201 // and highlight the sidenav
202 mPagePath = pagePath;
203 highlightSidenav();
Scott Mainac2aef52013-02-12 14:15:23 -0800204
Scott Mainf6145542013-04-01 16:38:11 -0700205 // set up prev/next links if they exist
Scott Maine4d8f1b2012-06-21 18:03:05 -0700206 var $selNavLink = $('#nav').find('a[href="' + pagePath + '"]');
Scott Main5a1123e2012-09-26 12:51:28 -0700207 var $selListItem;
Scott Maine4d8f1b2012-06-21 18:03:05 -0700208 if ($selNavLink.length) {
Scott Mainac2aef52013-02-12 14:15:23 -0800209 $selListItem = $selNavLink.closest('li');
Scott Maine4d8f1b2012-06-21 18:03:05 -0700210
211 // set up prev links
212 var $prevLink = [];
213 var $prevListItem = $selListItem.prev('li');
Scott Main3b90aff2013-08-01 18:09:35 -0700214
Scott Maine4d8f1b2012-06-21 18:03:05 -0700215 var crossBoundaries = ($("body.design").length > 0) || ($("body.guide").length > 0) ? true :
216false; // navigate across topic boundaries only in design docs
217 if ($prevListItem.length) {
218 if ($prevListItem.hasClass('nav-section')) {
Scott Main5a1123e2012-09-26 12:51:28 -0700219 // jump to last topic of previous section
220 $prevLink = $prevListItem.find('a:last');
221 } else if (!$selListItem.hasClass('nav-section')) {
Scott Maine4d8f1b2012-06-21 18:03:05 -0700222 // jump to previous topic in this section
223 $prevLink = $prevListItem.find('a:eq(0)');
224 }
225 } else {
226 // jump to this section's index page (if it exists)
227 var $parentListItem = $selListItem.parents('li');
228 $prevLink = $selListItem.parents('li').find('a');
Scott Main3b90aff2013-08-01 18:09:35 -0700229
Scott Maine4d8f1b2012-06-21 18:03:05 -0700230 // except if cross boundaries aren't allowed, and we're at the top of a section already
231 // (and there's another parent)
Scott Main3b90aff2013-08-01 18:09:35 -0700232 if (!crossBoundaries && $parentListItem.hasClass('nav-section')
Scott Maine4d8f1b2012-06-21 18:03:05 -0700233 && $selListItem.hasClass('nav-section')) {
234 $prevLink = [];
235 }
236 }
237
Scott Maine4d8f1b2012-06-21 18:03:05 -0700238 // set up next links
239 var $nextLink = [];
Scott Maine4d8f1b2012-06-21 18:03:05 -0700240 var startClass = false;
241 var training = $(".next-class-link").length; // decides whether to provide "next class" link
242 var isCrossingBoundary = false;
Scott Main3b90aff2013-08-01 18:09:35 -0700243
Scott Main1a00f7f2013-10-29 11:11:19 -0700244 if ($selListItem.hasClass('nav-section') && $selListItem.children('div.empty').length == 0) {
Scott Maine4d8f1b2012-06-21 18:03:05 -0700245 // we're on an index page, jump to the first topic
Scott Mainb505ca62012-07-26 18:00:14 -0700246 $nextLink = $selListItem.find('ul:eq(0)').find('a:eq(0)');
Scott Maine4d8f1b2012-06-21 18:03:05 -0700247
248 // if there aren't any children, go to the next section (required for About pages)
249 if($nextLink.length == 0) {
250 $nextLink = $selListItem.next('li').find('a');
Scott Mainb505ca62012-07-26 18:00:14 -0700251 } else if ($('.topic-start-link').length) {
252 // as long as there's a child link and there is a "topic start link" (we're on a landing)
253 // then set the landing page "start link" text to be the first doc title
254 $('.topic-start-link').text($nextLink.text().toUpperCase());
Scott Maine4d8f1b2012-06-21 18:03:05 -0700255 }
Scott Main3b90aff2013-08-01 18:09:35 -0700256
Scott Main5a1123e2012-09-26 12:51:28 -0700257 // If the selected page has a description, then it's a class or article homepage
258 if ($selListItem.find('a[description]').length) {
259 // this means we're on a class landing page
Scott Maine4d8f1b2012-06-21 18:03:05 -0700260 startClass = true;
261 }
262 } else {
263 // jump to the next topic in this section (if it exists)
264 $nextLink = $selListItem.next('li').find('a:eq(0)');
Scott Main1a00f7f2013-10-29 11:11:19 -0700265 if ($nextLink.length == 0) {
Scott Main5a1123e2012-09-26 12:51:28 -0700266 isCrossingBoundary = true;
267 // no more topics in this section, jump to the first topic in the next section
268 $nextLink = $selListItem.parents('li:eq(0)').next('li.nav-section').find('a:eq(0)');
269 if (!$nextLink.length) { // Go up another layer to look for next page (lesson > class > course)
270 $nextLink = $selListItem.parents('li:eq(1)').next('li.nav-section').find('a:eq(0)');
Scott Main1a00f7f2013-10-29 11:11:19 -0700271 if ($nextLink.length == 0) {
272 // if that doesn't work, we're at the end of the list, so disable NEXT link
273 $('.next-page-link').attr('href','').addClass("disabled")
274 .click(function() { return false; });
275 }
Scott Maine4d8f1b2012-06-21 18:03:05 -0700276 }
277 }
278 }
Scott Main5a1123e2012-09-26 12:51:28 -0700279
280 if (startClass) {
281 $('.start-class-link').attr('href', $nextLink.attr('href')).removeClass("hide");
282
Scott Main3b90aff2013-08-01 18:09:35 -0700283 // if there's no training bar (below the start button),
Scott Main5a1123e2012-09-26 12:51:28 -0700284 // then we need to add a bottom border to button
285 if (!$("#tb").length) {
286 $('.start-class-link').css({'border-bottom':'1px solid #DADADA'});
Scott Maine4d8f1b2012-06-21 18:03:05 -0700287 }
Scott Main5a1123e2012-09-26 12:51:28 -0700288 } else if (isCrossingBoundary && !$('body.design').length) { // Design always crosses boundaries
289 $('.content-footer.next-class').show();
290 $('.next-page-link').attr('href','')
291 .removeClass("hide").addClass("disabled")
292 .click(function() { return false; });
Scott Main1a00f7f2013-10-29 11:11:19 -0700293 if ($nextLink.length) {
294 $('.next-class-link').attr('href',$nextLink.attr('href'))
295 .removeClass("hide").append($nextLink.html());
296 $('.next-class-link').find('.new').empty();
297 }
Scott Main5a1123e2012-09-26 12:51:28 -0700298 } else {
299 $('.next-page-link').attr('href', $nextLink.attr('href')).removeClass("hide");
300 }
301
302 if (!startClass && $prevLink.length) {
303 var prevHref = $prevLink.attr('href');
304 if (prevHref == SITE_ROOT + 'index.html') {
305 // Don't show Previous when it leads to the homepage
306 } else {
307 $('.prev-page-link').attr('href', $prevLink.attr('href')).removeClass("hide");
308 }
Scott Main3b90aff2013-08-01 18:09:35 -0700309 }
Scott Main5a1123e2012-09-26 12:51:28 -0700310
311 // If this is a training 'article', there should be no prev/next nav
312 // ... if the grandparent is the "nav" ... and it has no child list items...
313 if (training && $selListItem.parents('ul').eq(1).is('[id="nav"]') &&
314 !$selListItem.find('li').length) {
315 $('.next-page-link,.prev-page-link').attr('href','').addClass("disabled")
316 .click(function() { return false; });
Scott Maine4d8f1b2012-06-21 18:03:05 -0700317 }
Scott Main3b90aff2013-08-01 18:09:35 -0700318
Scott Maine4d8f1b2012-06-21 18:03:05 -0700319 }
Scott Main3b90aff2013-08-01 18:09:35 -0700320
321
322
Scott Main5a1123e2012-09-26 12:51:28 -0700323 // Set up the course landing pages for Training with class names and descriptions
324 if ($('body.trainingcourse').length) {
325 var $classLinks = $selListItem.find('ul li a').not('#nav .nav-section .nav-section ul a');
326 var $classDescriptions = $classLinks.attr('description');
Scott Main3b90aff2013-08-01 18:09:35 -0700327
Scott Main5a1123e2012-09-26 12:51:28 -0700328 var $olClasses = $('<ol class="class-list"></ol>');
329 var $liClass;
330 var $imgIcon;
331 var $h2Title;
332 var $pSummary;
333 var $olLessons;
334 var $liLesson;
335 $classLinks.each(function(index) {
336 $liClass = $('<li></li>');
337 $h2Title = $('<a class="title" href="'+$(this).attr('href')+'"><h2>' + $(this).html()+'</h2><span></span></a>');
338 $pSummary = $('<p class="description">' + $(this).attr('description') + '</p>');
Scott Main3b90aff2013-08-01 18:09:35 -0700339
Scott Main5a1123e2012-09-26 12:51:28 -0700340 $olLessons = $('<ol class="lesson-list"></ol>');
Scott Main3b90aff2013-08-01 18:09:35 -0700341
Scott Main5a1123e2012-09-26 12:51:28 -0700342 $lessons = $(this).closest('li').find('ul li a');
Scott Main3b90aff2013-08-01 18:09:35 -0700343
Scott Main5a1123e2012-09-26 12:51:28 -0700344 if ($lessons.length) {
Scott Main3b90aff2013-08-01 18:09:35 -0700345 $imgIcon = $('<img src="'+toRoot+'assets/images/resource-tutorial.png" '
346 + ' width="64" height="64" alt=""/>');
Scott Main5a1123e2012-09-26 12:51:28 -0700347 $lessons.each(function(index) {
348 $olLessons.append('<li><a href="'+$(this).attr('href')+'">' + $(this).html()+'</a></li>');
349 });
350 } else {
Scott Main3b90aff2013-08-01 18:09:35 -0700351 $imgIcon = $('<img src="'+toRoot+'assets/images/resource-article.png" '
352 + ' width="64" height="64" alt=""/>');
Scott Main5a1123e2012-09-26 12:51:28 -0700353 $pSummary.addClass('article');
354 }
355
356 $liClass.append($h2Title).append($imgIcon).append($pSummary).append($olLessons);
357 $olClasses.append($liClass);
358 });
359 $('.jd-descr').append($olClasses);
360 }
361
Scott Maine4d8f1b2012-06-21 18:03:05 -0700362 // Set up expand/collapse behavior
Scott Mainad08f072013-08-20 16:49:57 -0700363 initExpandableNavItems("#nav");
Scott Main3b90aff2013-08-01 18:09:35 -0700364
Scott Main3b90aff2013-08-01 18:09:35 -0700365
Scott Maine4d8f1b2012-06-21 18:03:05 -0700366 $(".scroll-pane").scroll(function(event) {
367 event.preventDefault();
368 return false;
369 });
370
371 /* Resize nav height when window height changes */
372 $(window).resize(function() {
373 if ($('#side-nav').length == 0) return;
374 var stylesheet = $('link[rel="stylesheet"][class="fullscreen"]');
375 setNavBarLeftPos(); // do this even if sidenav isn't fixed because it could become fixed
376 // make sidenav behave when resizing the window and side-scolling is a concern
377 if (navBarIsFixed) {
378 if ((stylesheet.attr("disabled") == "disabled") || stylesheet.length == 0) {
379 updateSideNavPosition();
380 } else {
381 updateSidenavFullscreenWidth();
382 }
383 }
384 resizeNav();
385 });
386
387
388 // Set up fixed navbar
389 var prevScrollLeft = 0; // used to compare current position to previous position of horiz scroll
390 $(window).scroll(function(event) {
391 if ($('#side-nav').length == 0) return;
392 if (event.target.nodeName == "DIV") {
393 // Dump scroll event if the target is a DIV, because that means the event is coming
394 // from a scrollable div and so there's no need to make adjustments to our layout
395 return;
396 }
Scott Main3b90aff2013-08-01 18:09:35 -0700397 var scrollTop = $(window).scrollTop();
Scott Maine4d8f1b2012-06-21 18:03:05 -0700398 var headerHeight = $('#header').outerHeight();
399 var subheaderHeight = $('#nav-x').outerHeight();
Scott Main3b90aff2013-08-01 18:09:35 -0700400 var searchResultHeight = $('#searchResults').is(":visible") ?
Scott Maine4d8f1b2012-06-21 18:03:05 -0700401 $('#searchResults').outerHeight() : 0;
402 var totalHeaderHeight = headerHeight + subheaderHeight + searchResultHeight;
Scott Mainb8d06a52012-12-19 18:38:24 -0800403 // we set the navbar fixed when the scroll position is beyond the height of the site header...
Scott Maine4d8f1b2012-06-21 18:03:05 -0700404 var navBarShouldBeFixed = scrollTop > totalHeaderHeight;
Scott Mainb8d06a52012-12-19 18:38:24 -0800405 // ... except if the document content is shorter than the sidenav height.
406 // (this is necessary to avoid crazy behavior on OSX Lion due to overscroll bouncing)
407 if ($("#doc-col").height() < $("#side-nav").height()) {
408 navBarShouldBeFixed = false;
409 }
Scott Main3b90aff2013-08-01 18:09:35 -0700410
Scott Maine4d8f1b2012-06-21 18:03:05 -0700411 var scrollLeft = $(window).scrollLeft();
412 // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match
413 if (navBarIsFixed && (scrollLeft != prevScrollLeft)) {
414 updateSideNavPosition();
415 prevScrollLeft = scrollLeft;
416 }
Scott Main3b90aff2013-08-01 18:09:35 -0700417
418 // Don't continue if the header is sufficently far away
Scott Maine4d8f1b2012-06-21 18:03:05 -0700419 // (to avoid intensive resizing that slows scrolling)
420 if (navBarIsFixed && navBarShouldBeFixed) {
421 return;
422 }
Scott Main3b90aff2013-08-01 18:09:35 -0700423
Scott Maine4d8f1b2012-06-21 18:03:05 -0700424 if (navBarIsFixed != navBarShouldBeFixed) {
425 if (navBarShouldBeFixed) {
426 // make it fixed
427 var width = $('#devdoc-nav').width();
428 $('#devdoc-nav')
429 .addClass('fixed')
430 .css({'width':width+'px'})
431 .prependTo('#body-content');
432 // add neato "back to top" button
433 $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'});
Scott Main3b90aff2013-08-01 18:09:35 -0700434
Scott Maine4d8f1b2012-06-21 18:03:05 -0700435 // update the sidenaav position for side scrolling
436 updateSideNavPosition();
437 } else {
438 // make it static again
439 $('#devdoc-nav')
440 .removeClass('fixed')
441 .css({'width':'auto','margin':''})
442 .prependTo('#side-nav');
443 $('#devdoc-nav a.totop').hide();
444 }
445 navBarIsFixed = navBarShouldBeFixed;
Scott Main3b90aff2013-08-01 18:09:35 -0700446 }
447
Scott Maine4d8f1b2012-06-21 18:03:05 -0700448 resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance
449 });
450
Scott Main3b90aff2013-08-01 18:09:35 -0700451
Scott Maine4d8f1b2012-06-21 18:03:05 -0700452 var navBarLeftPos;
453 if ($('#devdoc-nav').length) {
454 setNavBarLeftPos();
455 }
456
457
Scott Maine4d8f1b2012-06-21 18:03:05 -0700458 // Set up play-on-hover <video> tags.
459 $('video.play-on-hover').bind('click', function(){
460 $(this).get(0).load(); // in case the video isn't seekable
461 $(this).get(0).play();
462 });
463
464 // Set up tooltips
465 var TOOLTIP_MARGIN = 10;
Scott Maindb3678b2012-10-23 14:13:41 -0700466 $('acronym,.tooltip-link').each(function() {
Scott Maine4d8f1b2012-06-21 18:03:05 -0700467 var $target = $(this);
468 var $tooltip = $('<div>')
469 .addClass('tooltip-box')
Scott Maindb3678b2012-10-23 14:13:41 -0700470 .append($target.attr('title'))
Scott Maine4d8f1b2012-06-21 18:03:05 -0700471 .hide()
472 .appendTo('body');
473 $target.removeAttr('title');
474
475 $target.hover(function() {
476 // in
477 var targetRect = $target.offset();
478 targetRect.width = $target.width();
479 targetRect.height = $target.height();
480
481 $tooltip.css({
482 left: targetRect.left,
483 top: targetRect.top + targetRect.height + TOOLTIP_MARGIN
484 });
485 $tooltip.addClass('below');
486 $tooltip.show();
487 }, function() {
488 // out
489 $tooltip.hide();
490 });
491 });
492
493 // Set up <h2> deeplinks
494 $('h2').click(function() {
495 var id = $(this).attr('id');
496 if (id) {
497 document.location.hash = id;
498 }
499 });
500
501 //Loads the +1 button
502 var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
503 po.src = 'https://apis.google.com/js/plusone.js';
504 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
505
506
Scott Main3b90aff2013-08-01 18:09:35 -0700507 // Revise the sidenav widths to make room for the scrollbar
Scott Maine4d8f1b2012-06-21 18:03:05 -0700508 // which avoids the visible width from changing each time the bar appears
509 var $sidenav = $("#side-nav");
510 var sidenav_width = parseInt($sidenav.innerWidth());
Scott Main3b90aff2013-08-01 18:09:35 -0700511
Scott Maine4d8f1b2012-06-21 18:03:05 -0700512 $("#devdoc-nav #nav").css("width", sidenav_width - 4 + "px"); // 4px is scrollbar width
513
514
515 $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller
Scott Main3b90aff2013-08-01 18:09:35 -0700516
Scott Maine4d8f1b2012-06-21 18:03:05 -0700517 if ($(".scroll-pane").length > 1) {
518 // Check if there's a user preference for the panel heights
519 var cookieHeight = readCookie("reference_height");
520 if (cookieHeight) {
521 restoreHeight(cookieHeight);
522 }
523 }
Scott Main3b90aff2013-08-01 18:09:35 -0700524
Scott Maine4d8f1b2012-06-21 18:03:05 -0700525 resizeNav();
526
Scott Main015d6162013-01-29 09:01:52 -0800527 /* init the language selector based on user cookie for lang */
528 loadLangPref();
529 changeNavLang(getLangPref());
530
531 /* setup event handlers to ensure the overflow menu is visible while picking lang */
532 $("#language select")
533 .mousedown(function() {
534 $("div.morehover").addClass("hover"); })
535 .blur(function() {
536 $("div.morehover").removeClass("hover"); });
537
538 /* some global variable setup */
539 resizePackagesNav = $("#resize-packages-nav");
540 classesNav = $("#classes-nav");
541 devdocNav = $("#devdoc-nav");
542
543 var cookiePath = "";
544 if (location.href.indexOf("/reference/") != -1) {
545 cookiePath = "reference_";
546 } else if (location.href.indexOf("/guide/") != -1) {
547 cookiePath = "guide_";
548 } else if (location.href.indexOf("/tools/") != -1) {
549 cookiePath = "tools_";
550 } else if (location.href.indexOf("/training/") != -1) {
551 cookiePath = "training_";
552 } else if (location.href.indexOf("/design/") != -1) {
553 cookiePath = "design_";
554 } else if (location.href.indexOf("/distribute/") != -1) {
555 cookiePath = "distribute_";
556 }
Scott Maine4d8f1b2012-06-21 18:03:05 -0700557
558});
Scott Main7e447ed2013-02-19 17:22:37 -0800559// END of the onload event
Scott Maine4d8f1b2012-06-21 18:03:05 -0700560
561
Scott Mainad08f072013-08-20 16:49:57 -0700562function initExpandableNavItems(rootTag) {
563 $(rootTag + ' li.nav-section .nav-section-header').click(function() {
564 var section = $(this).closest('li.nav-section');
565 if (section.hasClass('expanded')) {
Scott Mainf0093852013-08-22 11:37:11 -0700566 /* hide me and descendants */
567 section.find('ul').slideUp(250, function() {
568 // remove 'expanded' class from my section and any children
Scott Mainad08f072013-08-20 16:49:57 -0700569 section.closest('li').removeClass('expanded');
Scott Mainf0093852013-08-22 11:37:11 -0700570 $('li.nav-section', section).removeClass('expanded');
Scott Mainad08f072013-08-20 16:49:57 -0700571 resizeNav();
572 });
573 } else {
574 /* show me */
575 // first hide all other siblings
Scott Main70557ee2013-10-30 14:47:40 -0700576 var $others = $('li.nav-section.expanded', $(this).closest('ul')).not('.sticky');
Scott Mainad08f072013-08-20 16:49:57 -0700577 $others.removeClass('expanded').children('ul').slideUp(250);
578
579 // now expand me
580 section.closest('li').addClass('expanded');
581 section.children('ul').slideDown(250, function() {
582 resizeNav();
583 });
584 }
585 });
Scott Mainf0093852013-08-22 11:37:11 -0700586
587 // Stop expand/collapse behavior when clicking on nav section links
588 // (since we're navigating away from the page)
589 // This selector captures the first instance of <a>, but not those with "#" as the href.
590 $('.nav-section-header').find('a:eq(0)').not('a[href="#"]').click(function(evt) {
591 window.location.href = $(this).attr('href');
592 return false;
593 });
Scott Mainad08f072013-08-20 16:49:57 -0700594}
595
Scott Maine624b3f2013-09-12 12:56:41 -0700596/** Highlight the current page in sidenav, expanding children as appropriate */
Scott Mainf6145542013-04-01 16:38:11 -0700597function highlightSidenav() {
Scott Maine624b3f2013-09-12 12:56:41 -0700598 // if something is already highlighted, undo it. This is for dynamic navigation (Samples index)
599 if ($("ul#nav li.selected").length) {
600 unHighlightSidenav();
601 }
602 // look for URL in sidenav, including the hash
603 var $selNavLink = $('#nav').find('a[href="' + mPagePath + location.hash + '"]');
604
605 // If the selNavLink is still empty, look for it without the hash
606 if ($selNavLink.length == 0) {
607 $selNavLink = $('#nav').find('a[href="' + mPagePath + '"]');
608 }
609
Scott Mainf6145542013-04-01 16:38:11 -0700610 var $selListItem;
611 if ($selNavLink.length) {
Scott Mainf6145542013-04-01 16:38:11 -0700612 // Find this page's <li> in sidenav and set selected
613 $selListItem = $selNavLink.closest('li');
614 $selListItem.addClass('selected');
Scott Main3b90aff2013-08-01 18:09:35 -0700615
Scott Mainf6145542013-04-01 16:38:11 -0700616 // Traverse up the tree and expand all parent nav-sections
617 $selNavLink.parents('li.nav-section').each(function() {
618 $(this).addClass('expanded');
619 $(this).children('ul').show();
620 });
621 }
622}
623
Scott Maine624b3f2013-09-12 12:56:41 -0700624function unHighlightSidenav() {
625 $("ul#nav li.selected").removeClass("selected");
626 $('ul#nav li.nav-section.expanded').removeClass('expanded').children('ul').hide();
627}
Scott Maine4d8f1b2012-06-21 18:03:05 -0700628
629function toggleFullscreen(enable) {
630 var delay = 20;
631 var enabled = true;
632 var stylesheet = $('link[rel="stylesheet"][class="fullscreen"]');
633 if (enable) {
634 // Currently NOT USING fullscreen; enable fullscreen
635 stylesheet.removeAttr('disabled');
636 $('#nav-swap .fullscreen').removeClass('disabled');
637 $('#devdoc-nav').css({left:''});
638 setTimeout(updateSidenavFullscreenWidth,delay); // need to wait a moment for css to switch
639 enabled = true;
640 } else {
641 // Currently USING fullscreen; disable fullscreen
642 stylesheet.attr('disabled', 'disabled');
643 $('#nav-swap .fullscreen').addClass('disabled');
644 setTimeout(updateSidenavFixedWidth,delay); // need to wait a moment for css to switch
645 enabled = false;
646 }
647 writeCookie("fullscreen", enabled, null, null);
648 setNavBarLeftPos();
649 resizeNav(delay);
650 updateSideNavPosition();
651 setTimeout(initSidenavHeightResize,delay);
652}
653
654
655function setNavBarLeftPos() {
656 navBarLeftPos = $('#body-content').offset().left;
657}
658
659
660function updateSideNavPosition() {
661 var newLeft = $(window).scrollLeft() - navBarLeftPos;
662 $('#devdoc-nav').css({left: -newLeft});
663 $('#devdoc-nav .totop').css({left: -(newLeft - parseInt($('#side-nav').css('margin-left')))});
664}
Scott Main3b90aff2013-08-01 18:09:35 -0700665
Scott Maine4d8f1b2012-06-21 18:03:05 -0700666// TODO: use $(document).ready instead
667function addLoadEvent(newfun) {
668 var current = window.onload;
669 if (typeof window.onload != 'function') {
670 window.onload = newfun;
671 } else {
672 window.onload = function() {
673 current();
674 newfun();
675 }
676 }
677}
678
679var agent = navigator['userAgent'].toLowerCase();
680// If a mobile phone, set flag and do mobile setup
681if ((agent.indexOf("mobile") != -1) || // android, iphone, ipod
682 (agent.indexOf("blackberry") != -1) ||
683 (agent.indexOf("webos") != -1) ||
684 (agent.indexOf("mini") != -1)) { // opera mini browsers
685 isMobile = true;
686}
687
688
Scott Main498d7102013-08-21 15:47:38 -0700689$(document).ready(function() {
Scott Maine4d8f1b2012-06-21 18:03:05 -0700690 $("pre:not(.no-pretty-print)").addClass("prettyprint");
691 prettyPrint();
Scott Main498d7102013-08-21 15:47:38 -0700692});
Scott Maine4d8f1b2012-06-21 18:03:05 -0700693
Scott Maine4d8f1b2012-06-21 18:03:05 -0700694
695
696
697/* ######### RESIZE THE SIDENAV HEIGHT ########## */
698
699function resizeNav(delay) {
700 var $nav = $("#devdoc-nav");
701 var $window = $(window);
702 var navHeight;
Scott Main3b90aff2013-08-01 18:09:35 -0700703
Scott Maine4d8f1b2012-06-21 18:03:05 -0700704 // Get the height of entire window and the total header height.
705 // Then figure out based on scroll position whether the header is visible
706 var windowHeight = $window.height();
707 var scrollTop = $window.scrollTop();
708 var headerHeight = $('#header').outerHeight();
709 var subheaderHeight = $('#nav-x').outerHeight();
710 var headerVisible = (scrollTop < (headerHeight + subheaderHeight));
Scott Main3b90aff2013-08-01 18:09:35 -0700711
712 // get the height of space between nav and top of window.
Scott Maine4d8f1b2012-06-21 18:03:05 -0700713 // Could be either margin or top position, depending on whether the nav is fixed.
Scott Main3b90aff2013-08-01 18:09:35 -0700714 var topMargin = (parseInt($nav.css('margin-top')) || parseInt($nav.css('top'))) + 1;
Scott Maine4d8f1b2012-06-21 18:03:05 -0700715 // add 1 for the #side-nav bottom margin
Scott Main3b90aff2013-08-01 18:09:35 -0700716
Scott Maine4d8f1b2012-06-21 18:03:05 -0700717 // Depending on whether the header is visible, set the side nav's height.
718 if (headerVisible) {
719 // The sidenav height grows as the header goes off screen
720 navHeight = windowHeight - (headerHeight + subheaderHeight - scrollTop) - topMargin;
721 } else {
722 // Once header is off screen, the nav height is almost full window height
723 navHeight = windowHeight - topMargin;
724 }
Scott Main3b90aff2013-08-01 18:09:35 -0700725
726
727
Scott Maine4d8f1b2012-06-21 18:03:05 -0700728 $scrollPanes = $(".scroll-pane");
729 if ($scrollPanes.length > 1) {
730 // subtract the height of the api level widget and nav swapper from the available nav height
731 navHeight -= ($('#api-nav-header').outerHeight(true) + $('#nav-swap').outerHeight(true));
Scott Main3b90aff2013-08-01 18:09:35 -0700732
Scott Maine4d8f1b2012-06-21 18:03:05 -0700733 $("#swapper").css({height:navHeight + "px"});
734 if ($("#nav-tree").is(":visible")) {
735 $("#nav-tree").css({height:navHeight});
736 }
Scott Main3b90aff2013-08-01 18:09:35 -0700737
738 var classesHeight = navHeight - parseInt($("#resize-packages-nav").css("height")) - 10 + "px";
Scott Maine4d8f1b2012-06-21 18:03:05 -0700739 //subtract 10px to account for drag bar
Scott Main3b90aff2013-08-01 18:09:35 -0700740
741 // if the window becomes small enough to make the class panel height 0,
Scott Maine4d8f1b2012-06-21 18:03:05 -0700742 // then the package panel should begin to shrink
743 if (parseInt(classesHeight) <= 0) {
744 $("#resize-packages-nav").css({height:navHeight - 10}); //subtract 10px for drag bar
745 $("#packages-nav").css({height:navHeight - 10});
746 }
Scott Main3b90aff2013-08-01 18:09:35 -0700747
Scott Maine4d8f1b2012-06-21 18:03:05 -0700748 $("#classes-nav").css({'height':classesHeight, 'margin-top':'10px'});
749 $("#classes-nav .jspContainer").css({height:classesHeight});
Scott Main3b90aff2013-08-01 18:09:35 -0700750
751
Scott Maine4d8f1b2012-06-21 18:03:05 -0700752 } else {
753 $nav.height(navHeight);
754 }
Scott Main3b90aff2013-08-01 18:09:35 -0700755
Scott Maine4d8f1b2012-06-21 18:03:05 -0700756 if (delay) {
757 updateFromResize = true;
758 delayedReInitScrollbars(delay);
759 } else {
760 reInitScrollbars();
761 }
Scott Main3b90aff2013-08-01 18:09:35 -0700762
Scott Maine4d8f1b2012-06-21 18:03:05 -0700763}
764
765var updateScrollbars = false;
766var updateFromResize = false;
767
768/* Re-initialize the scrollbars to account for changed nav size.
769 * This method postpones the actual update by a 1/4 second in order to optimize the
770 * scroll performance while the header is still visible, because re-initializing the
771 * scroll panes is an intensive process.
772 */
773function delayedReInitScrollbars(delay) {
774 // If we're scheduled for an update, but have received another resize request
775 // before the scheduled resize has occured, just ignore the new request
776 // (and wait for the scheduled one).
777 if (updateScrollbars && updateFromResize) {
778 updateFromResize = false;
779 return;
780 }
Scott Main3b90aff2013-08-01 18:09:35 -0700781
Scott Maine4d8f1b2012-06-21 18:03:05 -0700782 // We're scheduled for an update and the update request came from this method's setTimeout
783 if (updateScrollbars && !updateFromResize) {
784 reInitScrollbars();
785 updateScrollbars = false;
786 } else {
787 updateScrollbars = true;
788 updateFromResize = false;
789 setTimeout('delayedReInitScrollbars()',delay);
790 }
791}
792
793/* Re-initialize the scrollbars to account for changed nav size. */
794function reInitScrollbars() {
795 var pane = $(".scroll-pane").each(function(){
796 var api = $(this).data('jsp');
797 if (!api) { setTimeout(reInitScrollbars,300); return;}
798 api.reinitialise( {verticalGutter:0} );
Scott Main3b90aff2013-08-01 18:09:35 -0700799 });
Scott Maine4d8f1b2012-06-21 18:03:05 -0700800 $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller
801}
802
803
804/* Resize the height of the nav panels in the reference,
805 * and save the new size to a cookie */
806function saveNavPanels() {
807 var basePath = getBaseUri(location.pathname);
808 var section = basePath.substring(1,basePath.indexOf("/",1));
809 writeCookie("height", resizePackagesNav.css("height"), section, null);
810}
811
812
813
814function restoreHeight(packageHeight) {
815 $("#resize-packages-nav").height(packageHeight);
816 $("#packages-nav").height(packageHeight);
817 // var classesHeight = navHeight - packageHeight;
818 // $("#classes-nav").css({height:classesHeight});
819 // $("#classes-nav .jspContainer").css({height:classesHeight});
820}
821
822
823
824/* ######### END RESIZE THE SIDENAV HEIGHT ########## */
825
826
827
828
829
Scott Main3b90aff2013-08-01 18:09:35 -0700830/** Scroll the jScrollPane to make the currently selected item visible
Scott Maine4d8f1b2012-06-21 18:03:05 -0700831 This is called when the page finished loading. */
832function scrollIntoView(nav) {
833 var $nav = $("#"+nav);
834 var element = $nav.jScrollPane({/* ...settings... */});
835 var api = element.data('jsp');
836
837 if ($nav.is(':visible')) {
838 var $selected = $(".selected", $nav);
Scott Mainbc729572013-07-30 18:00:51 -0700839 if ($selected.length == 0) {
840 // If no selected item found, exit
841 return;
842 }
Scott Main52dd2062013-08-15 12:22:28 -0700843 // get the selected item's offset from its container nav by measuring the item's offset
844 // relative to the document then subtract the container nav's offset relative to the document
845 var selectedOffset = $selected.offset().top - $nav.offset().top;
846 if (selectedOffset > $nav.height() * .8) { // multiply nav height by .8 so we move up the item
847 // if it's more than 80% down the nav
848 // scroll the item up by an amount equal to 80% the container nav's height
849 api.scrollTo(0, selectedOffset - ($nav.height() * .8), false);
Scott Maine4d8f1b2012-06-21 18:03:05 -0700850 }
851 }
852}
853
854
855
856
857
858
859/* Show popup dialogs */
860function showDialog(id) {
861 $dialog = $("#"+id);
862 $dialog.prepend('<div class="box-border"><div class="top"> <div class="left"></div> <div class="right"></div></div><div class="bottom"> <div class="left"></div> <div class="right"></div> </div> </div>');
863 $dialog.wrapInner('<div/>');
864 $dialog.removeClass("hide");
865}
866
867
868
869
870
871/* ######### COOKIES! ########## */
872
873function readCookie(cookie) {
874 var myCookie = cookie_namespace+"_"+cookie+"=";
875 if (document.cookie) {
876 var index = document.cookie.indexOf(myCookie);
877 if (index != -1) {
878 var valStart = index + myCookie.length;
879 var valEnd = document.cookie.indexOf(";", valStart);
880 if (valEnd == -1) {
881 valEnd = document.cookie.length;
882 }
883 var val = document.cookie.substring(valStart, valEnd);
884 return val;
885 }
886 }
887 return 0;
888}
889
890function writeCookie(cookie, val, section, expiration) {
891 if (val==undefined) return;
892 section = section == null ? "_" : "_"+section+"_";
893 if (expiration == null) {
894 var date = new Date();
895 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week
896 expiration = date.toGMTString();
897 }
Scott Main3b90aff2013-08-01 18:09:35 -0700898 var cookieValue = cookie_namespace + section + cookie + "=" + val
Scott Maine4d8f1b2012-06-21 18:03:05 -0700899 + "; expires=" + expiration+"; path=/";
900 document.cookie = cookieValue;
901}
902
903/* ######### END COOKIES! ########## */
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
Scott Maind7026f72013-06-17 15:08:49 -0700923/* MISC LIBRARY FUNCTIONS */
Scott Maine4d8f1b2012-06-21 18:03:05 -0700924
925
926
927
928
929function toggle(obj, slide) {
930 var ul = $("ul:first", obj);
931 var li = ul.parent();
932 if (li.hasClass("closed")) {
933 if (slide) {
934 ul.slideDown("fast");
935 } else {
936 ul.show();
937 }
938 li.removeClass("closed");
939 li.addClass("open");
940 $(".toggle-img", li).attr("title", "hide pages");
941 } else {
942 ul.slideUp("fast");
943 li.removeClass("open");
944 li.addClass("closed");
945 $(".toggle-img", li).attr("title", "show pages");
946 }
947}
948
949
Scott Maine4d8f1b2012-06-21 18:03:05 -0700950function buildToggleLists() {
951 $(".toggle-list").each(
952 function(i) {
953 $("div:first", this).append("<a class='toggle-img' href='#' title='show pages' onClick='toggle(this.parentNode.parentNode, true); return false;'></a>");
954 $(this).addClass("closed");
955 });
956}
957
958
959
Scott Maind7026f72013-06-17 15:08:49 -0700960function hideNestedItems(list, toggle) {
961 $list = $(list);
962 // hide nested lists
963 if($list.hasClass('showing')) {
964 $("li ol", $list).hide('fast');
965 $list.removeClass('showing');
966 // show nested lists
967 } else {
968 $("li ol", $list).show('fast');
969 $list.addClass('showing');
970 }
971 $(".more,.less",$(toggle)).toggle();
972}
Scott Maine4d8f1b2012-06-21 18:03:05 -0700973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001/* REFERENCE NAV SWAP */
1002
1003
1004function getNavPref() {
1005 var v = readCookie('reference_nav');
1006 if (v != NAV_PREF_TREE) {
1007 v = NAV_PREF_PANELS;
1008 }
1009 return v;
1010}
1011
1012function chooseDefaultNav() {
1013 nav_pref = getNavPref();
1014 if (nav_pref == NAV_PREF_TREE) {
1015 $("#nav-panels").toggle();
1016 $("#panel-link").toggle();
1017 $("#nav-tree").toggle();
1018 $("#tree-link").toggle();
1019 }
1020}
1021
1022function swapNav() {
1023 if (nav_pref == NAV_PREF_TREE) {
1024 nav_pref = NAV_PREF_PANELS;
1025 } else {
1026 nav_pref = NAV_PREF_TREE;
1027 init_default_navtree(toRoot);
1028 }
1029 var date = new Date();
1030 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
1031 writeCookie("nav", nav_pref, "reference", date.toGMTString());
1032
1033 $("#nav-panels").toggle();
1034 $("#panel-link").toggle();
1035 $("#nav-tree").toggle();
1036 $("#tree-link").toggle();
Scott Main3b90aff2013-08-01 18:09:35 -07001037
Scott Maine4d8f1b2012-06-21 18:03:05 -07001038 resizeNav();
1039
1040 // Gross nasty hack to make tree view show up upon first swap by setting height manually
1041 $("#nav-tree .jspContainer:visible")
1042 .css({'height':$("#nav-tree .jspContainer .jspPane").height() +'px'});
1043 // Another nasty hack to make the scrollbar appear now that we have height
1044 resizeNav();
Scott Main3b90aff2013-08-01 18:09:35 -07001045
Scott Maine4d8f1b2012-06-21 18:03:05 -07001046 if ($("#nav-tree").is(':visible')) {
1047 scrollIntoView("nav-tree");
1048 } else {
1049 scrollIntoView("packages-nav");
1050 scrollIntoView("classes-nav");
1051 }
1052}
1053
1054
1055
Scott Mainf5089842012-08-14 16:31:07 -07001056/* ############################################ */
Scott Maine4d8f1b2012-06-21 18:03:05 -07001057/* ########## LOCALIZATION ############ */
Scott Mainf5089842012-08-14 16:31:07 -07001058/* ############################################ */
Scott Maine4d8f1b2012-06-21 18:03:05 -07001059
1060function getBaseUri(uri) {
1061 var intlUrl = (uri.substring(0,6) == "/intl/");
1062 if (intlUrl) {
1063 base = uri.substring(uri.indexOf('intl/')+5,uri.length);
1064 base = base.substring(base.indexOf('/')+1, base.length);
1065 //alert("intl, returning base url: /" + base);
1066 return ("/" + base);
1067 } else {
1068 //alert("not intl, returning uri as found.");
1069 return uri;
1070 }
1071}
1072
1073function requestAppendHL(uri) {
1074//append "?hl=<lang> to an outgoing request (such as to blog)
1075 var lang = getLangPref();
1076 if (lang) {
1077 var q = 'hl=' + lang;
1078 uri += '?' + q;
1079 window.location = uri;
1080 return false;
1081 } else {
1082 return true;
1083 }
1084}
1085
1086
Scott Maine4d8f1b2012-06-21 18:03:05 -07001087function changeNavLang(lang) {
Scott Main6eb95f12012-10-02 17:12:23 -07001088 var $links = $("#devdoc-nav,#header,#nav-x,.training-nav-top,.content-footer").find("a["+lang+"-lang]");
1089 $links.each(function(i){ // for each link with a translation
1090 var $link = $(this);
1091 if (lang != "en") { // No need to worry about English, because a language change invokes new request
1092 // put the desired language from the attribute as the text
1093 $link.text($link.attr(lang+"-lang"))
Scott Maine4d8f1b2012-06-21 18:03:05 -07001094 }
Scott Main6eb95f12012-10-02 17:12:23 -07001095 });
Scott Maine4d8f1b2012-06-21 18:03:05 -07001096}
1097
Scott Main015d6162013-01-29 09:01:52 -08001098function changeLangPref(lang, submit) {
Scott Maine4d8f1b2012-06-21 18:03:05 -07001099 var date = new Date();
Scott Main3b90aff2013-08-01 18:09:35 -07001100 expires = date.toGMTString(date.setTime(date.getTime()+(10*365*24*60*60*1000)));
Scott Maine4d8f1b2012-06-21 18:03:05 -07001101 // keep this for 50 years
1102 //alert("expires: " + expires)
1103 writeCookie("pref_lang", lang, null, expires);
Scott Main015d6162013-01-29 09:01:52 -08001104
1105 // ####### TODO: Remove this condition once we're stable on devsite #######
1106 // This condition is only needed if we still need to support legacy GAE server
1107 if (devsite) {
1108 // Switch language when on Devsite server
1109 if (submit) {
1110 $("#setlang").submit();
1111 }
1112 } else {
1113 // Switch language when on legacy GAE server
Scott Main015d6162013-01-29 09:01:52 -08001114 if (submit) {
1115 window.location = getBaseUri(location.pathname);
1116 }
Scott Maine4d8f1b2012-06-21 18:03:05 -07001117 }
1118}
1119
1120function loadLangPref() {
1121 var lang = readCookie("pref_lang");
1122 if (lang != 0) {
1123 $("#language").find("option[value='"+lang+"']").attr("selected",true);
1124 }
1125}
1126
1127function getLangPref() {
1128 var lang = $("#language").find(":selected").attr("value");
1129 if (!lang) {
1130 lang = readCookie("pref_lang");
1131 }
1132 return (lang != 0) ? lang : 'en';
1133}
1134
1135/* ########## END LOCALIZATION ############ */
1136
1137
1138
1139
1140
1141
1142/* Used to hide and reveal supplemental content, such as long code samples.
1143 See the companion CSS in android-developer-docs.css */
1144function toggleContent(obj) {
Scott Maindc63dda2013-08-22 16:03:21 -07001145 var div = $(obj).closest(".toggle-content");
1146 var toggleMe = $(".toggle-content-toggleme:eq(0)",div);
Scott Maine4d8f1b2012-06-21 18:03:05 -07001147 if (div.hasClass("closed")) { // if it's closed, open it
1148 toggleMe.slideDown();
Scott Maindc63dda2013-08-22 16:03:21 -07001149 $(".toggle-content-text:eq(0)", obj).toggle();
Scott Maine4d8f1b2012-06-21 18:03:05 -07001150 div.removeClass("closed").addClass("open");
Scott Maindc63dda2013-08-22 16:03:21 -07001151 $(".toggle-content-img:eq(0)", div).attr("title", "hide").attr("src", toRoot
Scott Maine4d8f1b2012-06-21 18:03:05 -07001152 + "assets/images/triangle-opened.png");
1153 } else { // if it's open, close it
1154 toggleMe.slideUp('fast', function() { // Wait until the animation is done before closing arrow
Scott Maindc63dda2013-08-22 16:03:21 -07001155 $(".toggle-content-text:eq(0)", obj).toggle();
Scott Maine4d8f1b2012-06-21 18:03:05 -07001156 div.removeClass("open").addClass("closed");
Scott Maindc63dda2013-08-22 16:03:21 -07001157 div.find(".toggle-content").removeClass("open").addClass("closed")
1158 .find(".toggle-content-toggleme").hide();
Scott Main3b90aff2013-08-01 18:09:35 -07001159 $(".toggle-content-img", div).attr("title", "show").attr("src", toRoot
Scott Maine4d8f1b2012-06-21 18:03:05 -07001160 + "assets/images/triangle-closed.png");
1161 });
1162 }
1163 return false;
1164}
Scott Mainf5089842012-08-14 16:31:07 -07001165
1166
Scott Maindb3678b2012-10-23 14:13:41 -07001167/* New version of expandable content */
1168function toggleExpandable(link,id) {
1169 if($(id).is(':visible')) {
1170 $(id).slideUp();
1171 $(link).removeClass('expanded');
1172 } else {
1173 $(id).slideDown();
1174 $(link).addClass('expanded');
1175 }
1176}
1177
1178function hideExpandable(ids) {
1179 $(ids).slideUp();
Scott Main55d99832012-11-12 23:03:59 -08001180 $(ids).prev('h4').find('a.expandable').removeClass('expanded');
Scott Maindb3678b2012-10-23 14:13:41 -07001181}
1182
Scott Mainf5089842012-08-14 16:31:07 -07001183
1184
1185
1186
Scott Main3b90aff2013-08-01 18:09:35 -07001187/*
Scott Mainf5089842012-08-14 16:31:07 -07001188 * Slideshow 1.0
1189 * Used on /index.html and /develop/index.html for carousel
1190 *
1191 * Sample usage:
1192 * HTML -
1193 * <div class="slideshow-container">
1194 * <a href="" class="slideshow-prev">Prev</a>
1195 * <a href="" class="slideshow-next">Next</a>
1196 * <ul>
1197 * <li class="item"><img src="images/marquee1.jpg"></li>
1198 * <li class="item"><img src="images/marquee2.jpg"></li>
1199 * <li class="item"><img src="images/marquee3.jpg"></li>
1200 * <li class="item"><img src="images/marquee4.jpg"></li>
1201 * </ul>
1202 * </div>
1203 *
1204 * <script type="text/javascript">
1205 * $('.slideshow-container').dacSlideshow({
1206 * auto: true,
1207 * btnPrev: '.slideshow-prev',
1208 * btnNext: '.slideshow-next'
1209 * });
1210 * </script>
1211 *
1212 * Options:
1213 * btnPrev: optional identifier for previous button
1214 * btnNext: optional identifier for next button
Scott Maineb410352013-01-14 19:03:40 -08001215 * btnPause: optional identifier for pause button
Scott Mainf5089842012-08-14 16:31:07 -07001216 * auto: whether or not to auto-proceed
1217 * speed: animation speed
1218 * autoTime: time between auto-rotation
1219 * easing: easing function for transition
1220 * start: item to select by default
1221 * scroll: direction to scroll in
1222 * pagination: whether or not to include dotted pagination
1223 *
1224 */
1225
1226 (function($) {
1227 $.fn.dacSlideshow = function(o) {
Scott Main3b90aff2013-08-01 18:09:35 -07001228
Scott Mainf5089842012-08-14 16:31:07 -07001229 //Options - see above
1230 o = $.extend({
1231 btnPrev: null,
1232 btnNext: null,
Scott Maineb410352013-01-14 19:03:40 -08001233 btnPause: null,
Scott Mainf5089842012-08-14 16:31:07 -07001234 auto: true,
1235 speed: 500,
1236 autoTime: 12000,
1237 easing: null,
1238 start: 0,
1239 scroll: 1,
1240 pagination: true
1241
1242 }, o || {});
Scott Main3b90aff2013-08-01 18:09:35 -07001243
1244 //Set up a carousel for each
Scott Mainf5089842012-08-14 16:31:07 -07001245 return this.each(function() {
1246
1247 var running = false;
1248 var animCss = o.vertical ? "top" : "left";
1249 var sizeCss = o.vertical ? "height" : "width";
1250 var div = $(this);
1251 var ul = $("ul", div);
1252 var tLi = $("li", ul);
Scott Main3b90aff2013-08-01 18:09:35 -07001253 var tl = tLi.size();
Scott Mainf5089842012-08-14 16:31:07 -07001254 var timer = null;
1255
1256 var li = $("li", ul);
1257 var itemLength = li.size();
1258 var curr = o.start;
1259
1260 li.css({float: o.vertical ? "none" : "left"});
1261 ul.css({margin: "0", padding: "0", position: "relative", "list-style-type": "none", "z-index": "1"});
1262 div.css({position: "relative", "z-index": "2", left: "0px"});
1263
1264 var liSize = o.vertical ? height(li) : width(li);
1265 var ulSize = liSize * itemLength;
1266 var divSize = liSize;
1267
1268 li.css({width: li.width(), height: li.height()});
1269 ul.css(sizeCss, ulSize+"px").css(animCss, -(curr*liSize));
1270
1271 div.css(sizeCss, divSize+"px");
Scott Main3b90aff2013-08-01 18:09:35 -07001272
Scott Mainf5089842012-08-14 16:31:07 -07001273 //Pagination
1274 if (o.pagination) {
1275 var pagination = $("<div class='pagination'></div>");
1276 var pag_ul = $("<ul></ul>");
1277 if (tl > 1) {
1278 for (var i=0;i<tl;i++) {
1279 var li = $("<li>"+i+"</li>");
1280 pag_ul.append(li);
1281 if (i==o.start) li.addClass('active');
1282 li.click(function() {
1283 go(parseInt($(this).text()));
1284 })
1285 }
1286 pagination.append(pag_ul);
1287 div.append(pagination);
1288 }
1289 }
Scott Main3b90aff2013-08-01 18:09:35 -07001290
Scott Mainf5089842012-08-14 16:31:07 -07001291 //Previous button
1292 if(o.btnPrev)
1293 $(o.btnPrev).click(function(e) {
1294 e.preventDefault();
1295 return go(curr-o.scroll);
1296 });
1297
1298 //Next button
1299 if(o.btnNext)
1300 $(o.btnNext).click(function(e) {
1301 e.preventDefault();
1302 return go(curr+o.scroll);
1303 });
Scott Maineb410352013-01-14 19:03:40 -08001304
1305 //Pause button
1306 if(o.btnPause)
1307 $(o.btnPause).click(function(e) {
1308 e.preventDefault();
1309 if ($(this).hasClass('paused')) {
1310 startRotateTimer();
1311 } else {
1312 pauseRotateTimer();
1313 }
1314 });
Scott Main3b90aff2013-08-01 18:09:35 -07001315
Scott Mainf5089842012-08-14 16:31:07 -07001316 //Auto rotation
1317 if(o.auto) startRotateTimer();
Scott Main3b90aff2013-08-01 18:09:35 -07001318
Scott Mainf5089842012-08-14 16:31:07 -07001319 function startRotateTimer() {
1320 clearInterval(timer);
1321 timer = setInterval(function() {
1322 if (curr == tl-1) {
1323 go(0);
1324 } else {
Scott Main3b90aff2013-08-01 18:09:35 -07001325 go(curr+o.scroll);
1326 }
Scott Mainf5089842012-08-14 16:31:07 -07001327 }, o.autoTime);
Scott Maineb410352013-01-14 19:03:40 -08001328 $(o.btnPause).removeClass('paused');
1329 }
1330
1331 function pauseRotateTimer() {
1332 clearInterval(timer);
1333 $(o.btnPause).addClass('paused');
Scott Mainf5089842012-08-14 16:31:07 -07001334 }
1335
1336 //Go to an item
1337 function go(to) {
1338 if(!running) {
1339
1340 if(to<0) {
1341 to = itemLength-1;
1342 } else if (to>itemLength-1) {
1343 to = 0;
1344 }
1345 curr = to;
1346
1347 running = true;
1348
1349 ul.animate(
1350 animCss == "left" ? { left: -(curr*liSize) } : { top: -(curr*liSize) } , o.speed, o.easing,
1351 function() {
1352 running = false;
1353 }
1354 );
1355
1356 $(o.btnPrev + "," + o.btnNext).removeClass("disabled");
1357 $( (curr-o.scroll<0 && o.btnPrev)
1358 ||
1359 (curr+o.scroll > itemLength && o.btnNext)
1360 ||
1361 []
1362 ).addClass("disabled");
1363
Scott Main3b90aff2013-08-01 18:09:35 -07001364
Scott Mainf5089842012-08-14 16:31:07 -07001365 var nav_items = $('li', pagination);
1366 nav_items.removeClass('active');
1367 nav_items.eq(to).addClass('active');
Scott Main3b90aff2013-08-01 18:09:35 -07001368
Scott Mainf5089842012-08-14 16:31:07 -07001369
1370 }
1371 if(o.auto) startRotateTimer();
1372 return false;
1373 };
1374 });
1375 };
1376
1377 function css(el, prop) {
1378 return parseInt($.css(el[0], prop)) || 0;
1379 };
1380 function width(el) {
1381 return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
1382 };
1383 function height(el) {
1384 return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
1385 };
1386
1387 })(jQuery);
1388
1389
Scott Main3b90aff2013-08-01 18:09:35 -07001390/*
Scott Mainf5089842012-08-14 16:31:07 -07001391 * dacSlideshow 1.0
1392 * Used on develop/index.html for side-sliding tabs
1393 *
1394 * Sample usage:
1395 * HTML -
1396 * <div class="slideshow-container">
1397 * <a href="" class="slideshow-prev">Prev</a>
1398 * <a href="" class="slideshow-next">Next</a>
1399 * <ul>
1400 * <li class="item"><img src="images/marquee1.jpg"></li>
1401 * <li class="item"><img src="images/marquee2.jpg"></li>
1402 * <li class="item"><img src="images/marquee3.jpg"></li>
1403 * <li class="item"><img src="images/marquee4.jpg"></li>
1404 * </ul>
1405 * </div>
1406 *
1407 * <script type="text/javascript">
1408 * $('.slideshow-container').dacSlideshow({
1409 * auto: true,
1410 * btnPrev: '.slideshow-prev',
1411 * btnNext: '.slideshow-next'
1412 * });
1413 * </script>
1414 *
1415 * Options:
1416 * btnPrev: optional identifier for previous button
1417 * btnNext: optional identifier for next button
1418 * auto: whether or not to auto-proceed
1419 * speed: animation speed
1420 * autoTime: time between auto-rotation
1421 * easing: easing function for transition
1422 * start: item to select by default
1423 * scroll: direction to scroll in
1424 * pagination: whether or not to include dotted pagination
1425 *
1426 */
1427 (function($) {
1428 $.fn.dacTabbedList = function(o) {
Scott Main3b90aff2013-08-01 18:09:35 -07001429
Scott Mainf5089842012-08-14 16:31:07 -07001430 //Options - see above
1431 o = $.extend({
1432 speed : 250,
1433 easing: null,
1434 nav_id: null,
1435 frame_id: null
1436 }, o || {});
Scott Main3b90aff2013-08-01 18:09:35 -07001437
1438 //Set up a carousel for each
Scott Mainf5089842012-08-14 16:31:07 -07001439 return this.each(function() {
1440
1441 var curr = 0;
1442 var running = false;
1443 var animCss = "margin-left";
1444 var sizeCss = "width";
1445 var div = $(this);
Scott Main3b90aff2013-08-01 18:09:35 -07001446
Scott Mainf5089842012-08-14 16:31:07 -07001447 var nav = $(o.nav_id, div);
1448 var nav_li = $("li", nav);
Scott Main3b90aff2013-08-01 18:09:35 -07001449 var nav_size = nav_li.size();
Scott Mainf5089842012-08-14 16:31:07 -07001450 var frame = div.find(o.frame_id);
1451 var content_width = $(frame).find('ul').width();
1452 //Buttons
1453 $(nav_li).click(function(e) {
1454 go($(nav_li).index($(this)));
1455 })
Scott Main3b90aff2013-08-01 18:09:35 -07001456
Scott Mainf5089842012-08-14 16:31:07 -07001457 //Go to an item
1458 function go(to) {
1459 if(!running) {
1460 curr = to;
1461 running = true;
1462
1463 frame.animate({ 'margin-left' : -(curr*content_width) }, o.speed, o.easing,
1464 function() {
1465 running = false;
1466 }
1467 );
1468
Scott Main3b90aff2013-08-01 18:09:35 -07001469
Scott Mainf5089842012-08-14 16:31:07 -07001470 nav_li.removeClass('active');
1471 nav_li.eq(to).addClass('active');
Scott Main3b90aff2013-08-01 18:09:35 -07001472
Scott Mainf5089842012-08-14 16:31:07 -07001473
1474 }
1475 return false;
1476 };
1477 });
1478 };
1479
1480 function css(el, prop) {
1481 return parseInt($.css(el[0], prop)) || 0;
1482 };
1483 function width(el) {
1484 return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
1485 };
1486 function height(el) {
1487 return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
1488 };
1489
1490 })(jQuery);
1491
1492
1493
1494
1495
1496/* ######################################################## */
1497/* ################ SEARCH SUGGESTIONS ################## */
1498/* ######################################################## */
1499
1500
Scott Main7e447ed2013-02-19 17:22:37 -08001501
Scott Main0e76e7e2013-03-12 10:24:07 -07001502var gSelectedIndex = -1; // the index position of currently highlighted suggestion
1503var gSelectedColumn = -1; // which column of suggestion lists is currently focused
1504
Scott Mainf5089842012-08-14 16:31:07 -07001505var gMatches = new Array();
1506var gLastText = "";
Scott Mainf5089842012-08-14 16:31:07 -07001507var gInitialized = false;
Scott Main7e447ed2013-02-19 17:22:37 -08001508var ROW_COUNT_FRAMEWORK = 20; // max number of results in list
1509var gListLength = 0;
1510
1511
1512var gGoogleMatches = new Array();
1513var ROW_COUNT_GOOGLE = 15; // max number of results in list
1514var gGoogleListLength = 0;
Scott Mainf5089842012-08-14 16:31:07 -07001515
Scott Main0e76e7e2013-03-12 10:24:07 -07001516var gDocsMatches = new Array();
1517var ROW_COUNT_DOCS = 100; // max number of results in list
1518var gDocsListLength = 0;
1519
Scott Mainde295272013-03-25 15:48:35 -07001520function onSuggestionClick(link) {
1521 // When user clicks a suggested document, track it
1522 _gaq.push(['_trackEvent', 'Suggestion Click', 'clicked: ' + $(link).text(),
1523 'from: ' + $("#search_autocomplete").val()]);
1524}
1525
Scott Mainf5089842012-08-14 16:31:07 -07001526function set_item_selected($li, selected)
1527{
1528 if (selected) {
1529 $li.attr('class','jd-autocomplete jd-selected');
1530 } else {
1531 $li.attr('class','jd-autocomplete');
1532 }
1533}
1534
1535function set_item_values(toroot, $li, match)
1536{
1537 var $link = $('a',$li);
1538 $link.html(match.__hilabel || match.label);
1539 $link.attr('href',toroot + match.link);
1540}
1541
Scott Main0e76e7e2013-03-12 10:24:07 -07001542function new_suggestion($list) {
Scott Main7e447ed2013-02-19 17:22:37 -08001543 var $li = $("<li class='jd-autocomplete'></li>");
1544 $list.append($li);
1545
1546 $li.mousedown(function() {
1547 window.location = this.firstChild.getAttribute("href");
1548 });
1549 $li.mouseover(function() {
Scott Main0e76e7e2013-03-12 10:24:07 -07001550 $('.search_filtered_wrapper li').removeClass('jd-selected');
Scott Main7e447ed2013-02-19 17:22:37 -08001551 $(this).addClass('jd-selected');
Scott Main0e76e7e2013-03-12 10:24:07 -07001552 gSelectedColumn = $(".search_filtered:visible").index($(this).closest('.search_filtered'));
1553 gSelectedIndex = $("li", $(".search_filtered:visible")[gSelectedColumn]).index(this);
Scott Main7e447ed2013-02-19 17:22:37 -08001554 });
Scott Mainde295272013-03-25 15:48:35 -07001555 $li.append("<a onclick='onSuggestionClick(this)'></a>");
Scott Main7e447ed2013-02-19 17:22:37 -08001556 $li.attr('class','show-item');
1557 return $li;
1558}
1559
Scott Mainf5089842012-08-14 16:31:07 -07001560function sync_selection_table(toroot)
1561{
Scott Mainf5089842012-08-14 16:31:07 -07001562 var $li; //list item jquery object
1563 var i; //list item iterator
Scott Main7e447ed2013-02-19 17:22:37 -08001564
Scott Main0e76e7e2013-03-12 10:24:07 -07001565 // if there are NO results at all, hide all columns
1566 if (!(gMatches.length > 0) && !(gGoogleMatches.length > 0) && !(gDocsMatches.length > 0)) {
1567 $('.suggest-card').hide(300);
1568 return;
1569 }
1570
1571 // if there are api results
Scott Main7e447ed2013-02-19 17:22:37 -08001572 if ((gMatches.length > 0) || (gGoogleMatches.length > 0)) {
Scott Main0e76e7e2013-03-12 10:24:07 -07001573 // reveal suggestion list
1574 $('.suggest-card.dummy').show();
1575 $('.suggest-card.reference').show();
1576 var listIndex = 0; // list index position
Scott Main7e447ed2013-02-19 17:22:37 -08001577
Scott Main0e76e7e2013-03-12 10:24:07 -07001578 // reset the lists
1579 $(".search_filtered_wrapper.reference li").remove();
Scott Main7e447ed2013-02-19 17:22:37 -08001580
Scott Main0e76e7e2013-03-12 10:24:07 -07001581 // ########### ANDROID RESULTS #############
1582 if (gMatches.length > 0) {
Scott Main7e447ed2013-02-19 17:22:37 -08001583
Scott Main0e76e7e2013-03-12 10:24:07 -07001584 // determine android results to show
1585 gListLength = gMatches.length < ROW_COUNT_FRAMEWORK ?
1586 gMatches.length : ROW_COUNT_FRAMEWORK;
1587 for (i=0; i<gListLength; i++) {
1588 var $li = new_suggestion($(".suggest-card.reference ul"));
1589 set_item_values(toroot, $li, gMatches[i]);
1590 set_item_selected($li, i == gSelectedIndex);
1591 }
1592 }
Scott Main7e447ed2013-02-19 17:22:37 -08001593
Scott Main0e76e7e2013-03-12 10:24:07 -07001594 // ########### GOOGLE RESULTS #############
1595 if (gGoogleMatches.length > 0) {
1596 // show header for list
1597 $(".suggest-card.reference ul").append("<li class='header'>in Google Services:</li>");
Scott Main7e447ed2013-02-19 17:22:37 -08001598
Scott Main0e76e7e2013-03-12 10:24:07 -07001599 // determine google results to show
1600 gGoogleListLength = gGoogleMatches.length < ROW_COUNT_GOOGLE ? gGoogleMatches.length : ROW_COUNT_GOOGLE;
1601 for (i=0; i<gGoogleListLength; i++) {
1602 var $li = new_suggestion($(".suggest-card.reference ul"));
1603 set_item_values(toroot, $li, gGoogleMatches[i]);
1604 set_item_selected($li, i == gSelectedIndex);
1605 }
1606 }
Scott Mainf5089842012-08-14 16:31:07 -07001607 } else {
Scott Main0e76e7e2013-03-12 10:24:07 -07001608 $('.suggest-card.reference').hide();
1609 $('.suggest-card.dummy').hide();
1610 }
1611
1612 // ########### JD DOC RESULTS #############
1613 if (gDocsMatches.length > 0) {
1614 // reset the lists
1615 $(".search_filtered_wrapper.docs li").remove();
1616
1617 // determine google results to show
1618 gDocsListLength = gDocsMatches.length < ROW_COUNT_DOCS ? gDocsMatches.length : ROW_COUNT_DOCS;
1619 for (i=0; i<gDocsListLength; i++) {
1620 var sugg = gDocsMatches[i];
1621 var $li;
1622 if (sugg.type == "design") {
1623 $li = new_suggestion($(".suggest-card.design ul"));
1624 } else
1625 if (sugg.type == "distribute") {
1626 $li = new_suggestion($(".suggest-card.distribute ul"));
1627 } else
1628 if (sugg.type == "training") {
1629 $li = new_suggestion($(".suggest-card.develop .child-card.training"));
1630 } else
1631 if (sugg.type == "guide"||"google") {
1632 $li = new_suggestion($(".suggest-card.develop .child-card.guides"));
1633 } else {
1634 continue;
1635 }
1636
1637 set_item_values(toroot, $li, sugg);
1638 set_item_selected($li, i == gSelectedIndex);
1639 }
1640
1641 // add heading and show or hide card
1642 if ($(".suggest-card.design li").length > 0) {
1643 $(".suggest-card.design ul").prepend("<li class='header'>Design:</li>");
1644 $(".suggest-card.design").show(300);
1645 } else {
1646 $('.suggest-card.design').hide(300);
1647 }
1648 if ($(".suggest-card.distribute li").length > 0) {
1649 $(".suggest-card.distribute ul").prepend("<li class='header'>Distribute:</li>");
1650 $(".suggest-card.distribute").show(300);
1651 } else {
1652 $('.suggest-card.distribute').hide(300);
1653 }
1654 if ($(".child-card.guides li").length > 0) {
1655 $(".child-card.guides").prepend("<li class='header'>Guides:</li>");
1656 $(".child-card.guides li").appendTo(".suggest-card.develop ul");
1657 }
1658 if ($(".child-card.training li").length > 0) {
1659 $(".child-card.training").prepend("<li class='header'>Training:</li>");
1660 $(".child-card.training li").appendTo(".suggest-card.develop ul");
1661 }
1662
1663 if ($(".suggest-card.develop li").length > 0) {
1664 $(".suggest-card.develop").show(300);
1665 } else {
1666 $('.suggest-card.develop').hide(300);
1667 }
1668
1669 } else {
1670 $('.search_filtered_wrapper.docs .suggest-card:not(.dummy)').hide(300);
Scott Mainf5089842012-08-14 16:31:07 -07001671 }
1672}
1673
Scott Main0e76e7e2013-03-12 10:24:07 -07001674/** Called by the search input's onkeydown and onkeyup events.
1675 * Handles navigation with keyboard arrows, Enter key to invoke search,
1676 * otherwise invokes search suggestions on key-up event.
1677 * @param e The JS event
1678 * @param kd True if the event is key-down
Scott Main3b90aff2013-08-01 18:09:35 -07001679 * @param toroot A string for the site's root path
Scott Main0e76e7e2013-03-12 10:24:07 -07001680 * @returns True if the event should bubble up
1681 */
Scott Mainf5089842012-08-14 16:31:07 -07001682function search_changed(e, kd, toroot)
1683{
1684 var search = document.getElementById("search_autocomplete");
1685 var text = search.value.replace(/(^ +)|( +$)/g, '');
Scott Main0e76e7e2013-03-12 10:24:07 -07001686 // get the ul hosting the currently selected item
1687 gSelectedColumn = gSelectedColumn >= 0 ? gSelectedColumn : 0;
1688 var $columns = $(".search_filtered_wrapper").find(".search_filtered:visible");
1689 var $selectedUl = $columns[gSelectedColumn];
1690
Scott Mainf5089842012-08-14 16:31:07 -07001691 // show/hide the close button
1692 if (text != '') {
1693 $(".search .close").removeClass("hide");
1694 } else {
1695 $(".search .close").addClass("hide");
1696 }
Scott Main0e76e7e2013-03-12 10:24:07 -07001697 // 27 = esc
1698 if (e.keyCode == 27) {
1699 // close all search results
1700 if (kd) $('.search .close').trigger('click');
1701 return true;
1702 }
Scott Mainf5089842012-08-14 16:31:07 -07001703 // 13 = enter
Scott Main0e76e7e2013-03-12 10:24:07 -07001704 else if (e.keyCode == 13) {
1705 if (gSelectedIndex < 0) {
1706 $('.suggest-card').hide();
Scott Main7e447ed2013-02-19 17:22:37 -08001707 if ($("#searchResults").is(":hidden") && (search.value != "")) {
1708 // if results aren't showing (and text not empty), return true to allow search to execute
Scott Mainf5089842012-08-14 16:31:07 -07001709 return true;
1710 } else {
1711 // otherwise, results are already showing, so allow ajax to auto refresh the results
1712 // and ignore this Enter press to avoid the reload.
1713 return false;
1714 }
1715 } else if (kd && gSelectedIndex >= 0) {
Scott Main0e76e7e2013-03-12 10:24:07 -07001716 // click the link corresponding to selected item
1717 $("a",$("li",$selectedUl)[gSelectedIndex]).get()[0].click();
Scott Mainf5089842012-08-14 16:31:07 -07001718 return false;
1719 }
1720 }
Scott Main0e76e7e2013-03-12 10:24:07 -07001721 // Stop here if Google results are showing
1722 else if ($("#searchResults").is(":visible")) {
1723 return true;
1724 }
1725 // 38 UP ARROW
Scott Mainf5089842012-08-14 16:31:07 -07001726 else if (kd && (e.keyCode == 38)) {
Scott Main0e76e7e2013-03-12 10:24:07 -07001727 // if the next item is a header, skip it
1728 if ($($("li", $selectedUl)[gSelectedIndex-1]).hasClass("header")) {
Scott Mainf5089842012-08-14 16:31:07 -07001729 gSelectedIndex--;
Scott Main7e447ed2013-02-19 17:22:37 -08001730 }
1731 if (gSelectedIndex >= 0) {
Scott Main0e76e7e2013-03-12 10:24:07 -07001732 $('li', $selectedUl).removeClass('jd-selected');
Scott Main7e447ed2013-02-19 17:22:37 -08001733 gSelectedIndex--;
Scott Main0e76e7e2013-03-12 10:24:07 -07001734 $('li:nth-child('+(gSelectedIndex+1)+')', $selectedUl).addClass('jd-selected');
1735 // If user reaches top, reset selected column
1736 if (gSelectedIndex < 0) {
1737 gSelectedColumn = -1;
1738 }
Scott Mainf5089842012-08-14 16:31:07 -07001739 }
1740 return false;
1741 }
Scott Main0e76e7e2013-03-12 10:24:07 -07001742 // 40 DOWN ARROW
Scott Mainf5089842012-08-14 16:31:07 -07001743 else if (kd && (e.keyCode == 40)) {
Scott Main0e76e7e2013-03-12 10:24:07 -07001744 // if the next item is a header, skip it
1745 if ($($("li", $selectedUl)[gSelectedIndex+1]).hasClass("header")) {
Scott Mainf5089842012-08-14 16:31:07 -07001746 gSelectedIndex++;
Scott Main7e447ed2013-02-19 17:22:37 -08001747 }
Scott Main0e76e7e2013-03-12 10:24:07 -07001748 if ((gSelectedIndex < $("li", $selectedUl).length-1) ||
1749 ($($("li", $selectedUl)[gSelectedIndex+1]).hasClass("header"))) {
1750 $('li', $selectedUl).removeClass('jd-selected');
Scott Main7e447ed2013-02-19 17:22:37 -08001751 gSelectedIndex++;
Scott Main0e76e7e2013-03-12 10:24:07 -07001752 $('li:nth-child('+(gSelectedIndex+1)+')', $selectedUl).addClass('jd-selected');
Scott Mainf5089842012-08-14 16:31:07 -07001753 }
1754 return false;
1755 }
Scott Main0e76e7e2013-03-12 10:24:07 -07001756 // Consider left/right arrow navigation
1757 // NOTE: Order of suggest columns are reverse order (index position 0 is on right)
1758 else if (kd && $columns.length > 1 && gSelectedColumn >= 0) {
1759 // 37 LEFT ARROW
1760 // go left only if current column is not left-most column (last column)
1761 if (e.keyCode == 37 && gSelectedColumn < $columns.length - 1) {
1762 $('li', $selectedUl).removeClass('jd-selected');
1763 gSelectedColumn++;
1764 $selectedUl = $columns[gSelectedColumn];
1765 // keep or reset the selected item to last item as appropriate
1766 gSelectedIndex = gSelectedIndex >
1767 $("li", $selectedUl).length-1 ?
1768 $("li", $selectedUl).length-1 : gSelectedIndex;
1769 // if the corresponding item is a header, move down
1770 if ($($("li", $selectedUl)[gSelectedIndex]).hasClass("header")) {
1771 gSelectedIndex++;
1772 }
Scott Main3b90aff2013-08-01 18:09:35 -07001773 // set item selected
Scott Main0e76e7e2013-03-12 10:24:07 -07001774 $('li:nth-child('+(gSelectedIndex+1)+')', $selectedUl).addClass('jd-selected');
1775 return false;
1776 }
1777 // 39 RIGHT ARROW
1778 // go right only if current column is not the right-most column (first column)
1779 else if (e.keyCode == 39 && gSelectedColumn > 0) {
1780 $('li', $selectedUl).removeClass('jd-selected');
1781 gSelectedColumn--;
1782 $selectedUl = $columns[gSelectedColumn];
1783 // keep or reset the selected item to last item as appropriate
1784 gSelectedIndex = gSelectedIndex >
1785 $("li", $selectedUl).length-1 ?
1786 $("li", $selectedUl).length-1 : gSelectedIndex;
1787 // if the corresponding item is a header, move down
1788 if ($($("li", $selectedUl)[gSelectedIndex]).hasClass("header")) {
1789 gSelectedIndex++;
1790 }
Scott Main3b90aff2013-08-01 18:09:35 -07001791 // set item selected
Scott Main0e76e7e2013-03-12 10:24:07 -07001792 $('li:nth-child('+(gSelectedIndex+1)+')', $selectedUl).addClass('jd-selected');
1793 return false;
1794 }
1795 }
1796
Scott Main7e447ed2013-02-19 17:22:37 -08001797 // if key-up event and not arrow down/up,
1798 // read the search query and add suggestsions to gMatches
Scott Main0e76e7e2013-03-12 10:24:07 -07001799 else if (!kd && (e.keyCode != 40)
1800 && (e.keyCode != 38)
1801 && (e.keyCode != 37)
1802 && (e.keyCode != 39)) {
1803 gSelectedIndex = -1;
Scott Mainf5089842012-08-14 16:31:07 -07001804 gMatches = new Array();
1805 matchedCount = 0;
Scott Main7e447ed2013-02-19 17:22:37 -08001806 gGoogleMatches = new Array();
1807 matchedCountGoogle = 0;
Scott Main0e76e7e2013-03-12 10:24:07 -07001808 gDocsMatches = new Array();
1809 matchedCountDocs = 0;
Scott Main7e447ed2013-02-19 17:22:37 -08001810
1811 // Search for Android matches
Scott Mainf5089842012-08-14 16:31:07 -07001812 for (var i=0; i<DATA.length; i++) {
1813 var s = DATA[i];
1814 if (text.length != 0 &&
1815 s.label.toLowerCase().indexOf(text.toLowerCase()) != -1) {
1816 gMatches[matchedCount] = s;
1817 matchedCount++;
1818 }
1819 }
Scott Main0e76e7e2013-03-12 10:24:07 -07001820 rank_autocomplete_api_results(text, gMatches);
Scott Mainf5089842012-08-14 16:31:07 -07001821 for (var i=0; i<gMatches.length; i++) {
1822 var s = gMatches[i];
Scott Main7e447ed2013-02-19 17:22:37 -08001823 }
1824
1825
1826 // Search for Google matches
1827 for (var i=0; i<GOOGLE_DATA.length; i++) {
1828 var s = GOOGLE_DATA[i];
1829 if (text.length != 0 &&
1830 s.label.toLowerCase().indexOf(text.toLowerCase()) != -1) {
1831 gGoogleMatches[matchedCountGoogle] = s;
1832 matchedCountGoogle++;
Scott Mainf5089842012-08-14 16:31:07 -07001833 }
1834 }
Scott Main0e76e7e2013-03-12 10:24:07 -07001835 rank_autocomplete_api_results(text, gGoogleMatches);
Scott Main7e447ed2013-02-19 17:22:37 -08001836 for (var i=0; i<gGoogleMatches.length; i++) {
1837 var s = gGoogleMatches[i];
1838 }
1839
Scott Mainf5089842012-08-14 16:31:07 -07001840 highlight_autocomplete_result_labels(text);
Scott Main0e76e7e2013-03-12 10:24:07 -07001841
1842
1843
1844 // Search for JD docs
1845 if (text.length >= 3) {
1846 for (var i=0; i<JD_DATA.length; i++) {
1847 // Regex to match only the beginning of a word
1848 var textRegex = new RegExp("\\b" + text.toLowerCase(), "g");
1849 // current search comparison, with counters for tag and title,
1850 // used later to improve ranking
1851 var s = JD_DATA[i];
1852 s.matched_tag = 0;
1853 s.matched_title = 0;
1854 var matched = false;
1855
1856 // Check if query matches any tags; work backwards toward 1 to assist ranking
1857 for (var j = s.tags.length - 1; j >= 0; j--) {
1858 // it matches a tag
1859 if (s.tags[j].toLowerCase().match(textRegex)) {
1860 matched = true;
1861 s.matched_tag = j + 1; // add 1 to index position
1862 }
1863 }
1864 // Don't consider doc title for lessons (only for class landing pages)
1865 // ...it is not a training lesson (or is but has matched a tag)
1866 if (!(s.type == "training" && s.link.indexOf("index.html") == -1) || matched) {
1867 // it matches the doc title
1868 if (s.label.toLowerCase().match(textRegex)) {
1869 matched = true;
1870 s.matched_title = 1;
1871 }
1872 }
1873 if (matched) {
1874 gDocsMatches[matchedCountDocs] = s;
1875 matchedCountDocs++;
1876 }
1877 }
1878 rank_autocomplete_doc_results(text, gDocsMatches);
1879 }
1880
1881 // draw the suggestions
Scott Mainf5089842012-08-14 16:31:07 -07001882 sync_selection_table(toroot);
1883 return true; // allow the event to bubble up to the search api
1884 }
1885}
1886
Scott Main0e76e7e2013-03-12 10:24:07 -07001887/* Order the jd doc result list based on match quality */
1888function rank_autocomplete_doc_results(query, matches) {
1889 query = query || '';
1890 if (!matches || !matches.length)
1891 return;
1892
1893 var _resultScoreFn = function(match) {
1894 var score = 1.0;
1895
1896 // if the query matched a tag
1897 if (match.matched_tag > 0) {
1898 // multiply score by factor relative to position in tags list (max of 3)
1899 score *= 3 / match.matched_tag;
1900
1901 // if it also matched the title
1902 if (match.matched_title > 0) {
1903 score *= 2;
1904 }
1905 } else if (match.matched_title > 0) {
1906 score *= 3;
1907 }
1908
1909 return score;
1910 };
1911
1912 for (var i=0; i<matches.length; i++) {
1913 matches[i].__resultScore = _resultScoreFn(matches[i]);
1914 }
1915
1916 matches.sort(function(a,b){
1917 var n = b.__resultScore - a.__resultScore;
1918 if (n == 0) // lexicographical sort if scores are the same
1919 n = (a.label < b.label) ? -1 : 1;
1920 return n;
1921 });
1922}
1923
Scott Main7e447ed2013-02-19 17:22:37 -08001924/* Order the result list based on match quality */
Scott Main0e76e7e2013-03-12 10:24:07 -07001925function rank_autocomplete_api_results(query, matches) {
Scott Mainf5089842012-08-14 16:31:07 -07001926 query = query || '';
Scott Main7e447ed2013-02-19 17:22:37 -08001927 if (!matches || !matches.length)
Scott Mainf5089842012-08-14 16:31:07 -07001928 return;
1929
1930 // helper function that gets the last occurence index of the given regex
1931 // in the given string, or -1 if not found
1932 var _lastSearch = function(s, re) {
1933 if (s == '')
1934 return -1;
1935 var l = -1;
1936 var tmp;
1937 while ((tmp = s.search(re)) >= 0) {
1938 if (l < 0) l = 0;
1939 l += tmp;
1940 s = s.substr(tmp + 1);
1941 }
1942 return l;
1943 };
1944
1945 // helper function that counts the occurrences of a given character in
1946 // a given string
1947 var _countChar = function(s, c) {
1948 var n = 0;
1949 for (var i=0; i<s.length; i++)
1950 if (s.charAt(i) == c) ++n;
1951 return n;
1952 };
1953
1954 var queryLower = query.toLowerCase();
1955 var queryAlnum = (queryLower.match(/\w+/) || [''])[0];
1956 var partPrefixAlnumRE = new RegExp('\\b' + queryAlnum);
1957 var partExactAlnumRE = new RegExp('\\b' + queryAlnum + '\\b');
1958
1959 var _resultScoreFn = function(result) {
1960 // scores are calculated based on exact and prefix matches,
1961 // and then number of path separators (dots) from the last
1962 // match (i.e. favoring classes and deep package names)
1963 var score = 1.0;
1964 var labelLower = result.label.toLowerCase();
1965 var t;
1966 t = _lastSearch(labelLower, partExactAlnumRE);
1967 if (t >= 0) {
1968 // exact part match
1969 var partsAfter = _countChar(labelLower.substr(t + 1), '.');
1970 score *= 200 / (partsAfter + 1);
1971 } else {
1972 t = _lastSearch(labelLower, partPrefixAlnumRE);
1973 if (t >= 0) {
1974 // part prefix match
1975 var partsAfter = _countChar(labelLower.substr(t + 1), '.');
1976 score *= 20 / (partsAfter + 1);
1977 }
1978 }
1979
1980 return score;
1981 };
1982
Scott Main7e447ed2013-02-19 17:22:37 -08001983 for (var i=0; i<matches.length; i++) {
Scott Main0e76e7e2013-03-12 10:24:07 -07001984 // if the API is deprecated, default score is 0; otherwise, perform scoring
1985 if (matches[i].deprecated == "true") {
1986 matches[i].__resultScore = 0;
1987 } else {
1988 matches[i].__resultScore = _resultScoreFn(matches[i]);
1989 }
Scott Mainf5089842012-08-14 16:31:07 -07001990 }
1991
Scott Main7e447ed2013-02-19 17:22:37 -08001992 matches.sort(function(a,b){
Scott Mainf5089842012-08-14 16:31:07 -07001993 var n = b.__resultScore - a.__resultScore;
1994 if (n == 0) // lexicographical sort if scores are the same
1995 n = (a.label < b.label) ? -1 : 1;
1996 return n;
1997 });
1998}
1999
Scott Main7e447ed2013-02-19 17:22:37 -08002000/* Add emphasis to part of string that matches query */
Scott Mainf5089842012-08-14 16:31:07 -07002001function highlight_autocomplete_result_labels(query) {
2002 query = query || '';
Scott Main7e447ed2013-02-19 17:22:37 -08002003 if ((!gMatches || !gMatches.length) && (!gGoogleMatches || !gGoogleMatches.length))
Scott Mainf5089842012-08-14 16:31:07 -07002004 return;
2005
2006 var queryLower = query.toLowerCase();
2007 var queryAlnumDot = (queryLower.match(/[\w\.]+/) || [''])[0];
2008 var queryRE = new RegExp(
2009 '(' + queryAlnumDot.replace(/\./g, '\\.') + ')', 'ig');
2010 for (var i=0; i<gMatches.length; i++) {
2011 gMatches[i].__hilabel = gMatches[i].label.replace(
2012 queryRE, '<b>$1</b>');
2013 }
Scott Main7e447ed2013-02-19 17:22:37 -08002014 for (var i=0; i<gGoogleMatches.length; i++) {
2015 gGoogleMatches[i].__hilabel = gGoogleMatches[i].label.replace(
2016 queryRE, '<b>$1</b>');
2017 }
Scott Mainf5089842012-08-14 16:31:07 -07002018}
2019
2020function search_focus_changed(obj, focused)
2021{
Scott Main3b90aff2013-08-01 18:09:35 -07002022 if (!focused) {
Scott Mainf5089842012-08-14 16:31:07 -07002023 if(obj.value == ""){
2024 $(".search .close").addClass("hide");
2025 }
Scott Main0e76e7e2013-03-12 10:24:07 -07002026 $(".suggest-card").hide();
Scott Mainf5089842012-08-14 16:31:07 -07002027 }
2028}
2029
2030function submit_search() {
2031 var query = document.getElementById('search_autocomplete').value;
2032 location.hash = 'q=' + query;
2033 loadSearchResults();
2034 $("#searchResults").slideDown('slow');
2035 return false;
2036}
2037
2038
2039function hideResults() {
2040 $("#searchResults").slideUp();
2041 $(".search .close").addClass("hide");
2042 location.hash = '';
Scott Main3b90aff2013-08-01 18:09:35 -07002043
Scott Mainf5089842012-08-14 16:31:07 -07002044 $("#search_autocomplete").val("").blur();
Scott Main3b90aff2013-08-01 18:09:35 -07002045
Scott Mainf5089842012-08-14 16:31:07 -07002046 // reset the ajax search callback to nothing, so results don't appear unless ENTER
2047 searchControl.setSearchStartingCallback(this, function(control, searcher, query) {});
Scott Main0e76e7e2013-03-12 10:24:07 -07002048
2049 // forcefully regain key-up event control (previously jacked by search api)
2050 $("#search_autocomplete").keyup(function(event) {
2051 return search_changed(event, false, toRoot);
2052 });
2053
Scott Mainf5089842012-08-14 16:31:07 -07002054 return false;
2055}
2056
2057
2058
2059/* ########################################################## */
2060/* ################ CUSTOM SEARCH ENGINE ################## */
2061/* ########################################################## */
2062
Scott Mainf5089842012-08-14 16:31:07 -07002063var searchControl;
Scott Main0e76e7e2013-03-12 10:24:07 -07002064google.load('search', '1', {"callback" : function() {
2065 searchControl = new google.search.SearchControl();
2066 } });
Scott Mainf5089842012-08-14 16:31:07 -07002067
2068function loadSearchResults() {
2069 document.getElementById("search_autocomplete").style.color = "#000";
2070
Scott Mainf5089842012-08-14 16:31:07 -07002071 searchControl = new google.search.SearchControl();
2072
2073 // use our existing search form and use tabs when multiple searchers are used
2074 drawOptions = new google.search.DrawOptions();
2075 drawOptions.setDrawMode(google.search.SearchControl.DRAW_MODE_TABBED);
2076 drawOptions.setInput(document.getElementById("search_autocomplete"));
2077
2078 // configure search result options
2079 searchOptions = new google.search.SearcherOptions();
2080 searchOptions.setExpandMode(GSearchControl.EXPAND_MODE_OPEN);
2081
2082 // configure each of the searchers, for each tab
2083 devSiteSearcher = new google.search.WebSearch();
2084 devSiteSearcher.setUserDefinedLabel("All");
2085 devSiteSearcher.setSiteRestriction("001482626316274216503:zu90b7s047u");
2086
2087 designSearcher = new google.search.WebSearch();
2088 designSearcher.setUserDefinedLabel("Design");
2089 designSearcher.setSiteRestriction("http://developer.android.com/design/");
2090
2091 trainingSearcher = new google.search.WebSearch();
2092 trainingSearcher.setUserDefinedLabel("Training");
2093 trainingSearcher.setSiteRestriction("http://developer.android.com/training/");
2094
2095 guidesSearcher = new google.search.WebSearch();
2096 guidesSearcher.setUserDefinedLabel("Guides");
2097 guidesSearcher.setSiteRestriction("http://developer.android.com/guide/");
2098
2099 referenceSearcher = new google.search.WebSearch();
2100 referenceSearcher.setUserDefinedLabel("Reference");
2101 referenceSearcher.setSiteRestriction("http://developer.android.com/reference/");
2102
Scott Maindf08ada2012-12-03 08:54:37 -08002103 googleSearcher = new google.search.WebSearch();
2104 googleSearcher.setUserDefinedLabel("Google Services");
2105 googleSearcher.setSiteRestriction("http://developer.android.com/google/");
2106
Scott Mainf5089842012-08-14 16:31:07 -07002107 blogSearcher = new google.search.WebSearch();
2108 blogSearcher.setUserDefinedLabel("Blog");
2109 blogSearcher.setSiteRestriction("http://android-developers.blogspot.com");
2110
2111 // add each searcher to the search control
2112 searchControl.addSearcher(devSiteSearcher, searchOptions);
2113 searchControl.addSearcher(designSearcher, searchOptions);
2114 searchControl.addSearcher(trainingSearcher, searchOptions);
2115 searchControl.addSearcher(guidesSearcher, searchOptions);
2116 searchControl.addSearcher(referenceSearcher, searchOptions);
Scott Maindf08ada2012-12-03 08:54:37 -08002117 searchControl.addSearcher(googleSearcher, searchOptions);
Scott Mainf5089842012-08-14 16:31:07 -07002118 searchControl.addSearcher(blogSearcher, searchOptions);
2119
2120 // configure result options
2121 searchControl.setResultSetSize(google.search.Search.LARGE_RESULTSET);
2122 searchControl.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
2123 searchControl.setTimeoutInterval(google.search.SearchControl.TIMEOUT_SHORT);
2124 searchControl.setNoResultsString(google.search.SearchControl.NO_RESULTS_DEFAULT_STRING);
2125
2126 // upon ajax search, refresh the url and search title
2127 searchControl.setSearchStartingCallback(this, function(control, searcher, query) {
2128 updateResultTitle(query);
2129 var query = document.getElementById('search_autocomplete').value;
2130 location.hash = 'q=' + query;
2131 });
2132
Scott Mainde295272013-03-25 15:48:35 -07002133 // once search results load, set up click listeners
2134 searchControl.setSearchCompleteCallback(this, function(control, searcher, query) {
2135 addResultClickListeners();
2136 });
2137
Scott Mainf5089842012-08-14 16:31:07 -07002138 // draw the search results box
2139 searchControl.draw(document.getElementById("leftSearchControl"), drawOptions);
2140
2141 // get query and execute the search
2142 searchControl.execute(decodeURI(getQuery(location.hash)));
2143
2144 document.getElementById("search_autocomplete").focus();
2145 addTabListeners();
2146}
2147// End of loadSearchResults
2148
2149
2150google.setOnLoadCallback(function(){
2151 if (location.hash.indexOf("q=") == -1) {
2152 // if there's no query in the url, don't search and make sure results are hidden
2153 $('#searchResults').hide();
2154 return;
2155 } else {
2156 // first time loading search results for this page
2157 $('#searchResults').slideDown('slow');
2158 $(".search .close").removeClass("hide");
2159 loadSearchResults();
2160 }
2161}, true);
2162
2163// when an event on the browser history occurs (back, forward, load) requery hash and do search
2164$(window).hashchange( function(){
Scott Maine624b3f2013-09-12 12:56:41 -07002165 // Handle hash changes in the samples browser
2166 if ($("body").hasClass("samples") && location.href.indexOf("/samples/index.html") != -1) {
2167 showSamples();
2168 highlightSidenav();
2169 resizeNav();
2170 }
Scott Mainf5089842012-08-14 16:31:07 -07002171 // Exit if the hash isn't a search query or there's an error in the query
2172 if ((location.hash.indexOf("q=") == -1) || (query == "undefined")) {
2173 // If the results pane is open, close it.
2174 if (!$("#searchResults").is(":hidden")) {
2175 hideResults();
2176 }
2177 return;
2178 }
2179
2180 // Otherwise, we have a search to do
2181 var query = decodeURI(getQuery(location.hash));
2182 searchControl.execute(query);
2183 $('#searchResults').slideDown('slow');
2184 $("#search_autocomplete").focus();
2185 $(".search .close").removeClass("hide");
2186
2187 updateResultTitle(query);
2188});
2189
2190function updateResultTitle(query) {
2191 $("#searchTitle").html("Results for <em>" + escapeHTML(query) + "</em>");
2192}
2193
2194// forcefully regain key-up event control (previously jacked by search api)
2195$("#search_autocomplete").keyup(function(event) {
2196 return search_changed(event, false, toRoot);
2197});
2198
2199// add event listeners to each tab so we can track the browser history
2200function addTabListeners() {
2201 var tabHeaders = $(".gsc-tabHeader");
2202 for (var i = 0; i < tabHeaders.length; i++) {
2203 $(tabHeaders[i]).attr("id",i).click(function() {
2204 /*
2205 // make a copy of the page numbers for the search left pane
2206 setTimeout(function() {
2207 // remove any residual page numbers
2208 $('#searchResults .gsc-tabsArea .gsc-cursor-box.gs-bidi-start-align').remove();
Scott Main3b90aff2013-08-01 18:09:35 -07002209 // move the page numbers to the left position; make a clone,
Scott Mainf5089842012-08-14 16:31:07 -07002210 // because the element is drawn to the DOM only once
Scott Main3b90aff2013-08-01 18:09:35 -07002211 // and because we're going to remove it (previous line),
2212 // we need it to be available to move again as the user navigates
Scott Mainf5089842012-08-14 16:31:07 -07002213 $('#searchResults .gsc-webResult .gsc-cursor-box.gs-bidi-start-align:visible')
2214 .clone().appendTo('#searchResults .gsc-tabsArea');
2215 }, 200);
2216 */
2217 });
2218 }
2219 setTimeout(function(){$(tabHeaders[0]).click()},200);
2220}
2221
Scott Mainde295272013-03-25 15:48:35 -07002222// add analytics tracking events to each result link
2223function addResultClickListeners() {
2224 $("#searchResults a.gs-title").each(function(index, link) {
2225 // When user clicks enter for Google search results, track it
2226 $(link).click(function() {
2227 _gaq.push(['_trackEvent', 'Google Click', 'clicked: ' + $(this).text(),
2228 'from: ' + $("#search_autocomplete").val()]);
2229 });
2230 });
2231}
2232
Scott Mainf5089842012-08-14 16:31:07 -07002233
2234function getQuery(hash) {
2235 var queryParts = hash.split('=');
2236 return queryParts[1];
2237}
2238
2239/* returns the given string with all HTML brackets converted to entities
2240 TODO: move this to the site's JS library */
2241function escapeHTML(string) {
2242 return string.replace(/</g,"&lt;")
2243 .replace(/>/g,"&gt;");
2244}
2245
2246
2247
2248
2249
2250
2251
2252/* ######################################################## */
2253/* ################# JAVADOC REFERENCE ################### */
2254/* ######################################################## */
2255
Scott Main65511c02012-09-07 15:51:32 -07002256/* Initialize some droiddoc stuff, but only if we're in the reference */
Scott Main52dd2062013-08-15 12:22:28 -07002257if (location.pathname.indexOf("/reference") == 0) {
2258 if(!(location.pathname.indexOf("/reference-gms/packages.html") == 0)
2259 && !(location.pathname.indexOf("/reference-gcm/packages.html") == 0)
2260 && !(location.pathname.indexOf("/reference/com/google") == 0)) {
Robert Ly67d75f12012-12-03 12:53:42 -08002261 $(document).ready(function() {
2262 // init available apis based on user pref
2263 changeApiLevel();
2264 initSidenavHeightResize()
2265 });
2266 }
Scott Main65511c02012-09-07 15:51:32 -07002267}
Scott Mainf5089842012-08-14 16:31:07 -07002268
2269var API_LEVEL_COOKIE = "api_level";
2270var minLevel = 1;
2271var maxLevel = 1;
2272
2273/******* SIDENAV DIMENSIONS ************/
Scott Main3b90aff2013-08-01 18:09:35 -07002274
Scott Mainf5089842012-08-14 16:31:07 -07002275 function initSidenavHeightResize() {
2276 // Change the drag bar size to nicely fit the scrollbar positions
2277 var $dragBar = $(".ui-resizable-s");
2278 $dragBar.css({'width': $dragBar.parent().width() - 5 + "px"});
Scott Main3b90aff2013-08-01 18:09:35 -07002279
2280 $( "#resize-packages-nav" ).resizable({
Scott Mainf5089842012-08-14 16:31:07 -07002281 containment: "#nav-panels",
2282 handles: "s",
2283 alsoResize: "#packages-nav",
2284 resize: function(event, ui) { resizeNav(); }, /* resize the nav while dragging */
2285 stop: function(event, ui) { saveNavPanels(); } /* once stopped, save the sizes to cookie */
2286 });
Scott Main3b90aff2013-08-01 18:09:35 -07002287
Scott Mainf5089842012-08-14 16:31:07 -07002288 }
Scott Main3b90aff2013-08-01 18:09:35 -07002289
Scott Mainf5089842012-08-14 16:31:07 -07002290function updateSidenavFixedWidth() {
2291 if (!navBarIsFixed) return;
2292 $('#devdoc-nav').css({
2293 'width' : $('#side-nav').css('width'),
2294 'margin' : $('#side-nav').css('margin')
2295 });
2296 $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'});
Scott Main3b90aff2013-08-01 18:09:35 -07002297
Scott Mainf5089842012-08-14 16:31:07 -07002298 initSidenavHeightResize();
2299}
2300
2301function updateSidenavFullscreenWidth() {
2302 if (!navBarIsFixed) return;
2303 $('#devdoc-nav').css({
2304 'width' : $('#side-nav').css('width'),
2305 'margin' : $('#side-nav').css('margin')
2306 });
2307 $('#devdoc-nav .totop').css({'left': 'inherit'});
Scott Main3b90aff2013-08-01 18:09:35 -07002308
Scott Mainf5089842012-08-14 16:31:07 -07002309 initSidenavHeightResize();
2310}
2311
2312function buildApiLevelSelector() {
2313 maxLevel = SINCE_DATA.length;
2314 var userApiLevel = parseInt(readCookie(API_LEVEL_COOKIE));
2315 userApiLevel = userApiLevel == 0 ? maxLevel : userApiLevel; // If there's no cookie (zero), use the max by default
2316
2317 minLevel = parseInt($("#doc-api-level").attr("class"));
2318 // Handle provisional api levels; the provisional level will always be the highest possible level
2319 // Provisional api levels will also have a length; other stuff that's just missing a level won't,
2320 // so leave those kinds of entities at the default level of 1 (for example, the R.styleable class)
2321 if (isNaN(minLevel) && minLevel.length) {
2322 minLevel = maxLevel;
2323 }
2324 var select = $("#apiLevelSelector").html("").change(changeApiLevel);
2325 for (var i = maxLevel-1; i >= 0; i--) {
2326 var option = $("<option />").attr("value",""+SINCE_DATA[i]).append(""+SINCE_DATA[i]);
2327 // if (SINCE_DATA[i] < minLevel) option.addClass("absent"); // always false for strings (codenames)
2328 select.append(option);
2329 }
2330
2331 // get the DOM element and use setAttribute cuz IE6 fails when using jquery .attr('selected',true)
2332 var selectedLevelItem = $("#apiLevelSelector option[value='"+userApiLevel+"']").get(0);
2333 selectedLevelItem.setAttribute('selected',true);
2334}
2335
2336function changeApiLevel() {
2337 maxLevel = SINCE_DATA.length;
2338 var selectedLevel = maxLevel;
2339
2340 selectedLevel = parseInt($("#apiLevelSelector option:selected").val());
2341 toggleVisisbleApis(selectedLevel, "body");
2342
2343 var date = new Date();
2344 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
2345 var expiration = date.toGMTString();
2346 writeCookie(API_LEVEL_COOKIE, selectedLevel, null, expiration);
2347
2348 if (selectedLevel < minLevel) {
2349 var thing = ($("#jd-header").html().indexOf("package") != -1) ? "package" : "class";
Scott Main8f24ca82012-11-16 10:34:22 -08002350 $("#naMessage").show().html("<div><p><strong>This " + thing
2351 + " requires API level " + minLevel + " or higher.</strong></p>"
2352 + "<p>This document is hidden because your selected API level for the documentation is "
2353 + selectedLevel + ". You can change the documentation API level with the selector "
2354 + "above the left navigation.</p>"
2355 + "<p>For more information about specifying the API level your app requires, "
2356 + "read <a href='" + toRoot + "training/basics/supporting-devices/platforms.html'"
2357 + ">Supporting Different Platform Versions</a>.</p>"
2358 + "<input type='button' value='OK, make this page visible' "
2359 + "title='Change the API level to " + minLevel + "' "
2360 + "onclick='$(\"#apiLevelSelector\").val(\"" + minLevel + "\");changeApiLevel();' />"
2361 + "</div>");
Scott Mainf5089842012-08-14 16:31:07 -07002362 } else {
2363 $("#naMessage").hide();
2364 }
2365}
2366
2367function toggleVisisbleApis(selectedLevel, context) {
2368 var apis = $(".api",context);
2369 apis.each(function(i) {
2370 var obj = $(this);
2371 var className = obj.attr("class");
2372 var apiLevelIndex = className.lastIndexOf("-")+1;
2373 var apiLevelEndIndex = className.indexOf(" ", apiLevelIndex);
2374 apiLevelEndIndex = apiLevelEndIndex != -1 ? apiLevelEndIndex : className.length;
2375 var apiLevel = className.substring(apiLevelIndex, apiLevelEndIndex);
2376 if (apiLevel.length == 0) { // for odd cases when the since data is actually missing, just bail
2377 return;
2378 }
2379 apiLevel = parseInt(apiLevel);
2380
2381 // Handle provisional api levels; if this item's level is the provisional one, set it to the max
2382 var selectedLevelNum = parseInt(selectedLevel)
2383 var apiLevelNum = parseInt(apiLevel);
2384 if (isNaN(apiLevelNum)) {
2385 apiLevelNum = maxLevel;
2386 }
2387
2388 // Grey things out that aren't available and give a tooltip title
2389 if (apiLevelNum > selectedLevelNum) {
2390 obj.addClass("absent").attr("title","Requires API Level \""
2391 + apiLevel + "\" or higher");
Scott Main3b90aff2013-08-01 18:09:35 -07002392 }
Scott Mainf5089842012-08-14 16:31:07 -07002393 else obj.removeClass("absent").removeAttr("title");
2394 });
2395}
2396
2397
2398
2399
2400/* ################# SIDENAV TREE VIEW ################### */
2401
2402function new_node(me, mom, text, link, children_data, api_level)
2403{
2404 var node = new Object();
2405 node.children = Array();
2406 node.children_data = children_data;
2407 node.depth = mom.depth + 1;
2408
2409 node.li = document.createElement("li");
2410 mom.get_children_ul().appendChild(node.li);
2411
2412 node.label_div = document.createElement("div");
2413 node.label_div.className = "label";
2414 if (api_level != null) {
2415 $(node.label_div).addClass("api");
2416 $(node.label_div).addClass("api-level-"+api_level);
2417 }
2418 node.li.appendChild(node.label_div);
2419
2420 if (children_data != null) {
2421 node.expand_toggle = document.createElement("a");
2422 node.expand_toggle.href = "javascript:void(0)";
2423 node.expand_toggle.onclick = function() {
2424 if (node.expanded) {
2425 $(node.get_children_ul()).slideUp("fast");
2426 node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
2427 node.expanded = false;
2428 } else {
2429 expand_node(me, node);
2430 }
2431 };
2432 node.label_div.appendChild(node.expand_toggle);
2433
2434 node.plus_img = document.createElement("img");
2435 node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
2436 node.plus_img.className = "plus";
2437 node.plus_img.width = "8";
2438 node.plus_img.border = "0";
2439 node.expand_toggle.appendChild(node.plus_img);
2440
2441 node.expanded = false;
2442 }
2443
2444 var a = document.createElement("a");
2445 node.label_div.appendChild(a);
2446 node.label = document.createTextNode(text);
2447 a.appendChild(node.label);
2448 if (link) {
2449 a.href = me.toroot + link;
2450 } else {
2451 if (children_data != null) {
2452 a.className = "nolink";
2453 a.href = "javascript:void(0)";
2454 a.onclick = node.expand_toggle.onclick;
2455 // This next line shouldn't be necessary. I'll buy a beer for the first
2456 // person who figures out how to remove this line and have the link
2457 // toggle shut on the first try. --joeo@android.com
2458 node.expanded = false;
2459 }
2460 }
Scott Main3b90aff2013-08-01 18:09:35 -07002461
Scott Mainf5089842012-08-14 16:31:07 -07002462
2463 node.children_ul = null;
2464 node.get_children_ul = function() {
2465 if (!node.children_ul) {
2466 node.children_ul = document.createElement("ul");
2467 node.children_ul.className = "children_ul";
2468 node.children_ul.style.display = "none";
2469 node.li.appendChild(node.children_ul);
2470 }
2471 return node.children_ul;
2472 };
2473
2474 return node;
2475}
2476
Robert Lyd2dd6e52012-11-29 21:28:48 -08002477
2478
2479
Scott Mainf5089842012-08-14 16:31:07 -07002480function expand_node(me, node)
2481{
2482 if (node.children_data && !node.expanded) {
2483 if (node.children_visited) {
2484 $(node.get_children_ul()).slideDown("fast");
2485 } else {
2486 get_node(me, node);
2487 if ($(node.label_div).hasClass("absent")) {
2488 $(node.get_children_ul()).addClass("absent");
Scott Main3b90aff2013-08-01 18:09:35 -07002489 }
Scott Mainf5089842012-08-14 16:31:07 -07002490 $(node.get_children_ul()).slideDown("fast");
2491 }
2492 node.plus_img.src = me.toroot + "assets/images/triangle-opened-small.png";
2493 node.expanded = true;
2494
2495 // perform api level toggling because new nodes are new to the DOM
2496 var selectedLevel = $("#apiLevelSelector option:selected").val();
2497 toggleVisisbleApis(selectedLevel, "#side-nav");
2498 }
2499}
2500
2501function get_node(me, mom)
2502{
2503 mom.children_visited = true;
2504 for (var i in mom.children_data) {
2505 var node_data = mom.children_data[i];
2506 mom.children[i] = new_node(me, mom, node_data[0], node_data[1],
2507 node_data[2], node_data[3]);
2508 }
2509}
2510
2511function this_page_relative(toroot)
2512{
2513 var full = document.location.pathname;
2514 var file = "";
2515 if (toroot.substr(0, 1) == "/") {
2516 if (full.substr(0, toroot.length) == toroot) {
2517 return full.substr(toroot.length);
2518 } else {
2519 // the file isn't under toroot. Fail.
2520 return null;
2521 }
2522 } else {
2523 if (toroot != "./") {
2524 toroot = "./" + toroot;
2525 }
2526 do {
2527 if (toroot.substr(toroot.length-3, 3) == "../" || toroot == "./") {
2528 var pos = full.lastIndexOf("/");
2529 file = full.substr(pos) + file;
2530 full = full.substr(0, pos);
2531 toroot = toroot.substr(0, toroot.length-3);
2532 }
2533 } while (toroot != "" && toroot != "/");
2534 return file.substr(1);
2535 }
2536}
2537
2538function find_page(url, data)
2539{
2540 var nodes = data;
2541 var result = null;
2542 for (var i in nodes) {
2543 var d = nodes[i];
2544 if (d[1] == url) {
2545 return new Array(i);
2546 }
2547 else if (d[2] != null) {
2548 result = find_page(url, d[2]);
2549 if (result != null) {
2550 return (new Array(i).concat(result));
2551 }
2552 }
2553 }
2554 return null;
2555}
2556
Scott Mainf5089842012-08-14 16:31:07 -07002557function init_default_navtree(toroot) {
Scott Main25e73002013-03-27 15:24:06 -07002558 // load json file for navtree data
2559 $.getScript(toRoot + 'navtree_data.js', function(data, textStatus, jqxhr) {
2560 // when the file is loaded, initialize the tree
2561 if(jqxhr.status === 200) {
2562 init_navtree("tree-list", toroot, NAVTREE_DATA);
2563 }
2564 });
Scott Main3b90aff2013-08-01 18:09:35 -07002565
Scott Mainf5089842012-08-14 16:31:07 -07002566 // perform api level toggling because because the whole tree is new to the DOM
2567 var selectedLevel = $("#apiLevelSelector option:selected").val();
2568 toggleVisisbleApis(selectedLevel, "#side-nav");
2569}
2570
2571function init_navtree(navtree_id, toroot, root_nodes)
2572{
2573 var me = new Object();
2574 me.toroot = toroot;
2575 me.node = new Object();
2576
2577 me.node.li = document.getElementById(navtree_id);
2578 me.node.children_data = root_nodes;
2579 me.node.children = new Array();
2580 me.node.children_ul = document.createElement("ul");
2581 me.node.get_children_ul = function() { return me.node.children_ul; };
2582 //me.node.children_ul.className = "children_ul";
2583 me.node.li.appendChild(me.node.children_ul);
2584 me.node.depth = 0;
2585
2586 get_node(me, me.node);
2587
2588 me.this_page = this_page_relative(toroot);
2589 me.breadcrumbs = find_page(me.this_page, root_nodes);
2590 if (me.breadcrumbs != null && me.breadcrumbs.length != 0) {
2591 var mom = me.node;
2592 for (var i in me.breadcrumbs) {
2593 var j = me.breadcrumbs[i];
2594 mom = mom.children[j];
2595 expand_node(me, mom);
2596 }
2597 mom.label_div.className = mom.label_div.className + " selected";
2598 addLoadEvent(function() {
2599 scrollIntoView("nav-tree");
2600 });
2601 }
2602}
2603
Dirk Dougherty4f7e5152010-09-16 10:43:40 -07002604
2605
2606
2607
2608
2609
2610
Robert Lyd2dd6e52012-11-29 21:28:48 -08002611/* TODO: eliminate redundancy with non-google functions */
2612function init_google_navtree(navtree_id, toroot, root_nodes)
2613{
2614 var me = new Object();
2615 me.toroot = toroot;
2616 me.node = new Object();
2617
2618 me.node.li = document.getElementById(navtree_id);
2619 me.node.children_data = root_nodes;
2620 me.node.children = new Array();
2621 me.node.children_ul = document.createElement("ul");
2622 me.node.get_children_ul = function() { return me.node.children_ul; };
2623 //me.node.children_ul.className = "children_ul";
2624 me.node.li.appendChild(me.node.children_ul);
2625 me.node.depth = 0;
2626
2627 get_google_node(me, me.node);
Robert Lyd2dd6e52012-11-29 21:28:48 -08002628}
2629
2630function new_google_node(me, mom, text, link, children_data, api_level)
2631{
2632 var node = new Object();
2633 var child;
2634 node.children = Array();
2635 node.children_data = children_data;
2636 node.depth = mom.depth + 1;
2637 node.get_children_ul = function() {
2638 if (!node.children_ul) {
Scott Main3b90aff2013-08-01 18:09:35 -07002639 node.children_ul = document.createElement("ul");
2640 node.children_ul.className = "tree-list-children";
Robert Lyd2dd6e52012-11-29 21:28:48 -08002641 node.li.appendChild(node.children_ul);
2642 }
2643 return node.children_ul;
2644 };
2645 node.li = document.createElement("li");
2646
2647 mom.get_children_ul().appendChild(node.li);
Scott Main3b90aff2013-08-01 18:09:35 -07002648
2649
Robert Lyd2dd6e52012-11-29 21:28:48 -08002650 if(link) {
2651 child = document.createElement("a");
2652
2653 }
2654 else {
2655 child = document.createElement("span");
Scott Mainac71b2b2012-11-30 14:40:58 -08002656 child.className = "tree-list-subtitle";
Robert Lyd2dd6e52012-11-29 21:28:48 -08002657
2658 }
2659 if (children_data != null) {
2660 node.li.className="nav-section";
2661 node.label_div = document.createElement("div");
Scott Main3b90aff2013-08-01 18:09:35 -07002662 node.label_div.className = "nav-section-header-ref";
Robert Lyd2dd6e52012-11-29 21:28:48 -08002663 node.li.appendChild(node.label_div);
2664 get_google_node(me, node);
2665 node.label_div.appendChild(child);
2666 }
2667 else {
2668 node.li.appendChild(child);
2669 }
2670 if(link) {
2671 child.href = me.toroot + link;
2672 }
2673 node.label = document.createTextNode(text);
2674 child.appendChild(node.label);
2675
2676 node.children_ul = null;
2677
2678 return node;
2679}
2680
2681function get_google_node(me, mom)
2682{
2683 mom.children_visited = true;
2684 var linkText;
2685 for (var i in mom.children_data) {
2686 var node_data = mom.children_data[i];
2687 linkText = node_data[0];
2688
2689 if(linkText.match("^"+"com.google.android")=="com.google.android"){
2690 linkText = linkText.substr(19, linkText.length);
2691 }
2692 mom.children[i] = new_google_node(me, mom, linkText, node_data[1],
2693 node_data[2], node_data[3]);
2694 }
2695}
Scott Mainad08f072013-08-20 16:49:57 -07002696
2697
2698
2699
2700
2701
2702/****** NEW version of script to build google and sample navs dynamically ******/
2703// TODO: update Google reference docs to tolerate this new implementation
2704
Scott Maine624b3f2013-09-12 12:56:41 -07002705var NODE_NAME = 0;
2706var NODE_HREF = 1;
2707var NODE_GROUP = 2;
2708var NODE_TAGS = 3;
2709var NODE_CHILDREN = 4;
2710
Scott Mainad08f072013-08-20 16:49:57 -07002711function init_google_navtree2(navtree_id, data)
2712{
2713 var $containerUl = $("#"+navtree_id);
Scott Mainad08f072013-08-20 16:49:57 -07002714 for (var i in data) {
2715 var node_data = data[i];
2716 $containerUl.append(new_google_node2(node_data));
2717 }
2718
Scott Main70557ee2013-10-30 14:47:40 -07002719 // Make all third-generation list items 'sticky' to prevent them from collapsing
2720 $containerUl.find('li li li.nav-section').addClass('sticky');
2721
Scott Mainad08f072013-08-20 16:49:57 -07002722 initExpandableNavItems("#"+navtree_id);
2723}
2724
2725function new_google_node2(node_data)
2726{
Scott Maine624b3f2013-09-12 12:56:41 -07002727 var linkText = node_data[NODE_NAME];
Scott Mainad08f072013-08-20 16:49:57 -07002728 if(linkText.match("^"+"com.google.android")=="com.google.android"){
2729 linkText = linkText.substr(19, linkText.length);
2730 }
2731 var $li = $('<li>');
2732 var $a;
Scott Maine624b3f2013-09-12 12:56:41 -07002733 if (node_data[NODE_HREF] != null) {
Scott Main70557ee2013-10-30 14:47:40 -07002734 $a = $('<a href="' + toRoot + node_data[NODE_HREF] + '" title="' + linkText + '" >'
2735 + linkText + '</a>');
Scott Mainad08f072013-08-20 16:49:57 -07002736 } else {
Scott Main70557ee2013-10-30 14:47:40 -07002737 $a = $('<a href="#" onclick="return false;" title="' + linkText + '" >'
2738 + linkText + '/</a>');
Scott Mainad08f072013-08-20 16:49:57 -07002739 }
2740 var $childUl = $('<ul>');
Scott Maine624b3f2013-09-12 12:56:41 -07002741 if (node_data[NODE_CHILDREN] != null) {
Scott Mainad08f072013-08-20 16:49:57 -07002742 $li.addClass("nav-section");
2743 $a = $('<div class="nav-section-header">').append($a);
Scott Maine624b3f2013-09-12 12:56:41 -07002744 if (node_data[NODE_HREF] == null) $a.addClass('empty');
Scott Mainad08f072013-08-20 16:49:57 -07002745
Scott Maine624b3f2013-09-12 12:56:41 -07002746 for (var i in node_data[NODE_CHILDREN]) {
2747 var child_node_data = node_data[NODE_CHILDREN][i];
Scott Mainad08f072013-08-20 16:49:57 -07002748 $childUl.append(new_google_node2(child_node_data));
2749 }
2750 $li.append($childUl);
2751 }
2752 $li.prepend($a);
2753
2754 return $li;
2755}
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
Robert Lyd2dd6e52012-11-29 21:28:48 -08002767function showGoogleRefTree() {
2768 init_default_google_navtree(toRoot);
2769 init_default_gcm_navtree(toRoot);
Robert Lyd2dd6e52012-11-29 21:28:48 -08002770}
2771
2772function init_default_google_navtree(toroot) {
Scott Mainf6145542013-04-01 16:38:11 -07002773 // load json file for navtree data
2774 $.getScript(toRoot + 'gms_navtree_data.js', function(data, textStatus, jqxhr) {
2775 // when the file is loaded, initialize the tree
2776 if(jqxhr.status === 200) {
2777 init_google_navtree("gms-tree-list", toroot, GMS_NAVTREE_DATA);
2778 highlightSidenav();
2779 resizeNav();
2780 }
2781 });
Robert Lyd2dd6e52012-11-29 21:28:48 -08002782}
2783
2784function init_default_gcm_navtree(toroot) {
Scott Mainf6145542013-04-01 16:38:11 -07002785 // load json file for navtree data
2786 $.getScript(toRoot + 'gcm_navtree_data.js', function(data, textStatus, jqxhr) {
2787 // when the file is loaded, initialize the tree
2788 if(jqxhr.status === 200) {
2789 init_google_navtree("gcm-tree-list", toroot, GCM_NAVTREE_DATA);
2790 highlightSidenav();
2791 resizeNav();
2792 }
2793 });
Robert Lyd2dd6e52012-11-29 21:28:48 -08002794}
2795
Dirk Dougherty4f7e5152010-09-16 10:43:40 -07002796function showSamplesRefTree() {
2797 init_default_samples_navtree(toRoot);
2798}
2799
2800function init_default_samples_navtree(toroot) {
2801 // load json file for navtree data
2802 $.getScript(toRoot + 'samples_navtree_data.js', function(data, textStatus, jqxhr) {
2803 // when the file is loaded, initialize the tree
2804 if(jqxhr.status === 200) {
Scott Mainf1435b72013-10-30 16:27:38 -07002805 // hack to remove the "about the samples" link then put it back in
2806 // after we nuke the list to remove the dummy static list of samples
2807 var $firstLi = $("#nav.samples-nav > li:first-child").clone();
2808 $("#nav.samples-nav").empty();
2809 $("#nav.samples-nav").append($firstLi);
2810
Scott Mainad08f072013-08-20 16:49:57 -07002811 init_google_navtree2("nav.samples-nav", SAMPLES_NAVTREE_DATA);
Dirk Dougherty4f7e5152010-09-16 10:43:40 -07002812 highlightSidenav();
2813 resizeNav();
2814 }
2815 });
2816}
2817
Scott Mainf5089842012-08-14 16:31:07 -07002818/* TOGGLE INHERITED MEMBERS */
2819
2820/* Toggle an inherited class (arrow toggle)
2821 * @param linkObj The link that was clicked.
2822 * @param expand 'true' to ensure it's expanded. 'false' to ensure it's closed.
2823 * 'null' to simply toggle.
2824 */
2825function toggleInherited(linkObj, expand) {
2826 var base = linkObj.getAttribute("id");
2827 var list = document.getElementById(base + "-list");
2828 var summary = document.getElementById(base + "-summary");
2829 var trigger = document.getElementById(base + "-trigger");
2830 var a = $(linkObj);
2831 if ( (expand == null && a.hasClass("closed")) || expand ) {
2832 list.style.display = "none";
2833 summary.style.display = "block";
2834 trigger.src = toRoot + "assets/images/triangle-opened.png";
2835 a.removeClass("closed");
2836 a.addClass("opened");
2837 } else if ( (expand == null && a.hasClass("opened")) || (expand == false) ) {
2838 list.style.display = "block";
2839 summary.style.display = "none";
2840 trigger.src = toRoot + "assets/images/triangle-closed.png";
2841 a.removeClass("opened");
2842 a.addClass("closed");
2843 }
2844 return false;
2845}
2846
2847/* Toggle all inherited classes in a single table (e.g. all inherited methods)
2848 * @param linkObj The link that was clicked.
2849 * @param expand 'true' to ensure it's expanded. 'false' to ensure it's closed.
2850 * 'null' to simply toggle.
2851 */
2852function toggleAllInherited(linkObj, expand) {
2853 var a = $(linkObj);
2854 var table = $(a.parent().parent().parent()); // ugly way to get table/tbody
2855 var expandos = $(".jd-expando-trigger", table);
2856 if ( (expand == null && a.text() == "[Expand]") || expand ) {
2857 expandos.each(function(i) {
2858 toggleInherited(this, true);
2859 });
2860 a.text("[Collapse]");
2861 } else if ( (expand == null && a.text() == "[Collapse]") || (expand == false) ) {
2862 expandos.each(function(i) {
2863 toggleInherited(this, false);
2864 });
2865 a.text("[Expand]");
2866 }
2867 return false;
2868}
2869
2870/* Toggle all inherited members in the class (link in the class title)
2871 */
2872function toggleAllClassInherited() {
2873 var a = $("#toggleAllClassInherited"); // get toggle link from class title
2874 var toggles = $(".toggle-all", $("#body-content"));
2875 if (a.text() == "[Expand All]") {
2876 toggles.each(function(i) {
2877 toggleAllInherited(this, true);
2878 });
2879 a.text("[Collapse All]");
2880 } else {
2881 toggles.each(function(i) {
2882 toggleAllInherited(this, false);
2883 });
2884 a.text("[Expand All]");
2885 }
2886 return false;
2887}
2888
2889/* Expand all inherited members in the class. Used when initiating page search */
2890function ensureAllInheritedExpanded() {
2891 var toggles = $(".toggle-all", $("#body-content"));
2892 toggles.each(function(i) {
2893 toggleAllInherited(this, true);
2894 });
2895 $("#toggleAllClassInherited").text("[Collapse All]");
2896}
2897
2898
2899/* HANDLE KEY EVENTS
2900 * - Listen for Ctrl+F (Cmd on Mac) and expand all inherited members (to aid page search)
2901 */
2902var agent = navigator['userAgent'].toLowerCase();
2903var mac = agent.indexOf("macintosh") != -1;
2904
2905$(document).keydown( function(e) {
2906var control = mac ? e.metaKey && !e.ctrlKey : e.ctrlKey; // get ctrl key
2907 if (control && e.which == 70) { // 70 is "F"
2908 ensureAllInheritedExpanded();
2909 }
2910});
Scott Main498d7102013-08-21 15:47:38 -07002911
2912
2913
2914
2915
2916
2917/* On-demand functions */
2918
2919/** Move sample code line numbers out of PRE block and into non-copyable column */
2920function initCodeLineNumbers() {
2921 var numbers = $("#codesample-block a.number");
2922 if (numbers.length) {
2923 $("#codesample-line-numbers").removeClass("hidden").append(numbers);
2924 }
2925
2926 $(document).ready(function() {
2927 // select entire line when clicked
2928 $("span.code-line").click(function() {
2929 if (!shifted) {
2930 selectText(this);
2931 }
2932 });
2933 // invoke line link on double click
2934 $(".code-line").dblclick(function() {
2935 document.location.hash = $(this).attr('id');
2936 });
2937 // highlight the line when hovering on the number
2938 $("#codesample-line-numbers a.number").mouseover(function() {
2939 var id = $(this).attr('href');
2940 $(id).css('background','#e7e7e7');
2941 });
2942 $("#codesample-line-numbers a.number").mouseout(function() {
2943 var id = $(this).attr('href');
2944 $(id).css('background','none');
2945 });
2946 });
2947}
2948
2949// create SHIFT key binder to avoid the selectText method when selecting multiple lines
2950var shifted = false;
2951$(document).bind('keyup keydown', function(e){shifted = e.shiftKey; return true;} );
2952
2953// courtesy of jasonedelman.com
2954function selectText(element) {
2955 var doc = document
2956 , range, selection
2957 ;
2958 if (doc.body.createTextRange) { //ms
2959 range = doc.body.createTextRange();
2960 range.moveToElementText(element);
2961 range.select();
2962 } else if (window.getSelection) { //all others
Scott Main70557ee2013-10-30 14:47:40 -07002963 selection = window.getSelection();
Scott Main498d7102013-08-21 15:47:38 -07002964 range = doc.createRange();
2965 range.selectNodeContents(element);
2966 selection.removeAllRanges();
2967 selection.addRange(range);
2968 }
Scott Main285f0772013-08-22 23:22:09 +00002969}