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