docs.js revision 67d75f16f4c5a51da199f96931e9b6b9c17818c7
1var classesNav; 2var devdocNav; 3var sidenav; 4var cookie_namespace = 'android_developer'; 5var NAV_PREF_TREE = "tree"; 6var NAV_PREF_PANELS = "panels"; 7var nav_pref; 8var isMobile = false; // true if mobile, so we can adjust some layout 9 10var basePath = getBaseUri(location.pathname); 11var SITE_ROOT = toRoot + basePath.substring(1,basePath.indexOf("/",1)); 12 13 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) 31 $('h2').not('#qv h2').not('#tb h2').not('.sidebox h2').not('#devdoc-nav h2').not('h2.norule').css({marginBottom:0}).after('<hr/>'); 32 33 // set search's onkeyup handler here so we can show suggestions 34 // even while search results are visible 35 $("#search_autocomplete").keyup(function() {return search_changed(event, false, toRoot)}); 36 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 + '"]'); 138 var $selListItem; 139 if ($selNavLink.length) { 140 $selListItem = $selNavLink.closest('li'); 141 142 $selListItem.addClass('selected'); 143 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 }); 149 150 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')) { 159 // jump to last topic of previous section 160 $prevLink = $prevListItem.find('a:last'); 161 } else if (!$selListItem.hasClass('nav-section')) { 162 // 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 178 // set up next links 179 var $nextLink = []; 180 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 186 $nextLink = $selListItem.find('ul:eq(0)').find('a:eq(0)'); 187 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'); 191 } 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()); 195 } 196 197 // 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 200 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) { 206 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)'); 211 } 212 } 213 } 214 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'}); 222 } 223 } 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; }); 251 } 252 253 } 254 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 294 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; 425 $('acronym,.tooltip-link').each(function() { 426 var $target = $(this); 427 var $tooltip = $('<div>') 428 .addClass('tooltip-box') 429 .append($target.attr('title')) 430 .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 573function 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 989/* ############################################ */ 990/* ########## LOCALIZATION ############ */ 991/* ############################################ */ 992 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 1020function changeNavLang(lang) { 1021 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")) 1027 } 1028 }); 1029} 1030 1031function changeDocLang(lang) { 1032 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} 1091 1092 1093/* 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(); 1106 $(ids).prev('h4').find('a.expandable').removeClass('expanded'); 1107} 1108 1109 1110 1111 1112 1113/* 1114 * 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 1297/* 1298 * 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 1724 blogSearcher = new google.search.WebSearch(); 1725 blogSearcher.setUserDefinedLabel("Blog"); 1726 blogSearcher.setSiteRestriction("http://android-developers.blogspot.com"); 1727 1728 // add each searcher to the search control 1729 searchControl.addSearcher(devSiteSearcher, searchOptions); 1730 searchControl.addSearcher(designSearcher, searchOptions); 1731 searchControl.addSearcher(trainingSearcher, searchOptions); 1732 searchControl.addSearcher(guidesSearcher, searchOptions); 1733 searchControl.addSearcher(referenceSearcher, searchOptions); 1734 searchControl.addSearcher(blogSearcher, searchOptions); 1735 1736 // configure result options 1737 searchControl.setResultSetSize(google.search.Search.LARGE_RESULTSET); 1738 searchControl.setLinkTarget(google.search.Search.LINK_TARGET_SELF); 1739 searchControl.setTimeoutInterval(google.search.SearchControl.TIMEOUT_SHORT); 1740 searchControl.setNoResultsString(google.search.SearchControl.NO_RESULTS_DEFAULT_STRING); 1741 1742 // upon ajax search, refresh the url and search title 1743 searchControl.setSearchStartingCallback(this, function(control, searcher, query) { 1744 updateResultTitle(query); 1745 var query = document.getElementById('search_autocomplete').value; 1746 location.hash = 'q=' + query; 1747 }); 1748 1749 // draw the search results box 1750 searchControl.draw(document.getElementById("leftSearchControl"), drawOptions); 1751 1752 // get query and execute the search 1753 searchControl.execute(decodeURI(getQuery(location.hash))); 1754 1755 document.getElementById("search_autocomplete").focus(); 1756 addTabListeners(); 1757} 1758// End of loadSearchResults 1759 1760 1761google.setOnLoadCallback(function(){ 1762 if (location.hash.indexOf("q=") == -1) { 1763 // if there's no query in the url, don't search and make sure results are hidden 1764 $('#searchResults').hide(); 1765 return; 1766 } else { 1767 // first time loading search results for this page 1768 $('#searchResults').slideDown('slow'); 1769 $(".search .close").removeClass("hide"); 1770 loadSearchResults(); 1771 } 1772}, true); 1773 1774// when an event on the browser history occurs (back, forward, load) requery hash and do search 1775$(window).hashchange( function(){ 1776 // Exit if the hash isn't a search query or there's an error in the query 1777 if ((location.hash.indexOf("q=") == -1) || (query == "undefined")) { 1778 // If the results pane is open, close it. 1779 if (!$("#searchResults").is(":hidden")) { 1780 hideResults(); 1781 } 1782 return; 1783 } 1784 1785 // Otherwise, we have a search to do 1786 var query = decodeURI(getQuery(location.hash)); 1787 searchControl.execute(query); 1788 $('#searchResults').slideDown('slow'); 1789 $("#search_autocomplete").focus(); 1790 $(".search .close").removeClass("hide"); 1791 1792 updateResultTitle(query); 1793}); 1794 1795function updateResultTitle(query) { 1796 $("#searchTitle").html("Results for <em>" + escapeHTML(query) + "</em>"); 1797} 1798 1799// forcefully regain key-up event control (previously jacked by search api) 1800$("#search_autocomplete").keyup(function(event) { 1801 return search_changed(event, false, toRoot); 1802}); 1803 1804// add event listeners to each tab so we can track the browser history 1805function addTabListeners() { 1806 var tabHeaders = $(".gsc-tabHeader"); 1807 for (var i = 0; i < tabHeaders.length; i++) { 1808 $(tabHeaders[i]).attr("id",i).click(function() { 1809 /* 1810 // make a copy of the page numbers for the search left pane 1811 setTimeout(function() { 1812 // remove any residual page numbers 1813 $('#searchResults .gsc-tabsArea .gsc-cursor-box.gs-bidi-start-align').remove(); 1814 // move the page numbers to the left position; make a clone, 1815 // because the element is drawn to the DOM only once 1816 // and because we're going to remove it (previous line), 1817 // we need it to be available to move again as the user navigates 1818 $('#searchResults .gsc-webResult .gsc-cursor-box.gs-bidi-start-align:visible') 1819 .clone().appendTo('#searchResults .gsc-tabsArea'); 1820 }, 200); 1821 */ 1822 }); 1823 } 1824 setTimeout(function(){$(tabHeaders[0]).click()},200); 1825} 1826 1827 1828function getQuery(hash) { 1829 var queryParts = hash.split('='); 1830 return queryParts[1]; 1831} 1832 1833/* returns the given string with all HTML brackets converted to entities 1834 TODO: move this to the site's JS library */ 1835function escapeHTML(string) { 1836 return string.replace(/</g,"<") 1837 .replace(/>/g,">"); 1838} 1839 1840 1841 1842 1843 1844 1845 1846/* ######################################################## */ 1847/* ################# JAVADOC REFERENCE ################### */ 1848/* ######################################################## */ 1849 1850/* Initialize some droiddoc stuff, but only if we're in the reference */ 1851if (location.pathname.indexOf("/reference")) { 1852 if(!location.pathname.indexOf("/reference-gms/packages.html") 1853 && !location.pathname.indexOf("/reference-gcm/packages.html") 1854 && !location.pathname.indexOf("/reference/com/google") == 0) { 1855 $(document).ready(function() { 1856 // init available apis based on user pref 1857 changeApiLevel(); 1858 initSidenavHeightResize() 1859 }); 1860 } 1861} 1862 1863var API_LEVEL_COOKIE = "api_level"; 1864var minLevel = 1; 1865var maxLevel = 1; 1866 1867/******* SIDENAV DIMENSIONS ************/ 1868 1869 function initSidenavHeightResize() { 1870 // Change the drag bar size to nicely fit the scrollbar positions 1871 var $dragBar = $(".ui-resizable-s"); 1872 $dragBar.css({'width': $dragBar.parent().width() - 5 + "px"}); 1873 1874 $( "#resize-packages-nav" ).resizable({ 1875 containment: "#nav-panels", 1876 handles: "s", 1877 alsoResize: "#packages-nav", 1878 resize: function(event, ui) { resizeNav(); }, /* resize the nav while dragging */ 1879 stop: function(event, ui) { saveNavPanels(); } /* once stopped, save the sizes to cookie */ 1880 }); 1881 1882 } 1883 1884function updateSidenavFixedWidth() { 1885 if (!navBarIsFixed) return; 1886 $('#devdoc-nav').css({ 1887 'width' : $('#side-nav').css('width'), 1888 'margin' : $('#side-nav').css('margin') 1889 }); 1890 $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'}); 1891 1892 initSidenavHeightResize(); 1893} 1894 1895function updateSidenavFullscreenWidth() { 1896 if (!navBarIsFixed) return; 1897 $('#devdoc-nav').css({ 1898 'width' : $('#side-nav').css('width'), 1899 'margin' : $('#side-nav').css('margin') 1900 }); 1901 $('#devdoc-nav .totop').css({'left': 'inherit'}); 1902 1903 initSidenavHeightResize(); 1904} 1905 1906function buildApiLevelSelector() { 1907 maxLevel = SINCE_DATA.length; 1908 var userApiLevel = parseInt(readCookie(API_LEVEL_COOKIE)); 1909 userApiLevel = userApiLevel == 0 ? maxLevel : userApiLevel; // If there's no cookie (zero), use the max by default 1910 1911 minLevel = parseInt($("#doc-api-level").attr("class")); 1912 // Handle provisional api levels; the provisional level will always be the highest possible level 1913 // Provisional api levels will also have a length; other stuff that's just missing a level won't, 1914 // so leave those kinds of entities at the default level of 1 (for example, the R.styleable class) 1915 if (isNaN(minLevel) && minLevel.length) { 1916 minLevel = maxLevel; 1917 } 1918 var select = $("#apiLevelSelector").html("").change(changeApiLevel); 1919 for (var i = maxLevel-1; i >= 0; i--) { 1920 var option = $("<option />").attr("value",""+SINCE_DATA[i]).append(""+SINCE_DATA[i]); 1921 // if (SINCE_DATA[i] < minLevel) option.addClass("absent"); // always false for strings (codenames) 1922 select.append(option); 1923 } 1924 1925 // get the DOM element and use setAttribute cuz IE6 fails when using jquery .attr('selected',true) 1926 var selectedLevelItem = $("#apiLevelSelector option[value='"+userApiLevel+"']").get(0); 1927 selectedLevelItem.setAttribute('selected',true); 1928} 1929 1930function changeApiLevel() { 1931 maxLevel = SINCE_DATA.length; 1932 var selectedLevel = maxLevel; 1933 1934 selectedLevel = parseInt($("#apiLevelSelector option:selected").val()); 1935 toggleVisisbleApis(selectedLevel, "body"); 1936 1937 var date = new Date(); 1938 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years 1939 var expiration = date.toGMTString(); 1940 writeCookie(API_LEVEL_COOKIE, selectedLevel, null, expiration); 1941 1942 if (selectedLevel < minLevel) { 1943 var thing = ($("#jd-header").html().indexOf("package") != -1) ? "package" : "class"; 1944 $("#naMessage").show().html("<div><p><strong>This " + thing 1945 + " requires API level " + minLevel + " or higher.</strong></p>" 1946 + "<p>This document is hidden because your selected API level for the documentation is " 1947 + selectedLevel + ". You can change the documentation API level with the selector " 1948 + "above the left navigation.</p>" 1949 + "<p>For more information about specifying the API level your app requires, " 1950 + "read <a href='" + toRoot + "training/basics/supporting-devices/platforms.html'" 1951 + ">Supporting Different Platform Versions</a>.</p>" 1952 + "<input type='button' value='OK, make this page visible' " 1953 + "title='Change the API level to " + minLevel + "' " 1954 + "onclick='$(\"#apiLevelSelector\").val(\"" + minLevel + "\");changeApiLevel();' />" 1955 + "</div>"); 1956 } else { 1957 $("#naMessage").hide(); 1958 } 1959} 1960 1961function toggleVisisbleApis(selectedLevel, context) { 1962 var apis = $(".api",context); 1963 apis.each(function(i) { 1964 var obj = $(this); 1965 var className = obj.attr("class"); 1966 var apiLevelIndex = className.lastIndexOf("-")+1; 1967 var apiLevelEndIndex = className.indexOf(" ", apiLevelIndex); 1968 apiLevelEndIndex = apiLevelEndIndex != -1 ? apiLevelEndIndex : className.length; 1969 var apiLevel = className.substring(apiLevelIndex, apiLevelEndIndex); 1970 if (apiLevel.length == 0) { // for odd cases when the since data is actually missing, just bail 1971 return; 1972 } 1973 apiLevel = parseInt(apiLevel); 1974 1975 // Handle provisional api levels; if this item's level is the provisional one, set it to the max 1976 var selectedLevelNum = parseInt(selectedLevel) 1977 var apiLevelNum = parseInt(apiLevel); 1978 if (isNaN(apiLevelNum)) { 1979 apiLevelNum = maxLevel; 1980 } 1981 1982 // Grey things out that aren't available and give a tooltip title 1983 if (apiLevelNum > selectedLevelNum) { 1984 obj.addClass("absent").attr("title","Requires API Level \"" 1985 + apiLevel + "\" or higher"); 1986 } 1987 else obj.removeClass("absent").removeAttr("title"); 1988 }); 1989} 1990 1991 1992 1993 1994/* ################# SIDENAV TREE VIEW ################### */ 1995 1996function new_node(me, mom, text, link, children_data, api_level) 1997{ 1998 var node = new Object(); 1999 node.children = Array(); 2000 node.children_data = children_data; 2001 node.depth = mom.depth + 1; 2002 2003 node.li = document.createElement("li"); 2004 mom.get_children_ul().appendChild(node.li); 2005 2006 node.label_div = document.createElement("div"); 2007 node.label_div.className = "label"; 2008 if (api_level != null) { 2009 $(node.label_div).addClass("api"); 2010 $(node.label_div).addClass("api-level-"+api_level); 2011 } 2012 node.li.appendChild(node.label_div); 2013 2014 if (children_data != null) { 2015 node.expand_toggle = document.createElement("a"); 2016 node.expand_toggle.href = "javascript:void(0)"; 2017 node.expand_toggle.onclick = function() { 2018 if (node.expanded) { 2019 $(node.get_children_ul()).slideUp("fast"); 2020 node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png"; 2021 node.expanded = false; 2022 } else { 2023 expand_node(me, node); 2024 } 2025 }; 2026 node.label_div.appendChild(node.expand_toggle); 2027 2028 node.plus_img = document.createElement("img"); 2029 node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png"; 2030 node.plus_img.className = "plus"; 2031 node.plus_img.width = "8"; 2032 node.plus_img.border = "0"; 2033 node.expand_toggle.appendChild(node.plus_img); 2034 2035 node.expanded = false; 2036 } 2037 2038 var a = document.createElement("a"); 2039 node.label_div.appendChild(a); 2040 node.label = document.createTextNode(text); 2041 a.appendChild(node.label); 2042 if (link) { 2043 a.href = me.toroot + link; 2044 } else { 2045 if (children_data != null) { 2046 a.className = "nolink"; 2047 a.href = "javascript:void(0)"; 2048 a.onclick = node.expand_toggle.onclick; 2049 // This next line shouldn't be necessary. I'll buy a beer for the first 2050 // person who figures out how to remove this line and have the link 2051 // toggle shut on the first try. --joeo@android.com 2052 node.expanded = false; 2053 } 2054 } 2055 2056 2057 node.children_ul = null; 2058 node.get_children_ul = function() { 2059 if (!node.children_ul) { 2060 node.children_ul = document.createElement("ul"); 2061 node.children_ul.className = "children_ul"; 2062 node.children_ul.style.display = "none"; 2063 node.li.appendChild(node.children_ul); 2064 } 2065 return node.children_ul; 2066 }; 2067 2068 return node; 2069} 2070 2071 2072 2073 2074function expand_node(me, node) 2075{ 2076 if (node.children_data && !node.expanded) { 2077 if (node.children_visited) { 2078 $(node.get_children_ul()).slideDown("fast"); 2079 } else { 2080 get_node(me, node); 2081 if ($(node.label_div).hasClass("absent")) { 2082 $(node.get_children_ul()).addClass("absent"); 2083 } 2084 $(node.get_children_ul()).slideDown("fast"); 2085 } 2086 node.plus_img.src = me.toroot + "assets/images/triangle-opened-small.png"; 2087 node.expanded = true; 2088 2089 // perform api level toggling because new nodes are new to the DOM 2090 var selectedLevel = $("#apiLevelSelector option:selected").val(); 2091 toggleVisisbleApis(selectedLevel, "#side-nav"); 2092 } 2093} 2094 2095function get_node(me, mom) 2096{ 2097 mom.children_visited = true; 2098 for (var i in mom.children_data) { 2099 var node_data = mom.children_data[i]; 2100 mom.children[i] = new_node(me, mom, node_data[0], node_data[1], 2101 node_data[2], node_data[3]); 2102 } 2103} 2104 2105function this_page_relative(toroot) 2106{ 2107 var full = document.location.pathname; 2108 var file = ""; 2109 if (toroot.substr(0, 1) == "/") { 2110 if (full.substr(0, toroot.length) == toroot) { 2111 return full.substr(toroot.length); 2112 } else { 2113 // the file isn't under toroot. Fail. 2114 return null; 2115 } 2116 } else { 2117 if (toroot != "./") { 2118 toroot = "./" + toroot; 2119 } 2120 do { 2121 if (toroot.substr(toroot.length-3, 3) == "../" || toroot == "./") { 2122 var pos = full.lastIndexOf("/"); 2123 file = full.substr(pos) + file; 2124 full = full.substr(0, pos); 2125 toroot = toroot.substr(0, toroot.length-3); 2126 } 2127 } while (toroot != "" && toroot != "/"); 2128 return file.substr(1); 2129 } 2130} 2131 2132function find_page(url, data) 2133{ 2134 var nodes = data; 2135 var result = null; 2136 for (var i in nodes) { 2137 var d = nodes[i]; 2138 if (d[1] == url) { 2139 return new Array(i); 2140 } 2141 else if (d[2] != null) { 2142 result = find_page(url, d[2]); 2143 if (result != null) { 2144 return (new Array(i).concat(result)); 2145 } 2146 } 2147 } 2148 return null; 2149} 2150 2151function init_default_navtree(toroot) { 2152 init_navtree("tree-list", toroot, NAVTREE_DATA); 2153 2154 // perform api level toggling because because the whole tree is new to the DOM 2155 var selectedLevel = $("#apiLevelSelector option:selected").val(); 2156 toggleVisisbleApis(selectedLevel, "#side-nav"); 2157} 2158 2159function init_navtree(navtree_id, toroot, root_nodes) 2160{ 2161 var me = new Object(); 2162 me.toroot = toroot; 2163 me.node = new Object(); 2164 2165 me.node.li = document.getElementById(navtree_id); 2166 me.node.children_data = root_nodes; 2167 me.node.children = new Array(); 2168 me.node.children_ul = document.createElement("ul"); 2169 me.node.get_children_ul = function() { return me.node.children_ul; }; 2170 //me.node.children_ul.className = "children_ul"; 2171 me.node.li.appendChild(me.node.children_ul); 2172 me.node.depth = 0; 2173 2174 get_node(me, me.node); 2175 2176 me.this_page = this_page_relative(toroot); 2177 me.breadcrumbs = find_page(me.this_page, root_nodes); 2178 if (me.breadcrumbs != null && me.breadcrumbs.length != 0) { 2179 var mom = me.node; 2180 for (var i in me.breadcrumbs) { 2181 var j = me.breadcrumbs[i]; 2182 mom = mom.children[j]; 2183 expand_node(me, mom); 2184 } 2185 mom.label_div.className = mom.label_div.className + " selected"; 2186 addLoadEvent(function() { 2187 scrollIntoView("nav-tree"); 2188 }); 2189 } 2190} 2191 2192/* TODO: eliminate redundancy with non-google functions */ 2193function init_google_navtree(navtree_id, toroot, root_nodes) 2194{ 2195 var me = new Object(); 2196 me.toroot = toroot; 2197 me.node = new Object(); 2198 2199 me.node.li = document.getElementById(navtree_id); 2200 me.node.children_data = root_nodes; 2201 me.node.children = new Array(); 2202 me.node.children_ul = document.createElement("ul"); 2203 me.node.get_children_ul = function() { return me.node.children_ul; }; 2204 //me.node.children_ul.className = "children_ul"; 2205 me.node.li.appendChild(me.node.children_ul); 2206 me.node.depth = 0; 2207 2208 get_google_node(me, me.node); 2209 2210} 2211 2212function new_google_node(me, mom, text, link, children_data, api_level) 2213{ 2214 var node = new Object(); 2215 var child; 2216 node.children = Array(); 2217 node.children_data = children_data; 2218 node.depth = mom.depth + 1; 2219 node.get_children_ul = function() { 2220 if (!node.children_ul) { 2221 node.children_ul = document.createElement("ul"); 2222 node.children_ul.className = "tree-list-children"; 2223 node.li.appendChild(node.children_ul); 2224 } 2225 return node.children_ul; 2226 }; 2227 node.li = document.createElement("li"); 2228 2229 mom.get_children_ul().appendChild(node.li); 2230 2231 2232 if(link) { 2233 child = document.createElement("a"); 2234 2235 } 2236 else { 2237 child = document.createElement("span"); 2238 child.className = "tree-list-subtitle"; 2239 2240 } 2241 if (children_data != null) { 2242 node.li.className="nav-section"; 2243 node.label_div = document.createElement("div"); 2244 node.label_div.className = "nav-section-header-ref"; 2245 node.li.appendChild(node.label_div); 2246 get_google_node(me, node); 2247 node.label_div.appendChild(child); 2248 } 2249 else { 2250 node.li.appendChild(child); 2251 } 2252 if(link) { 2253 child.href = me.toroot + link; 2254 } 2255 node.label = document.createTextNode(text); 2256 child.appendChild(node.label); 2257 2258 node.children_ul = null; 2259 2260 return node; 2261} 2262 2263function get_google_node(me, mom) 2264{ 2265 mom.children_visited = true; 2266 var linkText; 2267 for (var i in mom.children_data) { 2268 var node_data = mom.children_data[i]; 2269 linkText = node_data[0]; 2270 2271 if(linkText.match("^"+"com.google.android")=="com.google.android"){ 2272 linkText = linkText.substr(19, linkText.length); 2273 } 2274 mom.children[i] = new_google_node(me, mom, linkText, node_data[1], 2275 node_data[2], node_data[3]); 2276 } 2277} 2278function showGoogleRefTree() { 2279 init_default_google_navtree(toRoot); 2280 init_default_gcm_navtree(toRoot); 2281 resizeNav(); 2282} 2283 2284function init_default_google_navtree(toroot) { 2285 init_google_navtree("gms-tree-list", toroot, GMS_NAVTREE_DATA); 2286} 2287 2288function init_default_gcm_navtree(toroot) { 2289 init_google_navtree("gcm-tree-list", toroot, GCM_NAVTREE_DATA); 2290} 2291 2292/* TOGGLE INHERITED MEMBERS */ 2293 2294/* Toggle an inherited class (arrow toggle) 2295 * @param linkObj The link that was clicked. 2296 * @param expand 'true' to ensure it's expanded. 'false' to ensure it's closed. 2297 * 'null' to simply toggle. 2298 */ 2299function toggleInherited(linkObj, expand) { 2300 var base = linkObj.getAttribute("id"); 2301 var list = document.getElementById(base + "-list"); 2302 var summary = document.getElementById(base + "-summary"); 2303 var trigger = document.getElementById(base + "-trigger"); 2304 var a = $(linkObj); 2305 if ( (expand == null && a.hasClass("closed")) || expand ) { 2306 list.style.display = "none"; 2307 summary.style.display = "block"; 2308 trigger.src = toRoot + "assets/images/triangle-opened.png"; 2309 a.removeClass("closed"); 2310 a.addClass("opened"); 2311 } else if ( (expand == null && a.hasClass("opened")) || (expand == false) ) { 2312 list.style.display = "block"; 2313 summary.style.display = "none"; 2314 trigger.src = toRoot + "assets/images/triangle-closed.png"; 2315 a.removeClass("opened"); 2316 a.addClass("closed"); 2317 } 2318 return false; 2319} 2320 2321/* Toggle all inherited classes in a single table (e.g. all inherited methods) 2322 * @param linkObj The link that was clicked. 2323 * @param expand 'true' to ensure it's expanded. 'false' to ensure it's closed. 2324 * 'null' to simply toggle. 2325 */ 2326function toggleAllInherited(linkObj, expand) { 2327 var a = $(linkObj); 2328 var table = $(a.parent().parent().parent()); // ugly way to get table/tbody 2329 var expandos = $(".jd-expando-trigger", table); 2330 if ( (expand == null && a.text() == "[Expand]") || expand ) { 2331 expandos.each(function(i) { 2332 toggleInherited(this, true); 2333 }); 2334 a.text("[Collapse]"); 2335 } else if ( (expand == null && a.text() == "[Collapse]") || (expand == false) ) { 2336 expandos.each(function(i) { 2337 toggleInherited(this, false); 2338 }); 2339 a.text("[Expand]"); 2340 } 2341 return false; 2342} 2343 2344/* Toggle all inherited members in the class (link in the class title) 2345 */ 2346function toggleAllClassInherited() { 2347 var a = $("#toggleAllClassInherited"); // get toggle link from class title 2348 var toggles = $(".toggle-all", $("#body-content")); 2349 if (a.text() == "[Expand All]") { 2350 toggles.each(function(i) { 2351 toggleAllInherited(this, true); 2352 }); 2353 a.text("[Collapse All]"); 2354 } else { 2355 toggles.each(function(i) { 2356 toggleAllInherited(this, false); 2357 }); 2358 a.text("[Expand All]"); 2359 } 2360 return false; 2361} 2362 2363/* Expand all inherited members in the class. Used when initiating page search */ 2364function ensureAllInheritedExpanded() { 2365 var toggles = $(".toggle-all", $("#body-content")); 2366 toggles.each(function(i) { 2367 toggleAllInherited(this, true); 2368 }); 2369 $("#toggleAllClassInherited").text("[Collapse All]"); 2370} 2371 2372 2373/* HANDLE KEY EVENTS 2374 * - Listen for Ctrl+F (Cmd on Mac) and expand all inherited members (to aid page search) 2375 */ 2376var agent = navigator['userAgent'].toLowerCase(); 2377var mac = agent.indexOf("macintosh") != -1; 2378 2379$(document).keydown( function(e) { 2380var control = mac ? e.metaKey && !e.ctrlKey : e.ctrlKey; // get ctrl key 2381 if (control && e.which == 70) { // 70 is "F" 2382 ensureAllInheritedExpanded(); 2383 } 2384}); 2385