blob: e15ab8435ac050e1fc44f3a2781b36fa753201dd [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
9
Scott Main1b3db112012-07-03 14:06:22 -070010var basePath = getBaseUri(location.pathname);
11var SITE_ROOT = toRoot + basePath.substring(1,basePath.indexOf("/",1));
12
Scott Maine4d8f1b2012-06-21 18:03:05 -070013
14/****** ON LOAD SET UP STUFF *********/
15
16var navBarIsFixed = false;
17$(document).ready(function() {
18 // init the fullscreen toggle click event
19 $('#nav-swap .fullscreen').click(function(){
20 if ($(this).hasClass('disabled')) {
21 toggleFullscreen(true);
22 } else {
23 toggleFullscreen(false);
24 }
25 });
26
27 // initialize the divs with custom scrollbars
28 $('.scroll-pane').jScrollPane( {verticalGutter:0} );
29
30 // add HRs below all H2s (except for a few other h2 variants)
Scott Maindb3678b2012-10-23 14:13:41 -070031 $('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 -070032
33 // set search's onkeyup handler here so we can show suggestions
34 // even while search results are visible
Scott Main1b3db112012-07-03 14:06:22 -070035 $("#search_autocomplete").keyup(function() {return search_changed(event, false, toRoot)});
Scott Maine4d8f1b2012-06-21 18:03:05 -070036
37 // set up the search close button
38 $('.search .close').click(function() {
39 $searchInput = $('#search_autocomplete');
40 $searchInput.attr('value', '');
41 $(this).addClass("hide");
42 $("#search-container").removeClass('active');
43 $("#search_autocomplete").blur();
44 search_focus_changed($searchInput.get(), false); // see search_autocomplete.js
45 hideResults(); // see search_autocomplete.js
46 });
47 $('.search').click(function() {
48 if (!$('#search_autocomplete').is(":focused")) {
49 $('#search_autocomplete').focus();
50 }
51 });
52
53 // Set up quicknav
54 var quicknav_open = false;
55 $("#btn-quicknav").click(function() {
56 if (quicknav_open) {
57 $(this).removeClass('active');
58 quicknav_open = false;
59 collapse();
60 } else {
61 $(this).addClass('active');
62 quicknav_open = true;
63 expand();
64 }
65 })
66
67 var expand = function() {
68 $('#header-wrap').addClass('quicknav');
69 $('#quicknav').stop().show().animate({opacity:'1'});
70 }
71
72 var collapse = function() {
73 $('#quicknav').stop().animate({opacity:'0'}, 100, function() {
74 $(this).hide();
75 $('#header-wrap').removeClass('quicknav');
76 });
77 }
78
79
80 //Set up search
81 $("#search_autocomplete").focus(function() {
82 $("#search-container").addClass('active');
83 })
84 $("#search-container").mouseover(function() {
85 $("#search-container").addClass('active');
86 $("#search_autocomplete").focus();
87 })
88 $("#search-container").mouseout(function() {
89 if ($("#search_autocomplete").is(":focus")) return;
90 if ($("#search_autocomplete").val() == '') {
91 setTimeout(function(){
92 $("#search-container").removeClass('active');
93 $("#search_autocomplete").blur();
94 },250);
95 }
96 })
97 $("#search_autocomplete").blur(function() {
98 if ($("#search_autocomplete").val() == '') {
99 $("#search-container").removeClass('active');
100 }
101 })
102
103
104 // prep nav expandos
105 var pagePath = document.location.pathname;
106 // account for intl docs by removing the intl/*/ path
107 if (pagePath.indexOf("/intl/") == 0) {
108 pagePath = pagePath.substr(pagePath.indexOf("/",6)); // start after intl/ to get last /
109 }
110
111 if (pagePath.indexOf(SITE_ROOT) == 0) {
112 if (pagePath == '' || pagePath.charAt(pagePath.length - 1) == '/') {
113 pagePath += 'index.html';
114 }
115 }
116
117 if (SITE_ROOT.match(/\.\.\//) || SITE_ROOT == '') {
118 // If running locally, SITE_ROOT will be a relative path, so account for that by
119 // finding the relative URL to this page. This will allow us to find links on the page
120 // leading back to this page.
121 var pathParts = pagePath.split('/');
122 var relativePagePathParts = [];
123 var upDirs = (SITE_ROOT.match(/(\.\.\/)+/) || [''])[0].length / 3;
124 for (var i = 0; i < upDirs; i++) {
125 relativePagePathParts.push('..');
126 }
127 for (var i = 0; i < upDirs; i++) {
128 relativePagePathParts.push(pathParts[pathParts.length - (upDirs - i) - 1]);
129 }
130 relativePagePathParts.push(pathParts[pathParts.length - 1]);
131 pagePath = relativePagePathParts.join('/');
132 } else {
133 // Otherwise the page path is already an absolute URL
134 }
135
136 // select current page in sidenav and set up prev/next links if they exist
137 var $selNavLink = $('#nav').find('a[href="' + pagePath + '"]');
Scott Main5a1123e2012-09-26 12:51:28 -0700138 var $selListItem;
Scott Maine4d8f1b2012-06-21 18:03:05 -0700139 if ($selNavLink.length) {
140 $selListItem = $selNavLink.closest('li');
Robert Lyd2dd6e52012-11-29 21:28:48 -0800141
Scott Maine4d8f1b2012-06-21 18:03:05 -0700142 $selListItem.addClass('selected');
Scott Main502c9392012-11-27 15:00:40 -0800143
144 // Traverse up the tree and expand all parent nav-sections
145 $selNavLink.parents('li.nav-section').each(function() {
146 $(this).addClass('expanded');
147 $(this).children('ul').show();
148 });
Scott Maine4d8f1b2012-06-21 18:03:05 -0700149
Scott Maine4d8f1b2012-06-21 18:03:05 -0700150
151 // set up prev links
152 var $prevLink = [];
153 var $prevListItem = $selListItem.prev('li');
154
155 var crossBoundaries = ($("body.design").length > 0) || ($("body.guide").length > 0) ? true :
156false; // navigate across topic boundaries only in design docs
157 if ($prevListItem.length) {
158 if ($prevListItem.hasClass('nav-section')) {
Scott Main5a1123e2012-09-26 12:51:28 -0700159 // jump to last topic of previous section
160 $prevLink = $prevListItem.find('a:last');
161 } else if (!$selListItem.hasClass('nav-section')) {
Scott Maine4d8f1b2012-06-21 18:03:05 -0700162 // jump to previous topic in this section
163 $prevLink = $prevListItem.find('a:eq(0)');
164 }
165 } else {
166 // jump to this section's index page (if it exists)
167 var $parentListItem = $selListItem.parents('li');
168 $prevLink = $selListItem.parents('li').find('a');
169
170 // except if cross boundaries aren't allowed, and we're at the top of a section already
171 // (and there's another parent)
172 if (!crossBoundaries && $parentListItem.hasClass('nav-section')
173 && $selListItem.hasClass('nav-section')) {
174 $prevLink = [];
175 }
176 }
177
Scott Maine4d8f1b2012-06-21 18:03:05 -0700178 // set up next links
179 var $nextLink = [];
Scott Maine4d8f1b2012-06-21 18:03:05 -0700180 var startClass = false;
181 var training = $(".next-class-link").length; // decides whether to provide "next class" link
182 var isCrossingBoundary = false;
183
184 if ($selListItem.hasClass('nav-section')) {
185 // we're on an index page, jump to the first topic
Scott Mainb505ca62012-07-26 18:00:14 -0700186 $nextLink = $selListItem.find('ul:eq(0)').find('a:eq(0)');
Scott Maine4d8f1b2012-06-21 18:03:05 -0700187
188 // if there aren't any children, go to the next section (required for About pages)
189 if($nextLink.length == 0) {
190 $nextLink = $selListItem.next('li').find('a');
Scott Mainb505ca62012-07-26 18:00:14 -0700191 } else if ($('.topic-start-link').length) {
192 // as long as there's a child link and there is a "topic start link" (we're on a landing)
193 // then set the landing page "start link" text to be the first doc title
194 $('.topic-start-link').text($nextLink.text().toUpperCase());
Scott Maine4d8f1b2012-06-21 18:03:05 -0700195 }
196
Scott Main5a1123e2012-09-26 12:51:28 -0700197 // If the selected page has a description, then it's a class or article homepage
198 if ($selListItem.find('a[description]').length) {
199 // this means we're on a class landing page
Scott Maine4d8f1b2012-06-21 18:03:05 -0700200 startClass = true;
201 }
202 } else {
203 // jump to the next topic in this section (if it exists)
204 $nextLink = $selListItem.next('li').find('a:eq(0)');
205 if (!$nextLink.length) {
Scott Main5a1123e2012-09-26 12:51:28 -0700206 isCrossingBoundary = true;
207 // no more topics in this section, jump to the first topic in the next section
208 $nextLink = $selListItem.parents('li:eq(0)').next('li.nav-section').find('a:eq(0)');
209 if (!$nextLink.length) { // Go up another layer to look for next page (lesson > class > course)
210 $nextLink = $selListItem.parents('li:eq(1)').next('li.nav-section').find('a:eq(0)');
Scott Maine4d8f1b2012-06-21 18:03:05 -0700211 }
212 }
213 }
Scott Main5a1123e2012-09-26 12:51:28 -0700214
215 if (startClass) {
216 $('.start-class-link').attr('href', $nextLink.attr('href')).removeClass("hide");
217
218 // if there's no training bar (below the start button),
219 // then we need to add a bottom border to button
220 if (!$("#tb").length) {
221 $('.start-class-link').css({'border-bottom':'1px solid #DADADA'});
Scott Maine4d8f1b2012-06-21 18:03:05 -0700222 }
Scott Main5a1123e2012-09-26 12:51:28 -0700223 } else if (isCrossingBoundary && !$('body.design').length) { // Design always crosses boundaries
224 $('.content-footer.next-class').show();
225 $('.next-page-link').attr('href','')
226 .removeClass("hide").addClass("disabled")
227 .click(function() { return false; });
228
229 $('.next-class-link').attr('href',$nextLink.attr('href'))
230 .removeClass("hide").append($nextLink.html());
231 $('.next-class-link').find('.new').empty();
232 } else {
233 $('.next-page-link').attr('href', $nextLink.attr('href')).removeClass("hide");
234 }
235
236 if (!startClass && $prevLink.length) {
237 var prevHref = $prevLink.attr('href');
238 if (prevHref == SITE_ROOT + 'index.html') {
239 // Don't show Previous when it leads to the homepage
240 } else {
241 $('.prev-page-link').attr('href', $prevLink.attr('href')).removeClass("hide");
242 }
243 }
244
245 // If this is a training 'article', there should be no prev/next nav
246 // ... if the grandparent is the "nav" ... and it has no child list items...
247 if (training && $selListItem.parents('ul').eq(1).is('[id="nav"]') &&
248 !$selListItem.find('li').length) {
249 $('.next-page-link,.prev-page-link').attr('href','').addClass("disabled")
250 .click(function() { return false; });
Scott Maine4d8f1b2012-06-21 18:03:05 -0700251 }
252
253 }
Scott Main5a1123e2012-09-26 12:51:28 -0700254
255
256
257 // Set up the course landing pages for Training with class names and descriptions
258 if ($('body.trainingcourse').length) {
259 var $classLinks = $selListItem.find('ul li a').not('#nav .nav-section .nav-section ul a');
260 var $classDescriptions = $classLinks.attr('description');
261
262 var $olClasses = $('<ol class="class-list"></ol>');
263 var $liClass;
264 var $imgIcon;
265 var $h2Title;
266 var $pSummary;
267 var $olLessons;
268 var $liLesson;
269 $classLinks.each(function(index) {
270 $liClass = $('<li></li>');
271 $h2Title = $('<a class="title" href="'+$(this).attr('href')+'"><h2>' + $(this).html()+'</h2><span></span></a>');
272 $pSummary = $('<p class="description">' + $(this).attr('description') + '</p>');
273
274 $olLessons = $('<ol class="lesson-list"></ol>');
275
276 $lessons = $(this).closest('li').find('ul li a');
277
278 if ($lessons.length) {
279 $imgIcon = $('<img src="'+toRoot+'assets/images/resource-tutorial.png" alt=""/>');
280 $lessons.each(function(index) {
281 $olLessons.append('<li><a href="'+$(this).attr('href')+'">' + $(this).html()+'</a></li>');
282 });
283 } else {
284 $imgIcon = $('<img src="'+toRoot+'assets/images/resource-article.png" alt=""/>');
285 $pSummary.addClass('article');
286 }
287
288 $liClass.append($h2Title).append($imgIcon).append($pSummary).append($olLessons);
289 $olClasses.append($liClass);
290 });
291 $('.jd-descr').append($olClasses);
292 }
293
Scott Maine4d8f1b2012-06-21 18:03:05 -0700294
295
296
297 // Set up expand/collapse behavior
298 $('#nav li.nav-section .nav-section-header').click(function() {
299 var section = $(this).closest('li.nav-section');
300 if (section.hasClass('expanded')) {
301 /* hide me */
302 // if (section.hasClass('selected') || section.find('li').hasClass('selected')) {
303 // /* but not if myself or my descendents are selected */
304 // return;
305 // }
306 section.children('ul').slideUp(250, function() {
307 section.closest('li').removeClass('expanded');
308 resizeNav();
309 });
310 } else {
311 /* show me */
312 // first hide all other siblings
313 var $others = $('li.nav-section.expanded', $(this).closest('ul'));
314 $others.removeClass('expanded').children('ul').slideUp(250);
315
316 // now expand me
317 section.closest('li').addClass('expanded');
318 section.children('ul').slideDown(250, function() {
319 resizeNav();
320 });
321 }
322 });
323
324 $(".scroll-pane").scroll(function(event) {
325 event.preventDefault();
326 return false;
327 });
328
329 /* Resize nav height when window height changes */
330 $(window).resize(function() {
331 if ($('#side-nav').length == 0) return;
332 var stylesheet = $('link[rel="stylesheet"][class="fullscreen"]');
333 setNavBarLeftPos(); // do this even if sidenav isn't fixed because it could become fixed
334 // make sidenav behave when resizing the window and side-scolling is a concern
335 if (navBarIsFixed) {
336 if ((stylesheet.attr("disabled") == "disabled") || stylesheet.length == 0) {
337 updateSideNavPosition();
338 } else {
339 updateSidenavFullscreenWidth();
340 }
341 }
342 resizeNav();
343 });
344
345
346 // Set up fixed navbar
347 var prevScrollLeft = 0; // used to compare current position to previous position of horiz scroll
348 $(window).scroll(function(event) {
349 if ($('#side-nav').length == 0) return;
350 if (event.target.nodeName == "DIV") {
351 // Dump scroll event if the target is a DIV, because that means the event is coming
352 // from a scrollable div and so there's no need to make adjustments to our layout
353 return;
354 }
355 var scrollTop = $(window).scrollTop();
356 var headerHeight = $('#header').outerHeight();
357 var subheaderHeight = $('#nav-x').outerHeight();
358 var searchResultHeight = $('#searchResults').is(":visible") ?
359 $('#searchResults').outerHeight() : 0;
360 var totalHeaderHeight = headerHeight + subheaderHeight + searchResultHeight;
361 var navBarShouldBeFixed = scrollTop > totalHeaderHeight;
362
363 var scrollLeft = $(window).scrollLeft();
364 // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match
365 if (navBarIsFixed && (scrollLeft != prevScrollLeft)) {
366 updateSideNavPosition();
367 prevScrollLeft = scrollLeft;
368 }
369
370 // Don't continue if the header is sufficently far away
371 // (to avoid intensive resizing that slows scrolling)
372 if (navBarIsFixed && navBarShouldBeFixed) {
373 return;
374 }
375
376 if (navBarIsFixed != navBarShouldBeFixed) {
377 if (navBarShouldBeFixed) {
378 // make it fixed
379 var width = $('#devdoc-nav').width();
380 $('#devdoc-nav')
381 .addClass('fixed')
382 .css({'width':width+'px'})
383 .prependTo('#body-content');
384 // add neato "back to top" button
385 $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'});
386
387 // update the sidenaav position for side scrolling
388 updateSideNavPosition();
389 } else {
390 // make it static again
391 $('#devdoc-nav')
392 .removeClass('fixed')
393 .css({'width':'auto','margin':''})
394 .prependTo('#side-nav');
395 $('#devdoc-nav a.totop').hide();
396 }
397 navBarIsFixed = navBarShouldBeFixed;
398 }
399
400 resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance
401 });
402
403
404 var navBarLeftPos;
405 if ($('#devdoc-nav').length) {
406 setNavBarLeftPos();
407 }
408
409
410 // Stop expand/collapse behavior when clicking on nav section links (since we're navigating away
411 // from the page)
412 $('.nav-section-header').find('a:eq(0)').click(function(evt) {
413 window.location.href = $(this).attr('href');
414 return false;
415 });
416
417 // Set up play-on-hover <video> tags.
418 $('video.play-on-hover').bind('click', function(){
419 $(this).get(0).load(); // in case the video isn't seekable
420 $(this).get(0).play();
421 });
422
423 // Set up tooltips
424 var TOOLTIP_MARGIN = 10;
Scott Maindb3678b2012-10-23 14:13:41 -0700425 $('acronym,.tooltip-link').each(function() {
Scott Maine4d8f1b2012-06-21 18:03:05 -0700426 var $target = $(this);
427 var $tooltip = $('<div>')
428 .addClass('tooltip-box')
Scott Maindb3678b2012-10-23 14:13:41 -0700429 .append($target.attr('title'))
Scott Maine4d8f1b2012-06-21 18:03:05 -0700430 .hide()
431 .appendTo('body');
432 $target.removeAttr('title');
433
434 $target.hover(function() {
435 // in
436 var targetRect = $target.offset();
437 targetRect.width = $target.width();
438 targetRect.height = $target.height();
439
440 $tooltip.css({
441 left: targetRect.left,
442 top: targetRect.top + targetRect.height + TOOLTIP_MARGIN
443 });
444 $tooltip.addClass('below');
445 $tooltip.show();
446 }, function() {
447 // out
448 $tooltip.hide();
449 });
450 });
451
452 // Set up <h2> deeplinks
453 $('h2').click(function() {
454 var id = $(this).attr('id');
455 if (id) {
456 document.location.hash = id;
457 }
458 });
459
460 //Loads the +1 button
461 var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
462 po.src = 'https://apis.google.com/js/plusone.js';
463 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
464
465
466 // Revise the sidenav widths to make room for the scrollbar
467 // which avoids the visible width from changing each time the bar appears
468 var $sidenav = $("#side-nav");
469 var sidenav_width = parseInt($sidenav.innerWidth());
470
471 $("#devdoc-nav #nav").css("width", sidenav_width - 4 + "px"); // 4px is scrollbar width
472
473
474 $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller
475
476 if ($(".scroll-pane").length > 1) {
477 // Check if there's a user preference for the panel heights
478 var cookieHeight = readCookie("reference_height");
479 if (cookieHeight) {
480 restoreHeight(cookieHeight);
481 }
482 }
483
484 resizeNav();
485
486
487});
488
489
490
491function toggleFullscreen(enable) {
492 var delay = 20;
493 var enabled = true;
494 var stylesheet = $('link[rel="stylesheet"][class="fullscreen"]');
495 if (enable) {
496 // Currently NOT USING fullscreen; enable fullscreen
497 stylesheet.removeAttr('disabled');
498 $('#nav-swap .fullscreen').removeClass('disabled');
499 $('#devdoc-nav').css({left:''});
500 setTimeout(updateSidenavFullscreenWidth,delay); // need to wait a moment for css to switch
501 enabled = true;
502 } else {
503 // Currently USING fullscreen; disable fullscreen
504 stylesheet.attr('disabled', 'disabled');
505 $('#nav-swap .fullscreen').addClass('disabled');
506 setTimeout(updateSidenavFixedWidth,delay); // need to wait a moment for css to switch
507 enabled = false;
508 }
509 writeCookie("fullscreen", enabled, null, null);
510 setNavBarLeftPos();
511 resizeNav(delay);
512 updateSideNavPosition();
513 setTimeout(initSidenavHeightResize,delay);
514}
515
516
517function setNavBarLeftPos() {
518 navBarLeftPos = $('#body-content').offset().left;
519}
520
521
522function updateSideNavPosition() {
523 var newLeft = $(window).scrollLeft() - navBarLeftPos;
524 $('#devdoc-nav').css({left: -newLeft});
525 $('#devdoc-nav .totop').css({left: -(newLeft - parseInt($('#side-nav').css('margin-left')))});
526}
527
528
529
530
531
532
533
534
535// TODO: use $(document).ready instead
536function addLoadEvent(newfun) {
537 var current = window.onload;
538 if (typeof window.onload != 'function') {
539 window.onload = newfun;
540 } else {
541 window.onload = function() {
542 current();
543 newfun();
544 }
545 }
546}
547
548var agent = navigator['userAgent'].toLowerCase();
549// If a mobile phone, set flag and do mobile setup
550if ((agent.indexOf("mobile") != -1) || // android, iphone, ipod
551 (agent.indexOf("blackberry") != -1) ||
552 (agent.indexOf("webos") != -1) ||
553 (agent.indexOf("mini") != -1)) { // opera mini browsers
554 isMobile = true;
555}
556
557
558/* loads the lists.js file to the page.
559Loading this in the head was slowing page load time */
560addLoadEvent( function() {
561 var lists = document.createElement("script");
562 lists.setAttribute("type","text/javascript");
563 lists.setAttribute("src", toRoot+"reference/lists.js");
564 document.getElementsByTagName("head")[0].appendChild(lists);
565} );
566
567
568addLoadEvent( function() {
569 $("pre:not(.no-pretty-print)").addClass("prettyprint");
570 prettyPrint();
571} );
572
Scott Maine4d8f1b2012-06-21 18:03:05 -0700573function init() {
574 //resizeNav();
575
576 resizePackagesNav = $("#resize-packages-nav");
577 classesNav = $("#classes-nav");
578 devdocNav = $("#devdoc-nav");
579
580 var cookiePath = "";
581 if (location.href.indexOf("/reference/") != -1) {
582 cookiePath = "reference_";
583 } else if (location.href.indexOf("/guide/") != -1) {
584 cookiePath = "guide_";
585 } else if (location.href.indexOf("/tools/") != -1) {
586 cookiePath = "tools_";
587 } else if (location.href.indexOf("/training/") != -1) {
588 cookiePath = "training_";
589 } else if (location.href.indexOf("/design/") != -1) {
590 cookiePath = "design_";
591 } else if (location.href.indexOf("/distribute/") != -1) {
592 cookiePath = "distribute_";
593 }
594}
595
596
597
598/* ######### RESIZE THE SIDENAV HEIGHT ########## */
599
600function resizeNav(delay) {
601 var $nav = $("#devdoc-nav");
602 var $window = $(window);
603 var navHeight;
604
605 // Get the height of entire window and the total header height.
606 // Then figure out based on scroll position whether the header is visible
607 var windowHeight = $window.height();
608 var scrollTop = $window.scrollTop();
609 var headerHeight = $('#header').outerHeight();
610 var subheaderHeight = $('#nav-x').outerHeight();
611 var headerVisible = (scrollTop < (headerHeight + subheaderHeight));
612
613 // get the height of space between nav and top of window.
614 // Could be either margin or top position, depending on whether the nav is fixed.
615 var topMargin = (parseInt($nav.css('margin-top')) || parseInt($nav.css('top'))) + 1;
616 // add 1 for the #side-nav bottom margin
617
618 // Depending on whether the header is visible, set the side nav's height.
619 if (headerVisible) {
620 // The sidenav height grows as the header goes off screen
621 navHeight = windowHeight - (headerHeight + subheaderHeight - scrollTop) - topMargin;
622 } else {
623 // Once header is off screen, the nav height is almost full window height
624 navHeight = windowHeight - topMargin;
625 }
626
627
628
629 $scrollPanes = $(".scroll-pane");
630 if ($scrollPanes.length > 1) {
631 // subtract the height of the api level widget and nav swapper from the available nav height
632 navHeight -= ($('#api-nav-header').outerHeight(true) + $('#nav-swap').outerHeight(true));
633
634 $("#swapper").css({height:navHeight + "px"});
635 if ($("#nav-tree").is(":visible")) {
636 $("#nav-tree").css({height:navHeight});
637 }
638
639 var classesHeight = navHeight - parseInt($("#resize-packages-nav").css("height")) - 10 + "px";
640 //subtract 10px to account for drag bar
641
642 // if the window becomes small enough to make the class panel height 0,
643 // then the package panel should begin to shrink
644 if (parseInt(classesHeight) <= 0) {
645 $("#resize-packages-nav").css({height:navHeight - 10}); //subtract 10px for drag bar
646 $("#packages-nav").css({height:navHeight - 10});
647 }
648
649 $("#classes-nav").css({'height':classesHeight, 'margin-top':'10px'});
650 $("#classes-nav .jspContainer").css({height:classesHeight});
651
652
653 } else {
654 $nav.height(navHeight);
655 }
656
657 if (delay) {
658 updateFromResize = true;
659 delayedReInitScrollbars(delay);
660 } else {
661 reInitScrollbars();
662 }
663
664}
665
666var updateScrollbars = false;
667var updateFromResize = false;
668
669/* Re-initialize the scrollbars to account for changed nav size.
670 * This method postpones the actual update by a 1/4 second in order to optimize the
671 * scroll performance while the header is still visible, because re-initializing the
672 * scroll panes is an intensive process.
673 */
674function delayedReInitScrollbars(delay) {
675 // If we're scheduled for an update, but have received another resize request
676 // before the scheduled resize has occured, just ignore the new request
677 // (and wait for the scheduled one).
678 if (updateScrollbars && updateFromResize) {
679 updateFromResize = false;
680 return;
681 }
682
683 // We're scheduled for an update and the update request came from this method's setTimeout
684 if (updateScrollbars && !updateFromResize) {
685 reInitScrollbars();
686 updateScrollbars = false;
687 } else {
688 updateScrollbars = true;
689 updateFromResize = false;
690 setTimeout('delayedReInitScrollbars()',delay);
691 }
692}
693
694/* Re-initialize the scrollbars to account for changed nav size. */
695function reInitScrollbars() {
696 var pane = $(".scroll-pane").each(function(){
697 var api = $(this).data('jsp');
698 if (!api) { setTimeout(reInitScrollbars,300); return;}
699 api.reinitialise( {verticalGutter:0} );
700 });
701 $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller
702}
703
704
705/* Resize the height of the nav panels in the reference,
706 * and save the new size to a cookie */
707function saveNavPanels() {
708 var basePath = getBaseUri(location.pathname);
709 var section = basePath.substring(1,basePath.indexOf("/",1));
710 writeCookie("height", resizePackagesNav.css("height"), section, null);
711}
712
713
714
715function restoreHeight(packageHeight) {
716 $("#resize-packages-nav").height(packageHeight);
717 $("#packages-nav").height(packageHeight);
718 // var classesHeight = navHeight - packageHeight;
719 // $("#classes-nav").css({height:classesHeight});
720 // $("#classes-nav .jspContainer").css({height:classesHeight});
721}
722
723
724
725/* ######### END RESIZE THE SIDENAV HEIGHT ########## */
726
727
728
729
730
731/** Scroll the jScrollPane to make the currently selected item visible
732 This is called when the page finished loading. */
733function scrollIntoView(nav) {
734 var $nav = $("#"+nav);
735 var element = $nav.jScrollPane({/* ...settings... */});
736 var api = element.data('jsp');
737
738 if ($nav.is(':visible')) {
739 var $selected = $(".selected", $nav);
740 if ($selected.length == 0) return;
741
742 var selectedOffset = $selected.position().top;
743 if (selectedOffset + 90 > $nav.height()) { // add 90 so that we scroll up even
744 // if the current item is close to the bottom
745 api.scrollTo(0, selectedOffset - ($nav.height() / 4), false); // scroll the item into view
746 // to be 1/4 of the way from the top
747 }
748 }
749}
750
751
752
753
754
755
756/* Show popup dialogs */
757function showDialog(id) {
758 $dialog = $("#"+id);
759 $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>');
760 $dialog.wrapInner('<div/>');
761 $dialog.removeClass("hide");
762}
763
764
765
766
767
768/* ######### COOKIES! ########## */
769
770function readCookie(cookie) {
771 var myCookie = cookie_namespace+"_"+cookie+"=";
772 if (document.cookie) {
773 var index = document.cookie.indexOf(myCookie);
774 if (index != -1) {
775 var valStart = index + myCookie.length;
776 var valEnd = document.cookie.indexOf(";", valStart);
777 if (valEnd == -1) {
778 valEnd = document.cookie.length;
779 }
780 var val = document.cookie.substring(valStart, valEnd);
781 return val;
782 }
783 }
784 return 0;
785}
786
787function writeCookie(cookie, val, section, expiration) {
788 if (val==undefined) return;
789 section = section == null ? "_" : "_"+section+"_";
790 if (expiration == null) {
791 var date = new Date();
792 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week
793 expiration = date.toGMTString();
794 }
795 var cookieValue = cookie_namespace + section + cookie + "=" + val
796 + "; expires=" + expiration+"; path=/";
797 document.cookie = cookieValue;
798}
799
800/* ######### END COOKIES! ########## */
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826/*
827
828REMEMBER THE PREVIOUS PAGE FOR EACH TAB
829
830function loadLast(cookiePath) {
831 var location = window.location.href;
832 if (location.indexOf("/"+cookiePath+"/") != -1) {
833 return true;
834 }
835 var lastPage = readCookie(cookiePath + "_lastpage");
836 if (lastPage) {
837 window.location = lastPage;
838 return false;
839 }
840 return true;
841}
842
843
844
845$(window).unload(function(){
846 var path = getBaseUri(location.pathname);
847 if (path.indexOf("/reference/") != -1) {
848 writeCookie("lastpage", path, "reference", null);
849 } else if (path.indexOf("/guide/") != -1) {
850 writeCookie("lastpage", path, "guide", null);
851 } else if ((path.indexOf("/resources/") != -1) || (path.indexOf("/training/") != -1)) {
852 writeCookie("lastpage", path, "resources", null);
853 }
854});
855
856*/
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871function toggle(obj, slide) {
872 var ul = $("ul:first", obj);
873 var li = ul.parent();
874 if (li.hasClass("closed")) {
875 if (slide) {
876 ul.slideDown("fast");
877 } else {
878 ul.show();
879 }
880 li.removeClass("closed");
881 li.addClass("open");
882 $(".toggle-img", li).attr("title", "hide pages");
883 } else {
884 ul.slideUp("fast");
885 li.removeClass("open");
886 li.addClass("closed");
887 $(".toggle-img", li).attr("title", "show pages");
888 }
889}
890
891
892
893
894
895function buildToggleLists() {
896 $(".toggle-list").each(
897 function(i) {
898 $("div:first", this).append("<a class='toggle-img' href='#' title='show pages' onClick='toggle(this.parentNode.parentNode, true); return false;'></a>");
899 $(this).addClass("closed");
900 });
901}
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934/* REFERENCE NAV SWAP */
935
936
937function getNavPref() {
938 var v = readCookie('reference_nav');
939 if (v != NAV_PREF_TREE) {
940 v = NAV_PREF_PANELS;
941 }
942 return v;
943}
944
945function chooseDefaultNav() {
946 nav_pref = getNavPref();
947 if (nav_pref == NAV_PREF_TREE) {
948 $("#nav-panels").toggle();
949 $("#panel-link").toggle();
950 $("#nav-tree").toggle();
951 $("#tree-link").toggle();
952 }
953}
954
955function swapNav() {
956 if (nav_pref == NAV_PREF_TREE) {
957 nav_pref = NAV_PREF_PANELS;
958 } else {
959 nav_pref = NAV_PREF_TREE;
960 init_default_navtree(toRoot);
961 }
962 var date = new Date();
963 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
964 writeCookie("nav", nav_pref, "reference", date.toGMTString());
965
966 $("#nav-panels").toggle();
967 $("#panel-link").toggle();
968 $("#nav-tree").toggle();
969 $("#tree-link").toggle();
970
971 resizeNav();
972
973 // Gross nasty hack to make tree view show up upon first swap by setting height manually
974 $("#nav-tree .jspContainer:visible")
975 .css({'height':$("#nav-tree .jspContainer .jspPane").height() +'px'});
976 // Another nasty hack to make the scrollbar appear now that we have height
977 resizeNav();
978
979 if ($("#nav-tree").is(':visible')) {
980 scrollIntoView("nav-tree");
981 } else {
982 scrollIntoView("packages-nav");
983 scrollIntoView("classes-nav");
984 }
985}
986
987
988
Scott Mainf5089842012-08-14 16:31:07 -0700989/* ############################################ */
Scott Maine4d8f1b2012-06-21 18:03:05 -0700990/* ########## LOCALIZATION ############ */
Scott Mainf5089842012-08-14 16:31:07 -0700991/* ############################################ */
Scott Maine4d8f1b2012-06-21 18:03:05 -0700992
993function getBaseUri(uri) {
994 var intlUrl = (uri.substring(0,6) == "/intl/");
995 if (intlUrl) {
996 base = uri.substring(uri.indexOf('intl/')+5,uri.length);
997 base = base.substring(base.indexOf('/')+1, base.length);
998 //alert("intl, returning base url: /" + base);
999 return ("/" + base);
1000 } else {
1001 //alert("not intl, returning uri as found.");
1002 return uri;
1003 }
1004}
1005
1006function requestAppendHL(uri) {
1007//append "?hl=<lang> to an outgoing request (such as to blog)
1008 var lang = getLangPref();
1009 if (lang) {
1010 var q = 'hl=' + lang;
1011 uri += '?' + q;
1012 window.location = uri;
1013 return false;
1014 } else {
1015 return true;
1016 }
1017}
1018
1019
Scott Maine4d8f1b2012-06-21 18:03:05 -07001020function changeNavLang(lang) {
Scott Main6eb95f12012-10-02 17:12:23 -07001021 var $links = $("#devdoc-nav,#header,#nav-x,.training-nav-top,.content-footer").find("a["+lang+"-lang]");
1022 $links.each(function(i){ // for each link with a translation
1023 var $link = $(this);
1024 if (lang != "en") { // No need to worry about English, because a language change invokes new request
1025 // put the desired language from the attribute as the text
1026 $link.text($link.attr(lang+"-lang"))
Scott Maine4d8f1b2012-06-21 18:03:05 -07001027 }
Scott Main6eb95f12012-10-02 17:12:23 -07001028 });
Scott Maine4d8f1b2012-06-21 18:03:05 -07001029}
1030
1031function changeDocLang(lang) {
Scott Maine4d8f1b2012-06-21 18:03:05 -07001032 changeNavLang(lang);
1033}
1034
1035function changeLangPref(lang, refresh) {
1036 var date = new Date();
1037 expires = date.toGMTString(date.setTime(date.getTime()+(10*365*24*60*60*1000)));
1038 // keep this for 50 years
1039 //alert("expires: " + expires)
1040 writeCookie("pref_lang", lang, null, expires);
1041 changeDocLang(lang);
1042 if (refresh) {
1043 l = getBaseUri(location.pathname);
1044 window.location = l;
1045 }
1046}
1047
1048function loadLangPref() {
1049 var lang = readCookie("pref_lang");
1050 if (lang != 0) {
1051 $("#language").find("option[value='"+lang+"']").attr("selected",true);
1052 }
1053}
1054
1055function getLangPref() {
1056 var lang = $("#language").find(":selected").attr("value");
1057 if (!lang) {
1058 lang = readCookie("pref_lang");
1059 }
1060 return (lang != 0) ? lang : 'en';
1061}
1062
1063/* ########## END LOCALIZATION ############ */
1064
1065
1066
1067
1068
1069
1070/* Used to hide and reveal supplemental content, such as long code samples.
1071 See the companion CSS in android-developer-docs.css */
1072function toggleContent(obj) {
1073 var div = $(obj.parentNode.parentNode);
1074 var toggleMe = $(".toggle-content-toggleme",div);
1075 if (div.hasClass("closed")) { // if it's closed, open it
1076 toggleMe.slideDown();
1077 $(".toggle-content-text", obj).toggle();
1078 div.removeClass("closed").addClass("open");
1079 $(".toggle-content-img", div).attr("title", "hide").attr("src", toRoot
1080 + "assets/images/triangle-opened.png");
1081 } else { // if it's open, close it
1082 toggleMe.slideUp('fast', function() { // Wait until the animation is done before closing arrow
1083 $(".toggle-content-text", obj).toggle();
1084 div.removeClass("open").addClass("closed");
1085 $(".toggle-content-img", div).attr("title", "show").attr("src", toRoot
1086 + "assets/images/triangle-closed.png");
1087 });
1088 }
1089 return false;
1090}
Scott Mainf5089842012-08-14 16:31:07 -07001091
1092
Scott Maindb3678b2012-10-23 14:13:41 -07001093/* New version of expandable content */
1094function toggleExpandable(link,id) {
1095 if($(id).is(':visible')) {
1096 $(id).slideUp();
1097 $(link).removeClass('expanded');
1098 } else {
1099 $(id).slideDown();
1100 $(link).addClass('expanded');
1101 }
1102}
1103
1104function hideExpandable(ids) {
1105 $(ids).slideUp();
Scott Main55d99832012-11-12 23:03:59 -08001106 $(ids).prev('h4').find('a.expandable').removeClass('expanded');
Scott Maindb3678b2012-10-23 14:13:41 -07001107}
1108
Scott Mainf5089842012-08-14 16:31:07 -07001109
1110
1111
1112
Robert Lyd2dd6e52012-11-29 21:28:48 -08001113/*
Scott Mainf5089842012-08-14 16:31:07 -07001114 * Slideshow 1.0
1115 * Used on /index.html and /develop/index.html for carousel
1116 *
1117 * Sample usage:
1118 * HTML -
1119 * <div class="slideshow-container">
1120 * <a href="" class="slideshow-prev">Prev</a>
1121 * <a href="" class="slideshow-next">Next</a>
1122 * <ul>
1123 * <li class="item"><img src="images/marquee1.jpg"></li>
1124 * <li class="item"><img src="images/marquee2.jpg"></li>
1125 * <li class="item"><img src="images/marquee3.jpg"></li>
1126 * <li class="item"><img src="images/marquee4.jpg"></li>
1127 * </ul>
1128 * </div>
1129 *
1130 * <script type="text/javascript">
1131 * $('.slideshow-container').dacSlideshow({
1132 * auto: true,
1133 * btnPrev: '.slideshow-prev',
1134 * btnNext: '.slideshow-next'
1135 * });
1136 * </script>
1137 *
1138 * Options:
1139 * btnPrev: optional identifier for previous button
1140 * btnNext: optional identifier for next button
1141 * auto: whether or not to auto-proceed
1142 * speed: animation speed
1143 * autoTime: time between auto-rotation
1144 * easing: easing function for transition
1145 * start: item to select by default
1146 * scroll: direction to scroll in
1147 * pagination: whether or not to include dotted pagination
1148 *
1149 */
1150
1151 (function($) {
1152 $.fn.dacSlideshow = function(o) {
1153
1154 //Options - see above
1155 o = $.extend({
1156 btnPrev: null,
1157 btnNext: null,
1158 auto: true,
1159 speed: 500,
1160 autoTime: 12000,
1161 easing: null,
1162 start: 0,
1163 scroll: 1,
1164 pagination: true
1165
1166 }, o || {});
1167
1168 //Set up a carousel for each
1169 return this.each(function() {
1170
1171 var running = false;
1172 var animCss = o.vertical ? "top" : "left";
1173 var sizeCss = o.vertical ? "height" : "width";
1174 var div = $(this);
1175 var ul = $("ul", div);
1176 var tLi = $("li", ul);
1177 var tl = tLi.size();
1178 var timer = null;
1179
1180 var li = $("li", ul);
1181 var itemLength = li.size();
1182 var curr = o.start;
1183
1184 li.css({float: o.vertical ? "none" : "left"});
1185 ul.css({margin: "0", padding: "0", position: "relative", "list-style-type": "none", "z-index": "1"});
1186 div.css({position: "relative", "z-index": "2", left: "0px"});
1187
1188 var liSize = o.vertical ? height(li) : width(li);
1189 var ulSize = liSize * itemLength;
1190 var divSize = liSize;
1191
1192 li.css({width: li.width(), height: li.height()});
1193 ul.css(sizeCss, ulSize+"px").css(animCss, -(curr*liSize));
1194
1195 div.css(sizeCss, divSize+"px");
1196
1197 //Pagination
1198 if (o.pagination) {
1199 var pagination = $("<div class='pagination'></div>");
1200 var pag_ul = $("<ul></ul>");
1201 if (tl > 1) {
1202 for (var i=0;i<tl;i++) {
1203 var li = $("<li>"+i+"</li>");
1204 pag_ul.append(li);
1205 if (i==o.start) li.addClass('active');
1206 li.click(function() {
1207 go(parseInt($(this).text()));
1208 })
1209 }
1210 pagination.append(pag_ul);
1211 div.append(pagination);
1212 }
1213 }
1214
1215 //Previous button
1216 if(o.btnPrev)
1217 $(o.btnPrev).click(function(e) {
1218 e.preventDefault();
1219 return go(curr-o.scroll);
1220 });
1221
1222 //Next button
1223 if(o.btnNext)
1224 $(o.btnNext).click(function(e) {
1225 e.preventDefault();
1226 return go(curr+o.scroll);
1227 });
1228
1229 //Auto rotation
1230 if(o.auto) startRotateTimer();
1231
1232 function startRotateTimer() {
1233 clearInterval(timer);
1234 timer = setInterval(function() {
1235 if (curr == tl-1) {
1236 go(0);
1237 } else {
1238 go(curr+o.scroll);
1239 }
1240 }, o.autoTime);
1241 }
1242
1243 //Go to an item
1244 function go(to) {
1245 if(!running) {
1246
1247 if(to<0) {
1248 to = itemLength-1;
1249 } else if (to>itemLength-1) {
1250 to = 0;
1251 }
1252 curr = to;
1253
1254 running = true;
1255
1256 ul.animate(
1257 animCss == "left" ? { left: -(curr*liSize) } : { top: -(curr*liSize) } , o.speed, o.easing,
1258 function() {
1259 running = false;
1260 }
1261 );
1262
1263 $(o.btnPrev + "," + o.btnNext).removeClass("disabled");
1264 $( (curr-o.scroll<0 && o.btnPrev)
1265 ||
1266 (curr+o.scroll > itemLength && o.btnNext)
1267 ||
1268 []
1269 ).addClass("disabled");
1270
1271
1272 var nav_items = $('li', pagination);
1273 nav_items.removeClass('active');
1274 nav_items.eq(to).addClass('active');
1275
1276
1277 }
1278 if(o.auto) startRotateTimer();
1279 return false;
1280 };
1281 });
1282 };
1283
1284 function css(el, prop) {
1285 return parseInt($.css(el[0], prop)) || 0;
1286 };
1287 function width(el) {
1288 return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
1289 };
1290 function height(el) {
1291 return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
1292 };
1293
1294 })(jQuery);
1295
1296
Robert Lyd2dd6e52012-11-29 21:28:48 -08001297/*
Scott Mainf5089842012-08-14 16:31:07 -07001298 * dacSlideshow 1.0
1299 * Used on develop/index.html for side-sliding tabs
1300 *
1301 * Sample usage:
1302 * HTML -
1303 * <div class="slideshow-container">
1304 * <a href="" class="slideshow-prev">Prev</a>
1305 * <a href="" class="slideshow-next">Next</a>
1306 * <ul>
1307 * <li class="item"><img src="images/marquee1.jpg"></li>
1308 * <li class="item"><img src="images/marquee2.jpg"></li>
1309 * <li class="item"><img src="images/marquee3.jpg"></li>
1310 * <li class="item"><img src="images/marquee4.jpg"></li>
1311 * </ul>
1312 * </div>
1313 *
1314 * <script type="text/javascript">
1315 * $('.slideshow-container').dacSlideshow({
1316 * auto: true,
1317 * btnPrev: '.slideshow-prev',
1318 * btnNext: '.slideshow-next'
1319 * });
1320 * </script>
1321 *
1322 * Options:
1323 * btnPrev: optional identifier for previous button
1324 * btnNext: optional identifier for next button
1325 * auto: whether or not to auto-proceed
1326 * speed: animation speed
1327 * autoTime: time between auto-rotation
1328 * easing: easing function for transition
1329 * start: item to select by default
1330 * scroll: direction to scroll in
1331 * pagination: whether or not to include dotted pagination
1332 *
1333 */
1334 (function($) {
1335 $.fn.dacTabbedList = function(o) {
1336
1337 //Options - see above
1338 o = $.extend({
1339 speed : 250,
1340 easing: null,
1341 nav_id: null,
1342 frame_id: null
1343 }, o || {});
1344
1345 //Set up a carousel for each
1346 return this.each(function() {
1347
1348 var curr = 0;
1349 var running = false;
1350 var animCss = "margin-left";
1351 var sizeCss = "width";
1352 var div = $(this);
1353
1354 var nav = $(o.nav_id, div);
1355 var nav_li = $("li", nav);
1356 var nav_size = nav_li.size();
1357 var frame = div.find(o.frame_id);
1358 var content_width = $(frame).find('ul').width();
1359 //Buttons
1360 $(nav_li).click(function(e) {
1361 go($(nav_li).index($(this)));
1362 })
1363
1364 //Go to an item
1365 function go(to) {
1366 if(!running) {
1367 curr = to;
1368 running = true;
1369
1370 frame.animate({ 'margin-left' : -(curr*content_width) }, o.speed, o.easing,
1371 function() {
1372 running = false;
1373 }
1374 );
1375
1376
1377 nav_li.removeClass('active');
1378 nav_li.eq(to).addClass('active');
1379
1380
1381 }
1382 return false;
1383 };
1384 });
1385 };
1386
1387 function css(el, prop) {
1388 return parseInt($.css(el[0], prop)) || 0;
1389 };
1390 function width(el) {
1391 return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
1392 };
1393 function height(el) {
1394 return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
1395 };
1396
1397 })(jQuery);
1398
1399
1400
1401
1402
1403/* ######################################################## */
1404/* ################ SEARCH SUGGESTIONS ################## */
1405/* ######################################################## */
1406
1407
1408var gSelectedIndex = -1;
1409var gSelectedID = -1;
1410var gMatches = new Array();
1411var gLastText = "";
1412var ROW_COUNT = 20;
1413var gInitialized = false;
1414
1415function set_item_selected($li, selected)
1416{
1417 if (selected) {
1418 $li.attr('class','jd-autocomplete jd-selected');
1419 } else {
1420 $li.attr('class','jd-autocomplete');
1421 }
1422}
1423
1424function set_item_values(toroot, $li, match)
1425{
1426 var $link = $('a',$li);
1427 $link.html(match.__hilabel || match.label);
1428 $link.attr('href',toroot + match.link);
1429}
1430
1431function sync_selection_table(toroot)
1432{
1433 var $list = $("#search_filtered");
1434 var $li; //list item jquery object
1435 var i; //list item iterator
1436 gSelectedID = -1;
1437
1438 //initialize the table; draw it for the first time (but not visible).
1439 if (!gInitialized) {
1440 for (i=0; i<ROW_COUNT; i++) {
1441 var $li = $("<li class='jd-autocomplete'></li>");
1442 $list.append($li);
1443
1444 $li.mousedown(function() {
1445 window.location = this.firstChild.getAttribute("href");
1446 });
1447 $li.mouseover(function() {
1448 $('#search_filtered li').removeClass('jd-selected');
1449 $(this).addClass('jd-selected');
1450 gSelectedIndex = $('#search_filtered li').index(this);
1451 });
1452 $li.append('<a></a>');
1453 }
1454 gInitialized = true;
1455 }
1456
1457 //if we have results, make the table visible and initialize result info
1458 if (gMatches.length > 0) {
1459 $('#search_filtered_div').removeClass('no-display');
1460 var N = gMatches.length < ROW_COUNT ? gMatches.length : ROW_COUNT;
1461 for (i=0; i<N; i++) {
1462 $li = $('#search_filtered li:nth-child('+(i+1)+')');
1463 $li.attr('class','show-item');
1464 set_item_values(toroot, $li, gMatches[i]);
1465 set_item_selected($li, i == gSelectedIndex);
1466 if (i == gSelectedIndex) {
1467 gSelectedID = gMatches[i].id;
1468 }
1469 }
1470 //start hiding rows that are no longer matches
1471 for (; i<ROW_COUNT; i++) {
1472 $li = $('#search_filtered li:nth-child('+(i+1)+')');
1473 $li.attr('class','no-display');
1474 }
1475 //if there are more results we're not showing, so say so.
1476/* if (gMatches.length > ROW_COUNT) {
1477 li = list.rows[ROW_COUNT];
1478 li.className = "show-item";
1479 c1 = li.cells[0];
1480 c1.innerHTML = "plus " + (gMatches.length-ROW_COUNT) + " more";
1481 } else {
1482 list.rows[ROW_COUNT].className = "hide-item";
1483 }*/
1484 //if we have no results, hide the table
1485 } else {
1486 $('#search_filtered_div').addClass('no-display');
1487 }
1488}
1489
1490function search_changed(e, kd, toroot)
1491{
1492 var search = document.getElementById("search_autocomplete");
1493 var text = search.value.replace(/(^ +)|( +$)/g, '');
1494
1495 // show/hide the close button
1496 if (text != '') {
1497 $(".search .close").removeClass("hide");
1498 } else {
1499 $(".search .close").addClass("hide");
1500 }
1501
1502 // 13 = enter
1503 if (e.keyCode == 13) {
1504 $('#search_filtered_div').addClass('no-display');
1505 if (!$('#search_filtered_div').hasClass('no-display') || (gSelectedIndex < 0)) {
1506 if ($("#searchResults").is(":hidden")) {
1507 // if results aren't showing, return true to allow search to execute
1508 return true;
1509 } else {
1510 // otherwise, results are already showing, so allow ajax to auto refresh the results
1511 // and ignore this Enter press to avoid the reload.
1512 return false;
1513 }
1514 } else if (kd && gSelectedIndex >= 0) {
1515 window.location = toroot + gMatches[gSelectedIndex].link;
1516 return false;
1517 }
1518 }
1519 // 38 -- arrow up
1520 else if (kd && (e.keyCode == 38)) {
1521 if (gSelectedIndex >= 0) {
1522 $('#search_filtered li').removeClass('jd-selected');
1523 gSelectedIndex--;
1524 $('#search_filtered li:nth-child('+(gSelectedIndex+1)+')').addClass('jd-selected');
1525 }
1526 return false;
1527 }
1528 // 40 -- arrow down
1529 else if (kd && (e.keyCode == 40)) {
1530 if (gSelectedIndex < gMatches.length-1
1531 && gSelectedIndex < ROW_COUNT-1) {
1532 $('#search_filtered li').removeClass('jd-selected');
1533 gSelectedIndex++;
1534 $('#search_filtered li:nth-child('+(gSelectedIndex+1)+')').addClass('jd-selected');
1535 }
1536 return false;
1537 }
1538 else if (!kd && (e.keyCode != 40) && (e.keyCode != 38)) {
1539 gMatches = new Array();
1540 matchedCount = 0;
1541 gSelectedIndex = -1;
1542 for (var i=0; i<DATA.length; i++) {
1543 var s = DATA[i];
1544 if (text.length != 0 &&
1545 s.label.toLowerCase().indexOf(text.toLowerCase()) != -1) {
1546 gMatches[matchedCount] = s;
1547 matchedCount++;
1548 }
1549 }
1550 rank_autocomplete_results(text);
1551 for (var i=0; i<gMatches.length; i++) {
1552 var s = gMatches[i];
1553 if (gSelectedID == s.id) {
1554 gSelectedIndex = i;
1555 }
1556 }
1557 highlight_autocomplete_result_labels(text);
1558 sync_selection_table(toroot);
1559 return true; // allow the event to bubble up to the search api
1560 }
1561}
1562
1563function rank_autocomplete_results(query) {
1564 query = query || '';
1565 if (!gMatches || !gMatches.length)
1566 return;
1567
1568 // helper function that gets the last occurence index of the given regex
1569 // in the given string, or -1 if not found
1570 var _lastSearch = function(s, re) {
1571 if (s == '')
1572 return -1;
1573 var l = -1;
1574 var tmp;
1575 while ((tmp = s.search(re)) >= 0) {
1576 if (l < 0) l = 0;
1577 l += tmp;
1578 s = s.substr(tmp + 1);
1579 }
1580 return l;
1581 };
1582
1583 // helper function that counts the occurrences of a given character in
1584 // a given string
1585 var _countChar = function(s, c) {
1586 var n = 0;
1587 for (var i=0; i<s.length; i++)
1588 if (s.charAt(i) == c) ++n;
1589 return n;
1590 };
1591
1592 var queryLower = query.toLowerCase();
1593 var queryAlnum = (queryLower.match(/\w+/) || [''])[0];
1594 var partPrefixAlnumRE = new RegExp('\\b' + queryAlnum);
1595 var partExactAlnumRE = new RegExp('\\b' + queryAlnum + '\\b');
1596
1597 var _resultScoreFn = function(result) {
1598 // scores are calculated based on exact and prefix matches,
1599 // and then number of path separators (dots) from the last
1600 // match (i.e. favoring classes and deep package names)
1601 var score = 1.0;
1602 var labelLower = result.label.toLowerCase();
1603 var t;
1604 t = _lastSearch(labelLower, partExactAlnumRE);
1605 if (t >= 0) {
1606 // exact part match
1607 var partsAfter = _countChar(labelLower.substr(t + 1), '.');
1608 score *= 200 / (partsAfter + 1);
1609 } else {
1610 t = _lastSearch(labelLower, partPrefixAlnumRE);
1611 if (t >= 0) {
1612 // part prefix match
1613 var partsAfter = _countChar(labelLower.substr(t + 1), '.');
1614 score *= 20 / (partsAfter + 1);
1615 }
1616 }
1617
1618 return score;
1619 };
1620
1621 for (var i=0; i<gMatches.length; i++) {
1622 gMatches[i].__resultScore = _resultScoreFn(gMatches[i]);
1623 }
1624
1625 gMatches.sort(function(a,b){
1626 var n = b.__resultScore - a.__resultScore;
1627 if (n == 0) // lexicographical sort if scores are the same
1628 n = (a.label < b.label) ? -1 : 1;
1629 return n;
1630 });
1631}
1632
1633function highlight_autocomplete_result_labels(query) {
1634 query = query || '';
1635 if (!gMatches || !gMatches.length)
1636 return;
1637
1638 var queryLower = query.toLowerCase();
1639 var queryAlnumDot = (queryLower.match(/[\w\.]+/) || [''])[0];
1640 var queryRE = new RegExp(
1641 '(' + queryAlnumDot.replace(/\./g, '\\.') + ')', 'ig');
1642 for (var i=0; i<gMatches.length; i++) {
1643 gMatches[i].__hilabel = gMatches[i].label.replace(
1644 queryRE, '<b>$1</b>');
1645 }
1646}
1647
1648function search_focus_changed(obj, focused)
1649{
1650 if (!focused) {
1651 if(obj.value == ""){
1652 $(".search .close").addClass("hide");
1653 }
1654 document.getElementById("search_filtered_div").className = "no-display";
1655 }
1656}
1657
1658function submit_search() {
1659 var query = document.getElementById('search_autocomplete').value;
1660 location.hash = 'q=' + query;
1661 loadSearchResults();
1662 $("#searchResults").slideDown('slow');
1663 return false;
1664}
1665
1666
1667function hideResults() {
1668 $("#searchResults").slideUp();
1669 $(".search .close").addClass("hide");
1670 location.hash = '';
1671
1672 $("#search_autocomplete").val("").blur();
1673
1674 // reset the ajax search callback to nothing, so results don't appear unless ENTER
1675 searchControl.setSearchStartingCallback(this, function(control, searcher, query) {});
1676 return false;
1677}
1678
1679
1680
1681/* ########################################################## */
1682/* ################ CUSTOM SEARCH ENGINE ################## */
1683/* ########################################################## */
1684
1685google.load('search', '1');
1686var searchControl;
1687
1688function loadSearchResults() {
1689 document.getElementById("search_autocomplete").style.color = "#000";
1690
1691 // create search control
1692 searchControl = new google.search.SearchControl();
1693
1694 // use our existing search form and use tabs when multiple searchers are used
1695 drawOptions = new google.search.DrawOptions();
1696 drawOptions.setDrawMode(google.search.SearchControl.DRAW_MODE_TABBED);
1697 drawOptions.setInput(document.getElementById("search_autocomplete"));
1698
1699 // configure search result options
1700 searchOptions = new google.search.SearcherOptions();
1701 searchOptions.setExpandMode(GSearchControl.EXPAND_MODE_OPEN);
1702
1703 // configure each of the searchers, for each tab
1704 devSiteSearcher = new google.search.WebSearch();
1705 devSiteSearcher.setUserDefinedLabel("All");
1706 devSiteSearcher.setSiteRestriction("001482626316274216503:zu90b7s047u");
1707
1708 designSearcher = new google.search.WebSearch();
1709 designSearcher.setUserDefinedLabel("Design");
1710 designSearcher.setSiteRestriction("http://developer.android.com/design/");
1711
1712 trainingSearcher = new google.search.WebSearch();
1713 trainingSearcher.setUserDefinedLabel("Training");
1714 trainingSearcher.setSiteRestriction("http://developer.android.com/training/");
1715
1716 guidesSearcher = new google.search.WebSearch();
1717 guidesSearcher.setUserDefinedLabel("Guides");
1718 guidesSearcher.setSiteRestriction("http://developer.android.com/guide/");
1719
1720 referenceSearcher = new google.search.WebSearch();
1721 referenceSearcher.setUserDefinedLabel("Reference");
1722 referenceSearcher.setSiteRestriction("http://developer.android.com/reference/");
1723
Scott Maindf08ada2012-12-03 08:54:37 -08001724 googleSearcher = new google.search.WebSearch();
1725 googleSearcher.setUserDefinedLabel("Google Services");
1726 googleSearcher.setSiteRestriction("http://developer.android.com/google/");
1727
Scott Mainf5089842012-08-14 16:31:07 -07001728 blogSearcher = new google.search.WebSearch();
1729 blogSearcher.setUserDefinedLabel("Blog");
1730 blogSearcher.setSiteRestriction("http://android-developers.blogspot.com");
1731
1732 // add each searcher to the search control
1733 searchControl.addSearcher(devSiteSearcher, searchOptions);
1734 searchControl.addSearcher(designSearcher, searchOptions);
1735 searchControl.addSearcher(trainingSearcher, searchOptions);
1736 searchControl.addSearcher(guidesSearcher, searchOptions);
1737 searchControl.addSearcher(referenceSearcher, searchOptions);
Scott Maindf08ada2012-12-03 08:54:37 -08001738 searchControl.addSearcher(googleSearcher, searchOptions);
Scott Mainf5089842012-08-14 16:31:07 -07001739 searchControl.addSearcher(blogSearcher, searchOptions);
1740
1741 // configure result options
1742 searchControl.setResultSetSize(google.search.Search.LARGE_RESULTSET);
1743 searchControl.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
1744 searchControl.setTimeoutInterval(google.search.SearchControl.TIMEOUT_SHORT);
1745 searchControl.setNoResultsString(google.search.SearchControl.NO_RESULTS_DEFAULT_STRING);
1746
1747 // upon ajax search, refresh the url and search title
1748 searchControl.setSearchStartingCallback(this, function(control, searcher, query) {
1749 updateResultTitle(query);
1750 var query = document.getElementById('search_autocomplete').value;
1751 location.hash = 'q=' + query;
1752 });
1753
1754 // draw the search results box
1755 searchControl.draw(document.getElementById("leftSearchControl"), drawOptions);
1756
1757 // get query and execute the search
1758 searchControl.execute(decodeURI(getQuery(location.hash)));
1759
1760 document.getElementById("search_autocomplete").focus();
1761 addTabListeners();
1762}
1763// End of loadSearchResults
1764
1765
1766google.setOnLoadCallback(function(){
1767 if (location.hash.indexOf("q=") == -1) {
1768 // if there's no query in the url, don't search and make sure results are hidden
1769 $('#searchResults').hide();
1770 return;
1771 } else {
1772 // first time loading search results for this page
1773 $('#searchResults').slideDown('slow');
1774 $(".search .close").removeClass("hide");
1775 loadSearchResults();
1776 }
1777}, true);
1778
1779// when an event on the browser history occurs (back, forward, load) requery hash and do search
1780$(window).hashchange( function(){
1781 // Exit if the hash isn't a search query or there's an error in the query
1782 if ((location.hash.indexOf("q=") == -1) || (query == "undefined")) {
1783 // If the results pane is open, close it.
1784 if (!$("#searchResults").is(":hidden")) {
1785 hideResults();
1786 }
1787 return;
1788 }
1789
1790 // Otherwise, we have a search to do
1791 var query = decodeURI(getQuery(location.hash));
1792 searchControl.execute(query);
1793 $('#searchResults').slideDown('slow');
1794 $("#search_autocomplete").focus();
1795 $(".search .close").removeClass("hide");
1796
1797 updateResultTitle(query);
1798});
1799
1800function updateResultTitle(query) {
1801 $("#searchTitle").html("Results for <em>" + escapeHTML(query) + "</em>");
1802}
1803
1804// forcefully regain key-up event control (previously jacked by search api)
1805$("#search_autocomplete").keyup(function(event) {
1806 return search_changed(event, false, toRoot);
1807});
1808
1809// add event listeners to each tab so we can track the browser history
1810function addTabListeners() {
1811 var tabHeaders = $(".gsc-tabHeader");
1812 for (var i = 0; i < tabHeaders.length; i++) {
1813 $(tabHeaders[i]).attr("id",i).click(function() {
1814 /*
1815 // make a copy of the page numbers for the search left pane
1816 setTimeout(function() {
1817 // remove any residual page numbers
1818 $('#searchResults .gsc-tabsArea .gsc-cursor-box.gs-bidi-start-align').remove();
1819 // move the page numbers to the left position; make a clone,
1820 // because the element is drawn to the DOM only once
1821 // and because we're going to remove it (previous line),
1822 // we need it to be available to move again as the user navigates
1823 $('#searchResults .gsc-webResult .gsc-cursor-box.gs-bidi-start-align:visible')
1824 .clone().appendTo('#searchResults .gsc-tabsArea');
1825 }, 200);
1826 */
1827 });
1828 }
1829 setTimeout(function(){$(tabHeaders[0]).click()},200);
1830}
1831
1832
1833function getQuery(hash) {
1834 var queryParts = hash.split('=');
1835 return queryParts[1];
1836}
1837
1838/* returns the given string with all HTML brackets converted to entities
1839 TODO: move this to the site's JS library */
1840function escapeHTML(string) {
1841 return string.replace(/</g,"&lt;")
1842 .replace(/>/g,"&gt;");
1843}
1844
1845
1846
1847
1848
1849
1850
1851/* ######################################################## */
1852/* ################# JAVADOC REFERENCE ################### */
1853/* ######################################################## */
1854
Scott Main65511c02012-09-07 15:51:32 -07001855/* Initialize some droiddoc stuff, but only if we're in the reference */
Scott Mainac71b2b2012-11-30 14:40:58 -08001856if ((location.pathname.indexOf("/reference") &&
1857 !location.pathname.indexOf("/reference-gms/packages.html") &&
1858 !location.pathname.indexOf("/reference-gcm/packages.html") &&
Robert Lyd2dd6e52012-11-29 21:28:48 -08001859 !location.pathname.indexOf("/reference/com/google")) == 0) {
Scott Main65511c02012-09-07 15:51:32 -07001860 $(document).ready(function() {
1861 // init available apis based on user pref
1862 changeApiLevel();
1863 initSidenavHeightResize()
1864 });
1865}
Scott Mainf5089842012-08-14 16:31:07 -07001866
1867var API_LEVEL_COOKIE = "api_level";
1868var minLevel = 1;
1869var maxLevel = 1;
1870
1871/******* SIDENAV DIMENSIONS ************/
1872
1873 function initSidenavHeightResize() {
1874 // Change the drag bar size to nicely fit the scrollbar positions
1875 var $dragBar = $(".ui-resizable-s");
1876 $dragBar.css({'width': $dragBar.parent().width() - 5 + "px"});
1877
1878 $( "#resize-packages-nav" ).resizable({
1879 containment: "#nav-panels",
1880 handles: "s",
1881 alsoResize: "#packages-nav",
1882 resize: function(event, ui) { resizeNav(); }, /* resize the nav while dragging */
1883 stop: function(event, ui) { saveNavPanels(); } /* once stopped, save the sizes to cookie */
1884 });
1885
1886 }
1887
1888function updateSidenavFixedWidth() {
1889 if (!navBarIsFixed) return;
1890 $('#devdoc-nav').css({
1891 'width' : $('#side-nav').css('width'),
1892 'margin' : $('#side-nav').css('margin')
1893 });
1894 $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'});
1895
1896 initSidenavHeightResize();
1897}
1898
1899function updateSidenavFullscreenWidth() {
1900 if (!navBarIsFixed) return;
1901 $('#devdoc-nav').css({
1902 'width' : $('#side-nav').css('width'),
1903 'margin' : $('#side-nav').css('margin')
1904 });
1905 $('#devdoc-nav .totop').css({'left': 'inherit'});
1906
1907 initSidenavHeightResize();
1908}
1909
1910function buildApiLevelSelector() {
1911 maxLevel = SINCE_DATA.length;
1912 var userApiLevel = parseInt(readCookie(API_LEVEL_COOKIE));
1913 userApiLevel = userApiLevel == 0 ? maxLevel : userApiLevel; // If there's no cookie (zero), use the max by default
1914
1915 minLevel = parseInt($("#doc-api-level").attr("class"));
1916 // Handle provisional api levels; the provisional level will always be the highest possible level
1917 // Provisional api levels will also have a length; other stuff that's just missing a level won't,
1918 // so leave those kinds of entities at the default level of 1 (for example, the R.styleable class)
1919 if (isNaN(minLevel) && minLevel.length) {
1920 minLevel = maxLevel;
1921 }
1922 var select = $("#apiLevelSelector").html("").change(changeApiLevel);
1923 for (var i = maxLevel-1; i >= 0; i--) {
1924 var option = $("<option />").attr("value",""+SINCE_DATA[i]).append(""+SINCE_DATA[i]);
1925 // if (SINCE_DATA[i] < minLevel) option.addClass("absent"); // always false for strings (codenames)
1926 select.append(option);
1927 }
1928
1929 // get the DOM element and use setAttribute cuz IE6 fails when using jquery .attr('selected',true)
1930 var selectedLevelItem = $("#apiLevelSelector option[value='"+userApiLevel+"']").get(0);
1931 selectedLevelItem.setAttribute('selected',true);
1932}
1933
1934function changeApiLevel() {
1935 maxLevel = SINCE_DATA.length;
1936 var selectedLevel = maxLevel;
1937
1938 selectedLevel = parseInt($("#apiLevelSelector option:selected").val());
1939 toggleVisisbleApis(selectedLevel, "body");
1940
1941 var date = new Date();
1942 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
1943 var expiration = date.toGMTString();
1944 writeCookie(API_LEVEL_COOKIE, selectedLevel, null, expiration);
1945
1946 if (selectedLevel < minLevel) {
1947 var thing = ($("#jd-header").html().indexOf("package") != -1) ? "package" : "class";
Scott Main8f24ca82012-11-16 10:34:22 -08001948 $("#naMessage").show().html("<div><p><strong>This " + thing
1949 + " requires API level " + minLevel + " or higher.</strong></p>"
1950 + "<p>This document is hidden because your selected API level for the documentation is "
1951 + selectedLevel + ". You can change the documentation API level with the selector "
1952 + "above the left navigation.</p>"
1953 + "<p>For more information about specifying the API level your app requires, "
1954 + "read <a href='" + toRoot + "training/basics/supporting-devices/platforms.html'"
1955 + ">Supporting Different Platform Versions</a>.</p>"
1956 + "<input type='button' value='OK, make this page visible' "
1957 + "title='Change the API level to " + minLevel + "' "
1958 + "onclick='$(\"#apiLevelSelector\").val(\"" + minLevel + "\");changeApiLevel();' />"
1959 + "</div>");
Scott Mainf5089842012-08-14 16:31:07 -07001960 } else {
1961 $("#naMessage").hide();
1962 }
1963}
1964
1965function toggleVisisbleApis(selectedLevel, context) {
1966 var apis = $(".api",context);
1967 apis.each(function(i) {
1968 var obj = $(this);
1969 var className = obj.attr("class");
1970 var apiLevelIndex = className.lastIndexOf("-")+1;
1971 var apiLevelEndIndex = className.indexOf(" ", apiLevelIndex);
1972 apiLevelEndIndex = apiLevelEndIndex != -1 ? apiLevelEndIndex : className.length;
1973 var apiLevel = className.substring(apiLevelIndex, apiLevelEndIndex);
1974 if (apiLevel.length == 0) { // for odd cases when the since data is actually missing, just bail
1975 return;
1976 }
1977 apiLevel = parseInt(apiLevel);
1978
1979 // Handle provisional api levels; if this item's level is the provisional one, set it to the max
1980 var selectedLevelNum = parseInt(selectedLevel)
1981 var apiLevelNum = parseInt(apiLevel);
1982 if (isNaN(apiLevelNum)) {
1983 apiLevelNum = maxLevel;
1984 }
1985
1986 // Grey things out that aren't available and give a tooltip title
1987 if (apiLevelNum > selectedLevelNum) {
1988 obj.addClass("absent").attr("title","Requires API Level \""
1989 + apiLevel + "\" or higher");
1990 }
1991 else obj.removeClass("absent").removeAttr("title");
1992 });
1993}
1994
1995
1996
1997
1998/* ################# SIDENAV TREE VIEW ################### */
1999
2000function new_node(me, mom, text, link, children_data, api_level)
2001{
2002 var node = new Object();
2003 node.children = Array();
2004 node.children_data = children_data;
2005 node.depth = mom.depth + 1;
2006
2007 node.li = document.createElement("li");
2008 mom.get_children_ul().appendChild(node.li);
2009
2010 node.label_div = document.createElement("div");
2011 node.label_div.className = "label";
2012 if (api_level != null) {
2013 $(node.label_div).addClass("api");
2014 $(node.label_div).addClass("api-level-"+api_level);
2015 }
2016 node.li.appendChild(node.label_div);
2017
2018 if (children_data != null) {
2019 node.expand_toggle = document.createElement("a");
2020 node.expand_toggle.href = "javascript:void(0)";
2021 node.expand_toggle.onclick = function() {
2022 if (node.expanded) {
2023 $(node.get_children_ul()).slideUp("fast");
2024 node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
2025 node.expanded = false;
2026 } else {
2027 expand_node(me, node);
2028 }
2029 };
2030 node.label_div.appendChild(node.expand_toggle);
2031
2032 node.plus_img = document.createElement("img");
2033 node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
2034 node.plus_img.className = "plus";
2035 node.plus_img.width = "8";
2036 node.plus_img.border = "0";
2037 node.expand_toggle.appendChild(node.plus_img);
2038
2039 node.expanded = false;
2040 }
2041
2042 var a = document.createElement("a");
2043 node.label_div.appendChild(a);
2044 node.label = document.createTextNode(text);
2045 a.appendChild(node.label);
2046 if (link) {
2047 a.href = me.toroot + link;
2048 } else {
2049 if (children_data != null) {
2050 a.className = "nolink";
2051 a.href = "javascript:void(0)";
2052 a.onclick = node.expand_toggle.onclick;
2053 // This next line shouldn't be necessary. I'll buy a beer for the first
2054 // person who figures out how to remove this line and have the link
2055 // toggle shut on the first try. --joeo@android.com
2056 node.expanded = false;
2057 }
2058 }
2059
2060
2061 node.children_ul = null;
2062 node.get_children_ul = function() {
2063 if (!node.children_ul) {
2064 node.children_ul = document.createElement("ul");
2065 node.children_ul.className = "children_ul";
2066 node.children_ul.style.display = "none";
2067 node.li.appendChild(node.children_ul);
2068 }
2069 return node.children_ul;
2070 };
2071
2072 return node;
2073}
2074
Robert Lyd2dd6e52012-11-29 21:28:48 -08002075
2076
2077
Scott Mainf5089842012-08-14 16:31:07 -07002078function expand_node(me, node)
2079{
2080 if (node.children_data && !node.expanded) {
2081 if (node.children_visited) {
2082 $(node.get_children_ul()).slideDown("fast");
2083 } else {
2084 get_node(me, node);
2085 if ($(node.label_div).hasClass("absent")) {
2086 $(node.get_children_ul()).addClass("absent");
2087 }
2088 $(node.get_children_ul()).slideDown("fast");
2089 }
2090 node.plus_img.src = me.toroot + "assets/images/triangle-opened-small.png";
2091 node.expanded = true;
2092
2093 // perform api level toggling because new nodes are new to the DOM
2094 var selectedLevel = $("#apiLevelSelector option:selected").val();
2095 toggleVisisbleApis(selectedLevel, "#side-nav");
2096 }
2097}
2098
2099function get_node(me, mom)
2100{
2101 mom.children_visited = true;
2102 for (var i in mom.children_data) {
2103 var node_data = mom.children_data[i];
2104 mom.children[i] = new_node(me, mom, node_data[0], node_data[1],
2105 node_data[2], node_data[3]);
2106 }
2107}
2108
2109function this_page_relative(toroot)
2110{
2111 var full = document.location.pathname;
2112 var file = "";
2113 if (toroot.substr(0, 1) == "/") {
2114 if (full.substr(0, toroot.length) == toroot) {
2115 return full.substr(toroot.length);
2116 } else {
2117 // the file isn't under toroot. Fail.
2118 return null;
2119 }
2120 } else {
2121 if (toroot != "./") {
2122 toroot = "./" + toroot;
2123 }
2124 do {
2125 if (toroot.substr(toroot.length-3, 3) == "../" || toroot == "./") {
2126 var pos = full.lastIndexOf("/");
2127 file = full.substr(pos) + file;
2128 full = full.substr(0, pos);
2129 toroot = toroot.substr(0, toroot.length-3);
2130 }
2131 } while (toroot != "" && toroot != "/");
2132 return file.substr(1);
2133 }
2134}
2135
2136function find_page(url, data)
2137{
2138 var nodes = data;
2139 var result = null;
2140 for (var i in nodes) {
2141 var d = nodes[i];
2142 if (d[1] == url) {
2143 return new Array(i);
2144 }
2145 else if (d[2] != null) {
2146 result = find_page(url, d[2]);
2147 if (result != null) {
2148 return (new Array(i).concat(result));
2149 }
2150 }
2151 }
2152 return null;
2153}
2154
Scott Mainf5089842012-08-14 16:31:07 -07002155function init_default_navtree(toroot) {
2156 init_navtree("tree-list", toroot, NAVTREE_DATA);
2157
2158 // perform api level toggling because because the whole tree is new to the DOM
2159 var selectedLevel = $("#apiLevelSelector option:selected").val();
2160 toggleVisisbleApis(selectedLevel, "#side-nav");
2161}
2162
2163function init_navtree(navtree_id, toroot, root_nodes)
2164{
2165 var me = new Object();
2166 me.toroot = toroot;
2167 me.node = new Object();
2168
2169 me.node.li = document.getElementById(navtree_id);
2170 me.node.children_data = root_nodes;
2171 me.node.children = new Array();
2172 me.node.children_ul = document.createElement("ul");
2173 me.node.get_children_ul = function() { return me.node.children_ul; };
2174 //me.node.children_ul.className = "children_ul";
2175 me.node.li.appendChild(me.node.children_ul);
2176 me.node.depth = 0;
2177
2178 get_node(me, me.node);
2179
2180 me.this_page = this_page_relative(toroot);
2181 me.breadcrumbs = find_page(me.this_page, root_nodes);
2182 if (me.breadcrumbs != null && me.breadcrumbs.length != 0) {
2183 var mom = me.node;
2184 for (var i in me.breadcrumbs) {
2185 var j = me.breadcrumbs[i];
2186 mom = mom.children[j];
2187 expand_node(me, mom);
2188 }
2189 mom.label_div.className = mom.label_div.className + " selected";
2190 addLoadEvent(function() {
2191 scrollIntoView("nav-tree");
2192 });
2193 }
2194}
2195
Robert Lyd2dd6e52012-11-29 21:28:48 -08002196/* TODO: eliminate redundancy with non-google functions */
2197function init_google_navtree(navtree_id, toroot, root_nodes)
2198{
2199 var me = new Object();
2200 me.toroot = toroot;
2201 me.node = new Object();
2202
2203 me.node.li = document.getElementById(navtree_id);
2204 me.node.children_data = root_nodes;
2205 me.node.children = new Array();
2206 me.node.children_ul = document.createElement("ul");
2207 me.node.get_children_ul = function() { return me.node.children_ul; };
2208 //me.node.children_ul.className = "children_ul";
2209 me.node.li.appendChild(me.node.children_ul);
2210 me.node.depth = 0;
2211
2212 get_google_node(me, me.node);
2213
2214}
2215
2216function new_google_node(me, mom, text, link, children_data, api_level)
2217{
2218 var node = new Object();
2219 var child;
2220 node.children = Array();
2221 node.children_data = children_data;
2222 node.depth = mom.depth + 1;
2223 node.get_children_ul = function() {
2224 if (!node.children_ul) {
Scott Mainac71b2b2012-11-30 14:40:58 -08002225 node.children_ul = document.createElement("ul");
2226 node.children_ul.className = "tree-list-children";
Robert Lyd2dd6e52012-11-29 21:28:48 -08002227 node.li.appendChild(node.children_ul);
2228 }
2229 return node.children_ul;
2230 };
2231 node.li = document.createElement("li");
2232
2233 mom.get_children_ul().appendChild(node.li);
2234
2235
2236 if(link) {
2237 child = document.createElement("a");
2238
2239 }
2240 else {
2241 child = document.createElement("span");
Scott Mainac71b2b2012-11-30 14:40:58 -08002242 child.className = "tree-list-subtitle";
Robert Lyd2dd6e52012-11-29 21:28:48 -08002243
2244 }
2245 if (children_data != null) {
2246 node.li.className="nav-section";
2247 node.label_div = document.createElement("div");
2248 node.label_div.className = "nav-section-header-ref";
2249 node.li.appendChild(node.label_div);
2250 get_google_node(me, node);
2251 node.label_div.appendChild(child);
2252 }
2253 else {
2254 node.li.appendChild(child);
2255 }
2256 if(link) {
2257 child.href = me.toroot + link;
2258 }
2259 node.label = document.createTextNode(text);
2260 child.appendChild(node.label);
2261
2262 node.children_ul = null;
2263
2264 return node;
2265}
2266
2267function get_google_node(me, mom)
2268{
2269 mom.children_visited = true;
2270 var linkText;
2271 for (var i in mom.children_data) {
2272 var node_data = mom.children_data[i];
2273 linkText = node_data[0];
2274
2275 if(linkText.match("^"+"com.google.android")=="com.google.android"){
2276 linkText = linkText.substr(19, linkText.length);
2277 }
2278 mom.children[i] = new_google_node(me, mom, linkText, node_data[1],
2279 node_data[2], node_data[3]);
2280 }
2281}
2282function showGoogleRefTree() {
2283 init_default_google_navtree(toRoot);
2284 init_default_gcm_navtree(toRoot);
2285 resizeNav();
2286}
2287
2288function init_default_google_navtree(toroot) {
2289 init_google_navtree("gms-tree-list", toroot, GMS_NAVTREE_DATA);
2290}
2291
2292function init_default_gcm_navtree(toroot) {
2293 init_google_navtree("gcm-tree-list", toroot, GCM_NAVTREE_DATA);
2294}
2295
Scott Mainf5089842012-08-14 16:31:07 -07002296/* TOGGLE INHERITED MEMBERS */
2297
2298/* Toggle an inherited class (arrow toggle)
2299 * @param linkObj The link that was clicked.
2300 * @param expand 'true' to ensure it's expanded. 'false' to ensure it's closed.
2301 * 'null' to simply toggle.
2302 */
2303function toggleInherited(linkObj, expand) {
2304 var base = linkObj.getAttribute("id");
2305 var list = document.getElementById(base + "-list");
2306 var summary = document.getElementById(base + "-summary");
2307 var trigger = document.getElementById(base + "-trigger");
2308 var a = $(linkObj);
2309 if ( (expand == null && a.hasClass("closed")) || expand ) {
2310 list.style.display = "none";
2311 summary.style.display = "block";
2312 trigger.src = toRoot + "assets/images/triangle-opened.png";
2313 a.removeClass("closed");
2314 a.addClass("opened");
2315 } else if ( (expand == null && a.hasClass("opened")) || (expand == false) ) {
2316 list.style.display = "block";
2317 summary.style.display = "none";
2318 trigger.src = toRoot + "assets/images/triangle-closed.png";
2319 a.removeClass("opened");
2320 a.addClass("closed");
2321 }
2322 return false;
2323}
2324
2325/* Toggle all inherited classes in a single table (e.g. all inherited methods)
2326 * @param linkObj The link that was clicked.
2327 * @param expand 'true' to ensure it's expanded. 'false' to ensure it's closed.
2328 * 'null' to simply toggle.
2329 */
2330function toggleAllInherited(linkObj, expand) {
2331 var a = $(linkObj);
2332 var table = $(a.parent().parent().parent()); // ugly way to get table/tbody
2333 var expandos = $(".jd-expando-trigger", table);
2334 if ( (expand == null && a.text() == "[Expand]") || expand ) {
2335 expandos.each(function(i) {
2336 toggleInherited(this, true);
2337 });
2338 a.text("[Collapse]");
2339 } else if ( (expand == null && a.text() == "[Collapse]") || (expand == false) ) {
2340 expandos.each(function(i) {
2341 toggleInherited(this, false);
2342 });
2343 a.text("[Expand]");
2344 }
2345 return false;
2346}
2347
2348/* Toggle all inherited members in the class (link in the class title)
2349 */
2350function toggleAllClassInherited() {
2351 var a = $("#toggleAllClassInherited"); // get toggle link from class title
2352 var toggles = $(".toggle-all", $("#body-content"));
2353 if (a.text() == "[Expand All]") {
2354 toggles.each(function(i) {
2355 toggleAllInherited(this, true);
2356 });
2357 a.text("[Collapse All]");
2358 } else {
2359 toggles.each(function(i) {
2360 toggleAllInherited(this, false);
2361 });
2362 a.text("[Expand All]");
2363 }
2364 return false;
2365}
2366
2367/* Expand all inherited members in the class. Used when initiating page search */
2368function ensureAllInheritedExpanded() {
2369 var toggles = $(".toggle-all", $("#body-content"));
2370 toggles.each(function(i) {
2371 toggleAllInherited(this, true);
2372 });
2373 $("#toggleAllClassInherited").text("[Collapse All]");
2374}
2375
2376
2377/* HANDLE KEY EVENTS
2378 * - Listen for Ctrl+F (Cmd on Mac) and expand all inherited members (to aid page search)
2379 */
2380var agent = navigator['userAgent'].toLowerCase();
2381var mac = agent.indexOf("macintosh") != -1;
2382
2383$(document).keydown( function(e) {
2384var control = mac ? e.metaKey && !e.ctrlKey : e.ctrlKey; // get ctrl key
2385 if (control && e.which == 70) { // 70 is "F"
2386 ensureAllInheritedExpanded();
2387 }
2388});