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