1var resizePackagesNav; 2var classesNav; 3var devdocNav; 4var sidenav; 5var content; 6var HEADER_HEIGHT = 117; 7var cookie_namespace = 'android_developer'; 8var NAV_PREF_TREE = "tree"; 9var NAV_PREF_PANELS = "panels"; 10var nav_pref; 11var toRoot; 12var isMobile = false; // true if mobile, so we can adjust some layout 13var isIE6 = false; // true if IE6 14 15// TODO: use $(document).ready instead 16function addLoadEvent(newfun) { 17 var current = window.onload; 18 if (typeof window.onload != 'function') { 19 window.onload = newfun; 20 } else { 21 window.onload = function() { 22 current(); 23 newfun(); 24 } 25 } 26} 27 28var agent = navigator['userAgent'].toLowerCase(); 29// If a mobile phone, set flag and do mobile setup 30if ((agent.indexOf("mobile") != -1) || // android, iphone, ipod 31 (agent.indexOf("blackberry") != -1) || 32 (agent.indexOf("webos") != -1) || 33 (agent.indexOf("mini") != -1)) { // opera mini browsers 34 isMobile = true; 35 addLoadEvent(mobileSetup); 36// If not a mobile browser, set the onresize event for IE6, and others 37} else if (agent.indexOf("msie 6") != -1) { 38 isIE6 = true; 39 addLoadEvent(function() { 40 window.onresize = resizeAll; 41 }); 42} else { 43 addLoadEvent(function() { 44 window.onresize = resizeHeight; 45 }); 46} 47 48function mobileSetup() { 49 $("body").css({'overflow':'auto'}); 50 $("html").css({'overflow':'auto'}); 51 $("#body-content").css({'position':'relative', 'top':'0'}); 52 $("#doc-content").css({'overflow':'visible', 'border-left':'3px solid #DDD'}); 53 $("#side-nav").css({'padding':'0'}); 54 $("#nav-tree").css({'overflow-y': 'auto'}); 55} 56 57/* loads the lists.js file to the page. 58Loading this in the head was slowing page load time */ 59addLoadEvent( function() { 60 var lists = document.createElement("script"); 61 lists.setAttribute("type","text/javascript"); 62 lists.setAttribute("src", toRoot+"reference/lists.js"); 63 document.getElementsByTagName("head")[0].appendChild(lists); 64} ); 65 66addLoadEvent( function() { 67 $("pre:not(.no-pretty-print)").addClass("prettyprint"); 68 prettyPrint(); 69} ); 70 71function setToRoot(root) { 72 toRoot = root; 73 // note: toRoot also used by carousel.js 74} 75 76function restoreWidth(navWidth) { 77 var windowWidth = $(window).width() + "px"; 78 content.css({marginLeft:parseInt(navWidth) + 6 + "px"}); //account for 6px-wide handle-bar 79 80 if (isIE6) { 81 content.css({width:parseInt(windowWidth) - parseInt(navWidth) - 6 + "px"}); // necessary in order for scrollbars to be visible 82 } 83 84 sidenav.css({width:navWidth}); 85 resizePackagesNav.css({width:navWidth}); 86 classesNav.css({width:navWidth}); 87 $("#packages-nav").css({width:navWidth}); 88} 89 90function restoreHeight(packageHeight) { 91 var windowHeight = ($(window).height() - HEADER_HEIGHT); 92 var swapperHeight = windowHeight - 13; 93 $("#swapper").css({height:swapperHeight + "px"}); 94 sidenav.css({height:windowHeight + "px"}); 95 content.css({height:windowHeight + "px"}); 96 resizePackagesNav.css({maxHeight:swapperHeight + "px", height:packageHeight}); 97 classesNav.css({height:swapperHeight - parseInt(packageHeight) + "px"}); 98 $("#packages-nav").css({height:parseInt(packageHeight) - 6 + "px"}); //move 6px to give space for the resize handle 99 devdocNav.css({height:sidenav.css("height")}); 100 $("#nav-tree").css({height:swapperHeight + "px"}); 101} 102 103function readCookie(cookie) { 104 var myCookie = cookie_namespace+"_"+cookie+"="; 105 if (document.cookie) { 106 var index = document.cookie.indexOf(myCookie); 107 if (index != -1) { 108 var valStart = index + myCookie.length; 109 var valEnd = document.cookie.indexOf(";", valStart); 110 if (valEnd == -1) { 111 valEnd = document.cookie.length; 112 } 113 var val = document.cookie.substring(valStart, valEnd); 114 return val; 115 } 116 } 117 return 0; 118} 119 120function writeCookie(cookie, val, section, expiration) { 121 if (val==undefined) return; 122 section = section == null ? "_" : "_"+section+"_"; 123 if (expiration == null) { 124 var date = new Date(); 125 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week 126 expiration = date.toGMTString(); 127 } 128 document.cookie = cookie_namespace + section + cookie + "=" + val + "; expires=" + expiration+"; path=/"; 129} 130 131function init() { 132 $("#side-nav").css({position:"absolute",left:0}); 133 content = $("#doc-content"); 134 resizePackagesNav = $("#resize-packages-nav"); 135 classesNav = $("#classes-nav"); 136 sidenav = $("#side-nav"); 137 devdocNav = $("#devdoc-nav"); 138 139 var cookiePath = ""; 140 if (location.href.indexOf("/reference/") != -1) { 141 cookiePath = "reference_"; 142 } else if (location.href.indexOf("/guide/") != -1) { 143 cookiePath = "guide_"; 144 } else if (location.href.indexOf("/sdk/") != -1) { 145 cookiePath = "sdk_"; 146 } else if ((location.href.indexOf("/resources/") != -1) || 147 (location.href.indexOf("/training/") != -1)) { 148 cookiePath = "resources_"; 149 } 150 151 if (!isMobile) { 152 $("#resize-packages-nav").resizable({handles: "s", resize: function(e, ui) { resizePackagesHeight(); } }); 153 $("#side-nav").resizable({handles: "e", resize: function(e, ui) { resizeWidth(); } }); 154 var cookieWidth = readCookie(cookiePath+'width'); 155 var cookieHeight = readCookie(cookiePath+'height'); 156 if (cookieWidth) { 157 restoreWidth(cookieWidth); 158 } else if ($("#side-nav").length) { 159 resizeWidth(); 160 } 161 if (cookieHeight) { 162 restoreHeight(cookieHeight); 163 } else { 164 resizeHeight(); 165 } 166 } 167 168 if (devdocNav.length) { // only dev guide, resources, and sdk 169 tryPopulateResourcesNav(); 170 highlightNav(location.href); 171 } 172} 173 174function tryPopulateResourcesNav() { 175 var sampleList = $('#devdoc-nav-sample-list'); 176 var articleList = $('#devdoc-nav-article-list'); 177 var tutorialList = $('#devdoc-nav-tutorial-list'); 178 var topicList = $('#devdoc-nav-topic-list'); 179 180 if (!topicList.length || !ANDROID_TAGS || !ANDROID_RESOURCES) 181 return; 182 183 var topics = []; 184 for (var topic in ANDROID_TAGS['topic']) { 185 topics.push({name:topic,title:ANDROID_TAGS['topic'][topic]}); 186 } 187 topics.sort(function(x,y){ return (x.title < y.title) ? -1 : 1; }); 188 for (var i = 0; i < topics.length; i++) { 189 topicList.append( 190 $('<li>').append( 191 $('<a>') 192 .attr('href', toRoot + "resources/browser.html?tag=" + topics[i].name) 193 .append($('<span>') 194 .addClass('en') 195 .html(topics[i].title) 196 ) 197 ) 198 ); 199 } 200 201 var _renderResourceList = function(tag, listNode) { 202 var resources = []; 203 var tags; 204 var resource; 205 var i, j; 206 for (i = 0; i < ANDROID_RESOURCES.length; i++) { 207 resource = ANDROID_RESOURCES[i]; 208 tags = resource.tags || []; 209 var hasTag = false; 210 for (j = 0; j < tags.length; j++) 211 if (tags[j] == tag) { 212 hasTag = true; 213 break; 214 } 215 if (!hasTag) 216 continue; 217 resources.push(resource); 218 } 219 //resources.sort(function(x,y){ return (x.title.en < y.title.en) ? -1 : 1; }); 220 for (i = 0; i < resources.length; i++) { 221 resource = resources[i]; 222 var listItemNode = $('<li>').append( 223 $('<a>') 224 .attr('href', toRoot + "resources/" + resource.path) 225 .append($('<span>') 226 .addClass('en') 227 .html(resource.title.en) 228 ) 229 ); 230 tags = resource.tags || []; 231 for (j = 0; j < tags.length; j++) { 232 if (tags[j] == 'new') { 233 listItemNode.get(0).innerHTML += ' <span class="new">new!</span>'; 234 break; 235 } else if (tags[j] == 'updated') { 236 listItemNode.get(0).innerHTML += ' <span class="new">updated!</span>'; 237 break; 238 } 239 } 240 listNode.append(listItemNode); 241 } 242 }; 243 244 _renderResourceList('sample', sampleList); 245 _renderResourceList('article', articleList); 246 _renderResourceList('tutorial', tutorialList); 247} 248 249function highlightNav(fullPageName) { 250 var lastSlashPos = fullPageName.lastIndexOf("/"); 251 var firstSlashPos; 252 if (fullPageName.indexOf("/guide/") != -1) { 253 firstSlashPos = fullPageName.indexOf("/guide/"); 254 } else if (fullPageName.indexOf("/sdk/") != -1) { 255 firstSlashPos = fullPageName.indexOf("/sdk/"); 256 } else if (fullPageName.indexOf("/resources/") != -1) { 257 firstSlashPos = fullPageName.indexOf("/resources/"); 258 } else if (fullPageName.indexOf("/training/") != -1) { 259 firstSlashPos = fullPageName.indexOf("/training/"); 260 } 261 if (lastSlashPos == (fullPageName.length - 1)) { // if the url ends in slash (add 'index.html') 262 fullPageName = fullPageName + "index.html"; 263 } 264 265 // get the path and page name from the URL (such as 'guide/topics/graphics/index.html') 266 var htmlPos = fullPageName.indexOf(".html"); 267 var pathPageName = fullPageName.slice(firstSlashPos, htmlPos + 5); // +5 advances past ".html" 268 // find instances of the page name in the side nav 269 var link = $("#devdoc-nav a[href$='"+ pathPageName+"']"); 270 // if there's no match, then let's backstep through the directory until we find an index.html 271 // page that matches our ancestor directories (only for dev guide and resources) 272 if ((link.length == 0) && ((fullPageName.indexOf("/guide/") != -1) || 273 (fullPageName.indexOf("/resources/") != -1))) { 274 lastBackstep = pathPageName.lastIndexOf("/"); 275 while (link.length == 0) { 276 backstepDirectory = pathPageName.lastIndexOf("/", lastBackstep); 277 link = $("#devdoc-nav a[href$='"+ pathPageName.slice(0, backstepDirectory + 278 1)+"index.html']"); 279 lastBackstep = pathPageName.lastIndexOf("/", lastBackstep - 1); 280 if (lastBackstep == 0) break; 281 } 282 } 283 284 // add 'selected' to the <li> or <div> that wraps this <a> 285 link.parent().addClass('selected'); 286 287 // if we're in a toggleable root link (<li class=toggle-list><div><a>) 288 if (link.parent().parent().hasClass('toggle-list')) { 289 toggle(link.parent().parent(), false); // open our own list 290 // then also check if we're in a third-level nested list that's toggleable 291 if (link.parent().parent().parent().is(':hidden')) { 292 toggle(link.parent().parent().parent().parent(), false); // open the super parent list 293 } 294 } 295 // if we're in a normal nav link (<li><a>) and the parent <ul> is hidden 296 else if (link.parent().parent().is(':hidden')) { 297 toggle(link.parent().parent().parent(), false); // open the parent list 298 // then also check if the parent list is also nested in a hidden list 299 if (link.parent().parent().parent().parent().is(':hidden')) { 300 toggle(link.parent().parent().parent().parent().parent(), false); // open the super parent list 301 } 302 } 303} 304 305/* Resize the height of the nav panels in the reference, 306 * and save the new size to a cookie */ 307function resizePackagesHeight() { 308 var windowHeight = ($(window).height() - HEADER_HEIGHT); 309 var swapperHeight = windowHeight - 13; // move 13px for swapper link at the bottom 310 resizePackagesNav.css({maxHeight:swapperHeight + "px"}); 311 classesNav.css({height:swapperHeight - parseInt(resizePackagesNav.css("height")) + "px"}); 312 313 $("#swapper").css({height:swapperHeight + "px"}); 314 $("#packages-nav").css({height:parseInt(resizePackagesNav.css("height")) - 6 + "px"}); //move 6px for handle 315 316 var basePath = getBaseUri(location.pathname); 317 var section = basePath.substring(1,basePath.indexOf("/",1)); 318 writeCookie("height", resizePackagesNav.css("height"), section, null); 319} 320 321/* Resize the height of the side-nav and doc-content divs, 322 * which creates the frame effect */ 323function resizeHeight() { 324 var docContent = $("#doc-content"); 325 326 // Get the window height and always resize the doc-content and side-nav divs 327 var windowHeight = ($(window).height() - HEADER_HEIGHT); 328 docContent.css({height:windowHeight + "px"}); 329 $("#side-nav").css({height:windowHeight + "px"}); 330 331 var href = location.href; 332 // If in the reference docs, also resize the "swapper", "classes-nav", and "nav-tree" divs 333 if (href.indexOf("/reference/") != -1) { 334 var swapperHeight = windowHeight - 13; 335 $("#swapper").css({height:swapperHeight + "px"}); 336 $("#classes-nav").css({height:swapperHeight - parseInt(resizePackagesNav.css("height")) + "px"}); 337 $("#nav-tree").css({height:swapperHeight + "px"}); 338 339 // Also resize the "devdoc-nav" div 340 } else if ($("#devdoc-nav").length) { 341 $("#devdoc-nav").css({height:sidenav.css("height")}); 342 } 343 344 // Hide the "Go to top" link if there's no vertical scroll 345 if ( parseInt($("#jd-content").css("height")) <= parseInt(docContent.css("height")) ) { 346 $("a[href='#top']").css({'display':'none'}); 347 } else { 348 $("a[href='#top']").css({'display':'inline'}); 349 } 350} 351 352/* Resize the width of the "side-nav" and the left margin of the "doc-content" div, 353 * which creates the resizable side bar */ 354function resizeWidth() { 355 var windowWidth = $(window).width() + "px"; 356 var sidenav = $("#side-nav"); 357 if (sidenav.length) { 358 var sidenavWidth = sidenav.css("width"); 359 } else { 360 var sidenavWidth = 0; 361 } 362 content.css({marginLeft:parseInt(sidenavWidth) + 6 + "px"}); //account for 6px-wide handle-bar 363 364 if (isIE6) { 365 content.css({width:parseInt(windowWidth) - parseInt(sidenavWidth) - 6 + "px"}); // necessary in order to for scrollbars to be visible 366 } 367 368 resizePackagesNav.css({width:sidenavWidth}); 369 classesNav.css({width:sidenavWidth}); 370 $("#packages-nav").css({width:sidenavWidth}); 371 372 if (sidenav.length) { // Must check if the nav exists because IE6 calls resizeWidth() from resizeAll() for all pages 373 var basePath = getBaseUri(location.pathname); 374 var section = basePath.substring(1,basePath.indexOf("/",1)); 375 section = section.indexOf("training") != -1 ? "resources" : section; 376 writeCookie("width", sidenavWidth, section, null); 377 } 378} 379 380/* For IE6 only, 381 * because it can't properly perform auto width for "doc-content" div, 382 * avoiding this for all browsers provides better performance */ 383function resizeAll() { 384 resizeHeight(); 385 resizeWidth(); 386} 387 388function getBaseUri(uri) { 389 var intlUrl = (uri.substring(0,6) == "/intl/"); 390 if (intlUrl) { 391 base = uri.substring(uri.indexOf('intl/')+5,uri.length); 392 base = base.substring(base.indexOf('/')+1, base.length); 393 //alert("intl, returning base url: /" + base); 394 return ("/" + base); 395 } else { 396 //alert("not intl, returning uri as found."); 397 return uri; 398 } 399} 400 401function requestAppendHL(uri) { 402//append "?hl=<lang> to an outgoing request (such as to blog) 403 var lang = getLangPref(); 404 if (lang) { 405 var q = 'hl=' + lang; 406 uri += '?' + q; 407 window.location = uri; 408 return false; 409 } else { 410 return true; 411 } 412} 413 414function loadLast(cookiePath) { 415 var location = window.location.href; 416 if (location.indexOf("/"+cookiePath+"/") != -1) { 417 return true; 418 } 419 var lastPage = readCookie(cookiePath + "_lastpage"); 420 if (lastPage) { 421 window.location = lastPage; 422 return false; 423 } 424 return true; 425} 426 427$(window).unload(function(){ 428 var path = getBaseUri(location.pathname); 429 if (path.indexOf("/reference/") != -1) { 430 writeCookie("lastpage", path, "reference", null); 431 } else if (path.indexOf("/guide/") != -1) { 432 writeCookie("lastpage", path, "guide", null); 433 } else if ((path.indexOf("/resources/") != -1) || (path.indexOf("/training/") != -1)) { 434 writeCookie("lastpage", path, "resources", null); 435 } 436}); 437 438function toggle(obj, slide) { 439 var ul = $("ul:first", obj); 440 var li = ul.parent(); 441 if (li.hasClass("closed")) { 442 if (slide) { 443 ul.slideDown("fast"); 444 } else { 445 ul.show(); 446 } 447 li.removeClass("closed"); 448 li.addClass("open"); 449 $(".toggle-img", li).attr("title", "hide pages"); 450 } else { 451 ul.slideUp("fast"); 452 li.removeClass("open"); 453 li.addClass("closed"); 454 $(".toggle-img", li).attr("title", "show pages"); 455 } 456} 457 458function buildToggleLists() { 459 $(".toggle-list").each( 460 function(i) { 461 $("div:first", this).append("<a class='toggle-img' href='#' title='show pages' onClick='toggle(this.parentNode.parentNode, true); return false;'></a>"); 462 $(this).addClass("closed"); 463 }); 464} 465 466function getNavPref() { 467 var v = readCookie('reference_nav'); 468 if (v != NAV_PREF_TREE) { 469 v = NAV_PREF_PANELS; 470 } 471 return v; 472} 473 474function chooseDefaultNav() { 475 nav_pref = getNavPref(); 476 if (nav_pref == NAV_PREF_TREE) { 477 $("#nav-panels").toggle(); 478 $("#panel-link").toggle(); 479 $("#nav-tree").toggle(); 480 $("#tree-link").toggle(); 481 } 482} 483 484function swapNav() { 485 if (nav_pref == NAV_PREF_TREE) { 486 nav_pref = NAV_PREF_PANELS; 487 } else { 488 nav_pref = NAV_PREF_TREE; 489 init_default_navtree(toRoot); 490 } 491 var date = new Date(); 492 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years 493 writeCookie("nav", nav_pref, "reference", date.toGMTString()); 494 495 $("#nav-panels").toggle(); 496 $("#panel-link").toggle(); 497 $("#nav-tree").toggle(); 498 $("#tree-link").toggle(); 499 500 if ($("#nav-tree").is(':visible')) scrollIntoView("nav-tree"); 501 else { 502 scrollIntoView("packages-nav"); 503 scrollIntoView("classes-nav"); 504 } 505} 506 507function scrollIntoView(nav) { 508 var navObj = $("#"+nav); 509 if (navObj.is(':visible')) { 510 var selected = $(".selected", navObj); 511 if (selected.length == 0) return; 512 if (selected.is("div")) selected = selected.parent(); // when the selected item is a parent 513 514 var scrolling = document.getElementById(nav); 515 var navHeight = navObj.height(); 516 var offsetTop = selected.position().top; 517 518 // handle nested items 519 if (selected.parent().parent().is(".toggle-list")) { 520 selected = selected.parent().parent(); 521 // handle second level nested items 522 if (selected.parent().parent().is(".toggle-list")) { 523 selected = selected.parent().parent(); 524 } 525 offsetTop += selected.position().top; 526 } 527 528 // 180px from the bottom of the list is the threshold 529 if(offsetTop > navHeight - 180) { 530 scrolling.scrollTop = offsetTop - navHeight + 180; 531 } 532 } 533} 534 535function changeTabLang(lang) { 536 var nodes = $("#header-tabs").find("."+lang); 537 for (i=0; i < nodes.length; i++) { // for each node in this language 538 var node = $(nodes[i]); 539 node.siblings().css("display","none"); // hide all siblings 540 if (node.not(":empty").length != 0) { //if this languages node has a translation, show it 541 node.css("display","inline"); 542 } else { //otherwise, show English instead 543 node.css("display","none"); 544 node.siblings().filter(".en").css("display","inline"); 545 } 546 } 547} 548 549function changeNavLang(lang) { 550 var nodes = $("#side-nav").find("."+lang); 551 for (i=0; i < nodes.length; i++) { // for each node in this language 552 var node = $(nodes[i]); 553 node.siblings().css("display","none"); // hide all siblings 554 if (node.not(":empty").length != 0) { // if this languages node has a translation, show it 555 node.css("display","inline"); 556 } else { // otherwise, show English instead 557 node.css("display","none"); 558 node.siblings().filter(".en").css("display","inline"); 559 } 560 } 561} 562 563function changeDocLang(lang) { 564 changeTabLang(lang); 565 changeNavLang(lang); 566} 567 568function changeLangPref(lang, refresh) { 569 var date = new Date(); 570 expires = date.toGMTString(date.setTime(date.getTime()+(10*365*24*60*60*1000))); // keep this for 50 years 571 //alert("expires: " + expires) 572 writeCookie("pref_lang", lang, null, expires); 573 //changeDocLang(lang); 574 if (refresh) { 575 l = getBaseUri(location.pathname); 576 window.location = l; 577 } 578} 579 580function loadLangPref() { 581 var lang = readCookie("pref_lang"); 582 if (lang != 0) { 583 $("#language").find("option[value='"+lang+"']").attr("selected",true); 584 } 585} 586 587function getLangPref() { 588 var lang = $("#language").find(":selected").attr("value"); 589 if (!lang) { 590 lang = readCookie("pref_lang"); 591 } 592 return (lang != 0) ? lang : 'en'; 593} 594 595 596/* Used to hide and reveal supplemental content, such as long code samples. 597 See the companion CSS in android-developer-docs.css */ 598function toggleContent(obj) { 599 var div = $(obj.parentNode.parentNode); 600 var toggleMe = $(".toggle-content-toggleme",div); 601 if (div.hasClass("closed")) { // if it's closed, open it 602 toggleMe.slideDown(); 603 $(".toggle-content-text", obj).toggle(); 604 div.removeClass("closed").addClass("open"); 605 $(".toggle-content-img", div).attr("title", "hide").attr("src", toRoot + "assets/images/triangle-opened.png"); 606 } else { // if it's open, close it 607 toggleMe.slideUp('fast', function() { // Wait until the animation is done before closing arrow 608 $(".toggle-content-text", obj).toggle(); 609 div.removeClass("open").addClass("closed"); 610 $(".toggle-content-img", div).attr("title", "show").attr("src", toRoot + "assets/images/triangle-closed.png"); 611 }); 612 } 613 return false; 614} 615