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