• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 toRoot;
9var isMobile = false; // true if mobile, so we can adjust some layout
10
11
12/******  ON LOAD SET UP STUFF *********/
13
14var navBarIsFixed = false;
15$(document).ready(function() {
16  // init the fullscreen toggle click event
17  $('#nav-swap .fullscreen').click(function(){
18    if ($(this).hasClass('disabled')) {
19      toggleFullscreen(true);
20    } else {
21      toggleFullscreen(false);
22    }
23  });
24
25  // initialize the divs with custom scrollbars
26  $('.scroll-pane').jScrollPane( {verticalGutter:0} );
27
28  // add HRs below all H2s (except for a few other h2 variants)
29  $('h2').not('#qv h2').not('#tb h2').not('#devdoc-nav h2').css({marginBottom:0}).after('<hr/>');
30
31  // set search's onkeyup handler here so we can show suggestions
32  // even while search results are visible
33  $("#search_autocomplete").keyup(function() {return search_changed(event, false, '/')});
34
35  // set up the search close button
36  $('.search .close').click(function() {
37    $searchInput = $('#search_autocomplete');
38    $searchInput.attr('value', '');
39    $(this).addClass("hide");
40    $("#search-container").removeClass('active');
41    $("#search_autocomplete").blur();
42    search_focus_changed($searchInput.get(), false);  // see search_autocomplete.js
43    hideResults();  // see search_autocomplete.js
44  });
45  $('.search').click(function() {
46    if (!$('#search_autocomplete').is(":focused")) {
47        $('#search_autocomplete').focus();
48    }
49  });
50
51  // Set up quicknav
52  var quicknav_open = false;
53  $("#btn-quicknav").click(function() {
54    if (quicknav_open) {
55      $(this).removeClass('active');
56      quicknav_open = false;
57      collapse();
58    } else {
59      $(this).addClass('active');
60      quicknav_open = true;
61      expand();
62    }
63  })
64
65  var expand = function() {
66   $('#header-wrap').addClass('quicknav');
67   $('#quicknav').stop().show().animate({opacity:'1'});
68  }
69
70  var collapse = function() {
71    $('#quicknav').stop().animate({opacity:'0'}, 100, function() {
72      $(this).hide();
73      $('#header-wrap').removeClass('quicknav');
74    });
75  }
76
77
78  //Set up search
79  $("#search_autocomplete").focus(function() {
80    $("#search-container").addClass('active');
81  })
82  $("#search-container").mouseover(function() {
83    $("#search-container").addClass('active');
84    $("#search_autocomplete").focus();
85  })
86  $("#search-container").mouseout(function() {
87    if ($("#search_autocomplete").is(":focus")) return;
88    if ($("#search_autocomplete").val() == '') {
89      setTimeout(function(){
90        $("#search-container").removeClass('active');
91        $("#search_autocomplete").blur();
92      },250);
93    }
94  })
95  $("#search_autocomplete").blur(function() {
96    if ($("#search_autocomplete").val() == '') {
97      $("#search-container").removeClass('active');
98    }
99  })
100
101
102  // prep nav expandos
103  var pagePath = document.location.pathname;
104  // account for intl docs by removing the intl/*/ path
105  if (pagePath.indexOf("/intl/") == 0) {
106    pagePath = pagePath.substr(pagePath.indexOf("/",6)); // start after intl/ to get last /
107  }
108
109  if (pagePath.indexOf(SITE_ROOT) == 0) {
110    if (pagePath == '' || pagePath.charAt(pagePath.length - 1) == '/') {
111      pagePath += 'index.html';
112    }
113  }
114
115  if (SITE_ROOT.match(/\.\.\//) || SITE_ROOT == '') {
116    // If running locally, SITE_ROOT will be a relative path, so account for that by
117    // finding the relative URL to this page. This will allow us to find links on the page
118    // leading back to this page.
119    var pathParts = pagePath.split('/');
120    var relativePagePathParts = [];
121    var upDirs = (SITE_ROOT.match(/(\.\.\/)+/) || [''])[0].length / 3;
122    for (var i = 0; i < upDirs; i++) {
123      relativePagePathParts.push('..');
124    }
125    for (var i = 0; i < upDirs; i++) {
126      relativePagePathParts.push(pathParts[pathParts.length - (upDirs - i) - 1]);
127    }
128    relativePagePathParts.push(pathParts[pathParts.length - 1]);
129    pagePath = relativePagePathParts.join('/');
130  } else {
131    // Otherwise the page path is already an absolute URL
132  }
133
134  // select current page in sidenav and set up prev/next links if they exist
135  var $selNavLink = $('#nav').find('a[href="' + pagePath + '"]');
136  if ($selNavLink.length) {
137    $selListItem = $selNavLink.closest('li');
138
139    $selListItem.addClass('selected');
140    $selListItem.closest('li.nav-section').addClass('expanded');
141    $selListItem.closest('li.nav-section').children('ul').show();
142    $selListItem.closest('li.nav-section').parent().closest('li.nav-section').addClass('expanded');
143    $selListItem.closest('li.nav-section').parent().closest('ul').show();
144
145
146  //  $selListItem.closest('li.nav-section').closest('li.nav-section').addClass('expanded');
147  //  $selListItem.closest('li.nav-section').closest('li.nav-section').children('ul').show();
148
149    // set up prev links
150    var $prevLink = [];
151    var $prevListItem = $selListItem.prev('li');
152
153    var crossBoundaries = ($("body.design").length > 0) || ($("body.guide").length > 0) ? true :
154false; // navigate across topic boundaries only in design docs
155    if ($prevListItem.length) {
156      if ($prevListItem.hasClass('nav-section')) {
157        if (crossBoundaries) {
158          // jump to last topic of previous section
159          $prevLink = $prevListItem.find('a:last');
160        }
161      } else {
162        // jump to previous topic in this section
163        $prevLink = $prevListItem.find('a:eq(0)');
164      }
165    } else {
166      // jump to this section's index page (if it exists)
167      var $parentListItem = $selListItem.parents('li');
168      $prevLink = $selListItem.parents('li').find('a');
169
170      // except if cross boundaries aren't allowed, and we're at the top of a section already
171      // (and there's another parent)
172      if (!crossBoundaries && $parentListItem.hasClass('nav-section')
173                           && $selListItem.hasClass('nav-section')) {
174        $prevLink = [];
175      }
176    }
177
178    if ($prevLink.length) {
179      var prevHref = $prevLink.attr('href');
180      if (prevHref == SITE_ROOT + 'index.html') {
181        // Don't show Previous when it leads to the homepage
182      } else {
183        $('.prev-page-link').attr('href', $prevLink.attr('href')).removeClass("hide");
184      }
185    }
186
187    // set up next links
188    var $nextLink = [];
189    var startCourse = false;
190    var startClass = false;
191    var training = $(".next-class-link").length; // decides whether to provide "next class" link
192    var isCrossingBoundary = false;
193
194    if ($selListItem.hasClass('nav-section')) {
195      // we're on an index page, jump to the first topic
196      $nextLink = $selListItem.find('ul').find('a:eq(0)');
197
198      // if there aren't any children, go to the next section (required for About pages)
199      if($nextLink.length == 0) {
200        $nextLink = $selListItem.next('li').find('a');
201      }
202
203      // Handle some Training specialties
204      if ($selListItem.parent().is("#nav") && $(".start-course-link").length) {
205        // this means we're at the very top of the TOC hierarchy
206        startCourse = true;
207      } else if ($(".start-class-link").length) {
208        // this means this page has children but is not at the top (it's a class, not a course)
209        startClass = true;
210      }
211    } else {
212      // jump to the next topic in this section (if it exists)
213      $nextLink = $selListItem.next('li').find('a:eq(0)');
214      if (!$nextLink.length) {
215        if (crossBoundaries || training) {
216          // no more topics in this section, jump to the first topic in the next section
217          $nextLink = $selListItem.parents('li:eq(0)').next('li.nav-section').find('a:eq(0)');
218          isCrossingBoundary = true;
219        }
220      }
221    }
222    if ($nextLink.length) {
223      if (startCourse || startClass) {
224        if (startCourse) {
225          $('.start-course-link').attr('href', $nextLink.attr('href')).removeClass("hide");
226        } else {
227          $('.start-class-link').attr('href', $nextLink.attr('href')).removeClass("hide");
228        }
229        // if there's no training bar (below the start button),
230        // then we need to add a bottom border to button
231        if (!$("#tb").length) {
232          $('.start-course-link').css({'border-bottom':'1px solid #DADADA'});
233          $('.start-class-link').css({'border-bottom':'1px solid #DADADA'});
234        }
235      } else if (training && isCrossingBoundary) {
236        $('.content-footer.next-class').show();
237        $('.next-page-link').attr('href','')
238                            .removeClass("hide").addClass("disabled")
239                            .click(function() { return false; });
240
241        $('.next-class-link').attr('href',$nextLink.attr('href'))
242                            .removeClass("hide").append($nextLink.html());
243        $('.next-class-link').find('.new').empty();
244      } else {
245        $('.next-page-link').attr('href', $nextLink.attr('href')).removeClass("hide");
246      }
247    }
248
249  }
250
251
252
253  // Set up expand/collapse behavior
254  $('#nav li.nav-section .nav-section-header').click(function() {
255    var section = $(this).closest('li.nav-section');
256    if (section.hasClass('expanded')) {
257    /* hide me */
258    //  if (section.hasClass('selected') || section.find('li').hasClass('selected')) {
259   //   /* but not if myself or my descendents are selected */
260   //     return;
261    //  }
262      section.children('ul').slideUp(250, function() {
263        section.closest('li').removeClass('expanded');
264        resizeNav();
265      });
266    } else {
267    /* show me */
268      // first hide all other siblings
269      var $others = $('li.nav-section.expanded', $(this).closest('ul'));
270      $others.removeClass('expanded').children('ul').slideUp(250);
271
272      // now expand me
273      section.closest('li').addClass('expanded');
274      section.children('ul').slideDown(250, function() {
275        resizeNav();
276      });
277    }
278  });
279
280  $(".scroll-pane").scroll(function(event) {
281      event.preventDefault();
282      return false;
283  });
284
285  /* Resize nav height when window height changes */
286  $(window).resize(function() {
287    if ($('#side-nav').length == 0) return;
288    var stylesheet = $('link[rel="stylesheet"][class="fullscreen"]');
289    setNavBarLeftPos(); // do this even if sidenav isn't fixed because it could become fixed
290    // make sidenav behave when resizing the window and side-scolling is a concern
291    if (navBarIsFixed) {
292      if ((stylesheet.attr("disabled") == "disabled") || stylesheet.length == 0) {
293        updateSideNavPosition();
294      } else {
295        updateSidenavFullscreenWidth();
296      }
297    }
298    resizeNav();
299  });
300
301
302  // Set up fixed navbar
303  var prevScrollLeft = 0; // used to compare current position to previous position of horiz scroll
304  $(window).scroll(function(event) {
305    if ($('#side-nav').length == 0) return;
306    if (event.target.nodeName == "DIV") {
307      // Dump scroll event if the target is a DIV, because that means the event is coming
308      // from a scrollable div and so there's no need to make adjustments to our layout
309      return;
310    }
311    var scrollTop = $(window).scrollTop();
312    var headerHeight = $('#header').outerHeight();
313    var subheaderHeight = $('#nav-x').outerHeight();
314    var searchResultHeight = $('#searchResults').is(":visible") ?
315                             $('#searchResults').outerHeight() : 0;
316    var totalHeaderHeight = headerHeight + subheaderHeight + searchResultHeight;
317    var navBarShouldBeFixed = scrollTop > totalHeaderHeight;
318
319    var scrollLeft = $(window).scrollLeft();
320    // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match
321    if (navBarIsFixed && (scrollLeft != prevScrollLeft)) {
322      updateSideNavPosition();
323      prevScrollLeft = scrollLeft;
324    }
325
326    // Don't continue if the header is sufficently far away
327    // (to avoid intensive resizing that slows scrolling)
328    if (navBarIsFixed && navBarShouldBeFixed) {
329      return;
330    }
331
332    if (navBarIsFixed != navBarShouldBeFixed) {
333      if (navBarShouldBeFixed) {
334        // make it fixed
335        var width = $('#devdoc-nav').width();
336        $('#devdoc-nav')
337            .addClass('fixed')
338            .css({'width':width+'px'})
339            .prependTo('#body-content');
340        // add neato "back to top" button
341        $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'});
342
343        // update the sidenaav position for side scrolling
344        updateSideNavPosition();
345      } else {
346        // make it static again
347        $('#devdoc-nav')
348            .removeClass('fixed')
349            .css({'width':'auto','margin':''})
350            .prependTo('#side-nav');
351        $('#devdoc-nav a.totop').hide();
352      }
353      navBarIsFixed = navBarShouldBeFixed;
354    }
355
356    resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance
357  });
358
359
360  var navBarLeftPos;
361  if ($('#devdoc-nav').length) {
362    setNavBarLeftPos();
363  }
364
365
366  // Stop expand/collapse behavior when clicking on nav section links (since we're navigating away
367  // from the page)
368  $('.nav-section-header').find('a:eq(0)').click(function(evt) {
369    window.location.href = $(this).attr('href');
370    return false;
371  });
372
373  // Set up play-on-hover <video> tags.
374  $('video.play-on-hover').bind('click', function(){
375    $(this).get(0).load(); // in case the video isn't seekable
376    $(this).get(0).play();
377  });
378
379  // Set up tooltips
380  var TOOLTIP_MARGIN = 10;
381  $('acronym').each(function() {
382    var $target = $(this);
383    var $tooltip = $('<div>')
384        .addClass('tooltip-box')
385        .text($target.attr('title'))
386        .hide()
387        .appendTo('body');
388    $target.removeAttr('title');
389
390    $target.hover(function() {
391      // in
392      var targetRect = $target.offset();
393      targetRect.width = $target.width();
394      targetRect.height = $target.height();
395
396      $tooltip.css({
397        left: targetRect.left,
398        top: targetRect.top + targetRect.height + TOOLTIP_MARGIN
399      });
400      $tooltip.addClass('below');
401      $tooltip.show();
402    }, function() {
403      // out
404      $tooltip.hide();
405    });
406  });
407
408  // Set up <h2> deeplinks
409  $('h2').click(function() {
410    var id = $(this).attr('id');
411    if (id) {
412      document.location.hash = id;
413    }
414  });
415
416  //Loads the +1 button
417  var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
418  po.src = 'https://apis.google.com/js/plusone.js';
419  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
420
421
422  // Revise the sidenav widths to make room for the scrollbar
423  // which avoids the visible width from changing each time the bar appears
424  var $sidenav = $("#side-nav");
425  var sidenav_width = parseInt($sidenav.innerWidth());
426
427  $("#devdoc-nav  #nav").css("width", sidenav_width - 4 + "px"); // 4px is scrollbar width
428
429
430  $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller
431
432  if ($(".scroll-pane").length > 1) {
433    // Check if there's a user preference for the panel heights
434    var cookieHeight = readCookie("reference_height");
435    if (cookieHeight) {
436      restoreHeight(cookieHeight);
437    }
438  }
439
440  resizeNav();
441
442
443});
444
445
446
447function toggleFullscreen(enable) {
448  var delay = 20;
449  var enabled = true;
450  var stylesheet = $('link[rel="stylesheet"][class="fullscreen"]');
451  if (enable) {
452    // Currently NOT USING fullscreen; enable fullscreen
453    stylesheet.removeAttr('disabled');
454    $('#nav-swap .fullscreen').removeClass('disabled');
455    $('#devdoc-nav').css({left:''});
456    setTimeout(updateSidenavFullscreenWidth,delay); // need to wait a moment for css to switch
457    enabled = true;
458  } else {
459    // Currently USING fullscreen; disable fullscreen
460    stylesheet.attr('disabled', 'disabled');
461    $('#nav-swap .fullscreen').addClass('disabled');
462    setTimeout(updateSidenavFixedWidth,delay); // need to wait a moment for css to switch
463    enabled = false;
464  }
465  writeCookie("fullscreen", enabled, null, null);
466  setNavBarLeftPos();
467  resizeNav(delay);
468  updateSideNavPosition();
469  setTimeout(initSidenavHeightResize,delay);
470}
471
472
473function setNavBarLeftPos() {
474  navBarLeftPos = $('#body-content').offset().left;
475}
476
477
478function updateSideNavPosition() {
479  var newLeft = $(window).scrollLeft() - navBarLeftPos;
480  $('#devdoc-nav').css({left: -newLeft});
481  $('#devdoc-nav .totop').css({left: -(newLeft - parseInt($('#side-nav').css('margin-left')))});
482}
483
484
485
486
487
488
489
490
491// TODO: use $(document).ready instead
492function addLoadEvent(newfun) {
493  var current = window.onload;
494  if (typeof window.onload != 'function') {
495    window.onload = newfun;
496  } else {
497    window.onload = function() {
498      current();
499      newfun();
500    }
501  }
502}
503
504var agent = navigator['userAgent'].toLowerCase();
505// If a mobile phone, set flag and do mobile setup
506if ((agent.indexOf("mobile") != -1) ||      // android, iphone, ipod
507    (agent.indexOf("blackberry") != -1) ||
508    (agent.indexOf("webos") != -1) ||
509    (agent.indexOf("mini") != -1)) {        // opera mini browsers
510  isMobile = true;
511}
512
513
514/* loads the lists.js file to the page.
515Loading this in the head was slowing page load time */
516addLoadEvent( function() {
517  var lists = document.createElement("script");
518  lists.setAttribute("type","text/javascript");
519  lists.setAttribute("src", toRoot+"reference/lists.js");
520  document.getElementsByTagName("head")[0].appendChild(lists);
521} );
522
523
524addLoadEvent( function() {
525  $("pre:not(.no-pretty-print)").addClass("prettyprint");
526  prettyPrint();
527} );
528
529function setToRoot(root) {
530  toRoot = root;
531  // note: toRoot also used by carousel.js
532}
533
534function init() {
535  //resizeNav();
536
537  resizePackagesNav = $("#resize-packages-nav");
538  classesNav = $("#classes-nav");
539  devdocNav = $("#devdoc-nav");
540
541  var cookiePath = "";
542  if (location.href.indexOf("/reference/") != -1) {
543    cookiePath = "reference_";
544  } else if (location.href.indexOf("/guide/") != -1) {
545    cookiePath = "guide_";
546  } else if (location.href.indexOf("/tools/") != -1) {
547    cookiePath = "tools_";
548  } else if (location.href.indexOf("/training/") != -1) {
549    cookiePath = "training_";
550  } else if (location.href.indexOf("/design/") != -1) {
551    cookiePath = "design_";
552  } else if (location.href.indexOf("/distribute/") != -1) {
553    cookiePath = "distribute_";
554  }
555}
556
557
558
559/* ######### RESIZE THE SIDENAV HEIGHT ########## */
560
561function resizeNav(delay) {
562  var $nav = $("#devdoc-nav");
563  var $window = $(window);
564  var navHeight;
565
566  // Get the height of entire window and the total header height.
567  // Then figure out based on scroll position whether the header is visible
568  var windowHeight = $window.height();
569  var scrollTop = $window.scrollTop();
570  var headerHeight = $('#header').outerHeight();
571  var subheaderHeight = $('#nav-x').outerHeight();
572  var headerVisible = (scrollTop < (headerHeight + subheaderHeight));
573
574  // get the height of space between nav and top of window.
575  // Could be either margin or top position, depending on whether the nav is fixed.
576  var topMargin = (parseInt($nav.css('margin-top')) || parseInt($nav.css('top'))) + 1;
577  // add 1 for the #side-nav bottom margin
578
579  // Depending on whether the header is visible, set the side nav's height.
580  if (headerVisible) {
581    // The sidenav height grows as the header goes off screen
582    navHeight = windowHeight - (headerHeight + subheaderHeight - scrollTop) - topMargin;
583  } else {
584    // Once header is off screen, the nav height is almost full window height
585    navHeight = windowHeight - topMargin;
586  }
587
588
589
590  $scrollPanes = $(".scroll-pane");
591  if ($scrollPanes.length > 1) {
592    // subtract the height of the api level widget and nav swapper from the available nav height
593    navHeight -= ($('#api-nav-header').outerHeight(true) + $('#nav-swap').outerHeight(true));
594
595    $("#swapper").css({height:navHeight + "px"});
596    if ($("#nav-tree").is(":visible")) {
597      $("#nav-tree").css({height:navHeight});
598    }
599
600    var classesHeight = navHeight - parseInt($("#resize-packages-nav").css("height")) - 10 + "px";
601    //subtract 10px to account for drag bar
602
603    // if the window becomes small enough to make the class panel height 0,
604    // then the package panel should begin to shrink
605    if (parseInt(classesHeight) <= 0) {
606      $("#resize-packages-nav").css({height:navHeight - 10}); //subtract 10px for drag bar
607      $("#packages-nav").css({height:navHeight - 10});
608    }
609
610    $("#classes-nav").css({'height':classesHeight, 'margin-top':'10px'});
611    $("#classes-nav .jspContainer").css({height:classesHeight});
612
613
614  } else {
615    $nav.height(navHeight);
616  }
617
618  if (delay) {
619    updateFromResize = true;
620    delayedReInitScrollbars(delay);
621  } else {
622    reInitScrollbars();
623  }
624
625}
626
627var updateScrollbars = false;
628var updateFromResize = false;
629
630/* Re-initialize the scrollbars to account for changed nav size.
631 * This method postpones the actual update by a 1/4 second in order to optimize the
632 * scroll performance while the header is still visible, because re-initializing the
633 * scroll panes is an intensive process.
634 */
635function delayedReInitScrollbars(delay) {
636  // If we're scheduled for an update, but have received another resize request
637  // before the scheduled resize has occured, just ignore the new request
638  // (and wait for the scheduled one).
639  if (updateScrollbars && updateFromResize) {
640    updateFromResize = false;
641    return;
642  }
643
644  // We're scheduled for an update and the update request came from this method's setTimeout
645  if (updateScrollbars && !updateFromResize) {
646    reInitScrollbars();
647    updateScrollbars = false;
648  } else {
649    updateScrollbars = true;
650    updateFromResize = false;
651    setTimeout('delayedReInitScrollbars()',delay);
652  }
653}
654
655/* Re-initialize the scrollbars to account for changed nav size. */
656function reInitScrollbars() {
657  var pane = $(".scroll-pane").each(function(){
658    var api = $(this).data('jsp');
659    if (!api) { setTimeout(reInitScrollbars,300); return;}
660    api.reinitialise( {verticalGutter:0} );
661  });
662  $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller
663}
664
665
666/* Resize the height of the nav panels in the reference,
667 * and save the new size to a cookie */
668function saveNavPanels() {
669  var basePath = getBaseUri(location.pathname);
670  var section = basePath.substring(1,basePath.indexOf("/",1));
671  writeCookie("height", resizePackagesNav.css("height"), section, null);
672}
673
674
675
676function restoreHeight(packageHeight) {
677    $("#resize-packages-nav").height(packageHeight);
678    $("#packages-nav").height(packageHeight);
679  //  var classesHeight = navHeight - packageHeight;
680 //   $("#classes-nav").css({height:classesHeight});
681  //  $("#classes-nav .jspContainer").css({height:classesHeight});
682}
683
684
685
686/* ######### END RESIZE THE SIDENAV HEIGHT ########## */
687
688
689
690
691
692/** Scroll the jScrollPane to make the currently selected item visible
693    This is called when the page finished loading. */
694function scrollIntoView(nav) {
695  var $nav = $("#"+nav);
696  var element = $nav.jScrollPane({/* ...settings... */});
697  var api = element.data('jsp');
698
699  if ($nav.is(':visible')) {
700    var $selected = $(".selected", $nav);
701    if ($selected.length == 0) return;
702
703    var selectedOffset = $selected.position().top;
704    if (selectedOffset + 90 > $nav.height()) {  // add 90 so that we scroll up even
705                                                // if the current item is close to the bottom
706      api.scrollTo(0, selectedOffset - ($nav.height() / 4), false); // scroll the item into view
707                                                              // to be 1/4 of the way from the top
708    }
709  }
710}
711
712
713
714
715
716
717/* Show popup dialogs */
718function showDialog(id) {
719  $dialog = $("#"+id);
720  $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>');
721  $dialog.wrapInner('<div/>');
722  $dialog.removeClass("hide");
723}
724
725
726
727
728
729/* #########    COOKIES!     ########## */
730
731function readCookie(cookie) {
732  var myCookie = cookie_namespace+"_"+cookie+"=";
733  if (document.cookie) {
734    var index = document.cookie.indexOf(myCookie);
735    if (index != -1) {
736      var valStart = index + myCookie.length;
737      var valEnd = document.cookie.indexOf(";", valStart);
738      if (valEnd == -1) {
739        valEnd = document.cookie.length;
740      }
741      var val = document.cookie.substring(valStart, valEnd);
742      return val;
743    }
744  }
745  return 0;
746}
747
748function writeCookie(cookie, val, section, expiration) {
749  if (val==undefined) return;
750  section = section == null ? "_" : "_"+section+"_";
751  if (expiration == null) {
752    var date = new Date();
753    date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week
754    expiration = date.toGMTString();
755  }
756  var cookieValue = cookie_namespace + section + cookie + "=" + val
757                    + "; expires=" + expiration+"; path=/";
758  document.cookie = cookieValue;
759}
760
761/* #########     END COOKIES!     ########## */
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787/*
788
789REMEMBER THE PREVIOUS PAGE FOR EACH TAB
790
791function loadLast(cookiePath) {
792  var location = window.location.href;
793  if (location.indexOf("/"+cookiePath+"/") != -1) {
794    return true;
795  }
796  var lastPage = readCookie(cookiePath + "_lastpage");
797  if (lastPage) {
798    window.location = lastPage;
799    return false;
800  }
801  return true;
802}
803
804
805
806$(window).unload(function(){
807  var path = getBaseUri(location.pathname);
808  if (path.indexOf("/reference/") != -1) {
809    writeCookie("lastpage", path, "reference", null);
810  } else if (path.indexOf("/guide/") != -1) {
811    writeCookie("lastpage", path, "guide", null);
812  } else if ((path.indexOf("/resources/") != -1) || (path.indexOf("/training/") != -1)) {
813    writeCookie("lastpage", path, "resources", null);
814  }
815});
816
817*/
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832function toggle(obj, slide) {
833  var ul = $("ul:first", obj);
834  var li = ul.parent();
835  if (li.hasClass("closed")) {
836    if (slide) {
837      ul.slideDown("fast");
838    } else {
839      ul.show();
840    }
841    li.removeClass("closed");
842    li.addClass("open");
843    $(".toggle-img", li).attr("title", "hide pages");
844  } else {
845    ul.slideUp("fast");
846    li.removeClass("open");
847    li.addClass("closed");
848    $(".toggle-img", li).attr("title", "show pages");
849  }
850}
851
852
853
854
855
856function buildToggleLists() {
857  $(".toggle-list").each(
858    function(i) {
859      $("div:first", this).append("<a class='toggle-img' href='#' title='show pages' onClick='toggle(this.parentNode.parentNode, true); return false;'></a>");
860      $(this).addClass("closed");
861    });
862}
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895/*      REFERENCE NAV SWAP     */
896
897
898function getNavPref() {
899  var v = readCookie('reference_nav');
900  if (v != NAV_PREF_TREE) {
901    v = NAV_PREF_PANELS;
902  }
903  return v;
904}
905
906function chooseDefaultNav() {
907  nav_pref = getNavPref();
908  if (nav_pref == NAV_PREF_TREE) {
909    $("#nav-panels").toggle();
910    $("#panel-link").toggle();
911    $("#nav-tree").toggle();
912    $("#tree-link").toggle();
913  }
914}
915
916function swapNav() {
917  if (nav_pref == NAV_PREF_TREE) {
918    nav_pref = NAV_PREF_PANELS;
919  } else {
920    nav_pref = NAV_PREF_TREE;
921    init_default_navtree(toRoot);
922  }
923  var date = new Date();
924  date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
925  writeCookie("nav", nav_pref, "reference", date.toGMTString());
926
927  $("#nav-panels").toggle();
928  $("#panel-link").toggle();
929  $("#nav-tree").toggle();
930  $("#tree-link").toggle();
931
932  resizeNav();
933
934  // Gross nasty hack to make tree view show up upon first swap by setting height manually
935  $("#nav-tree .jspContainer:visible")
936      .css({'height':$("#nav-tree .jspContainer .jspPane").height() +'px'});
937  // Another nasty hack to make the scrollbar appear now that we have height
938  resizeNav();
939
940  if ($("#nav-tree").is(':visible')) {
941    scrollIntoView("nav-tree");
942  } else {
943    scrollIntoView("packages-nav");
944    scrollIntoView("classes-nav");
945  }
946}
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972/* ##########     LOCALIZATION     ############ */
973
974function getBaseUri(uri) {
975  var intlUrl = (uri.substring(0,6) == "/intl/");
976  if (intlUrl) {
977    base = uri.substring(uri.indexOf('intl/')+5,uri.length);
978    base = base.substring(base.indexOf('/')+1, base.length);
979      //alert("intl, returning base url: /" + base);
980    return ("/" + base);
981  } else {
982      //alert("not intl, returning uri as found.");
983    return uri;
984  }
985}
986
987function requestAppendHL(uri) {
988//append "?hl=<lang> to an outgoing request (such as to blog)
989  var lang = getLangPref();
990  if (lang) {
991    var q = 'hl=' + lang;
992    uri += '?' + q;
993    window.location = uri;
994    return false;
995  } else {
996    return true;
997  }
998}
999
1000
1001function changeTabLang(lang) {
1002  var nodes = $("#header-tabs").find("."+lang);
1003  for (i=0; i < nodes.length; i++) { // for each node in this language
1004    var node = $(nodes[i]);
1005    node.siblings().css("display","none"); // hide all siblings
1006    if (node.not(":empty").length != 0) { //if this languages node has a translation, show it
1007      node.css("display","inline");
1008    } else { //otherwise, show English instead
1009      node.css("display","none");
1010      node.siblings().filter(".en").css("display","inline");
1011    }
1012  }
1013}
1014
1015function changeNavLang(lang) {
1016  var nodes = $("#devdoc-nav").find("."+lang);
1017  for (i=0; i < nodes.length; i++) { // for each node in this language
1018    var node = $(nodes[i]);
1019    node.siblings().css("display","none"); // hide all siblings
1020    if (node.not(":empty").length != 0) { // if this languages node has a translation, show it
1021      node.css("display","inline");
1022    } else { // otherwise, show English instead
1023      node.css("display","none");
1024      node.siblings().filter(".en").css("display","inline");
1025    }
1026  }
1027}
1028
1029function changeDocLang(lang) {
1030  changeTabLang(lang);
1031  changeNavLang(lang);
1032}
1033
1034function changeLangPref(lang, refresh) {
1035  var date = new Date();
1036  expires = date.toGMTString(date.setTime(date.getTime()+(10*365*24*60*60*1000)));
1037  // keep this for 50 years
1038  //alert("expires: " + expires)
1039  writeCookie("pref_lang", lang, null, expires);
1040  changeDocLang(lang);
1041  if (refresh) {
1042    l = getBaseUri(location.pathname);
1043    window.location = l;
1044  }
1045}
1046
1047function loadLangPref() {
1048  var lang = readCookie("pref_lang");
1049  if (lang != 0) {
1050    $("#language").find("option[value='"+lang+"']").attr("selected",true);
1051  }
1052}
1053
1054function getLangPref() {
1055  var lang = $("#language").find(":selected").attr("value");
1056  if (!lang) {
1057    lang = readCookie("pref_lang");
1058  }
1059  return (lang != 0) ? lang : 'en';
1060}
1061
1062/* ##########     END LOCALIZATION     ############ */
1063
1064
1065
1066
1067
1068
1069/* Used to hide and reveal supplemental content, such as long code samples.
1070   See the companion CSS in android-developer-docs.css */
1071function toggleContent(obj) {
1072  var div = $(obj.parentNode.parentNode);
1073  var toggleMe = $(".toggle-content-toggleme",div);
1074  if (div.hasClass("closed")) { // if it's closed, open it
1075    toggleMe.slideDown();
1076    $(".toggle-content-text", obj).toggle();
1077    div.removeClass("closed").addClass("open");
1078    $(".toggle-content-img", div).attr("title", "hide").attr("src", toRoot
1079                  + "assets/images/triangle-opened.png");
1080  } else { // if it's open, close it
1081    toggleMe.slideUp('fast', function() {  // Wait until the animation is done before closing arrow
1082      $(".toggle-content-text", obj).toggle();
1083      div.removeClass("open").addClass("closed");
1084      $(".toggle-content-img", div).attr("title", "show").attr("src", toRoot
1085                  + "assets/images/triangle-closed.png");
1086    });
1087  }
1088  return false;
1089}
1090