blob: 1b878b31be6a702bd290ea1ed8fb8a692530c658 [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
Scott Mainf6145542013-04-01 16:38:11 -07009var mPagePath; // initialized in ready() function
Scott Maine4d8f1b2012-06-21 18:03:05 -070010
Scott Main1b3db112012-07-03 14:06:22 -070011var basePath = getBaseUri(location.pathname);
12var SITE_ROOT = toRoot + basePath.substring(1,basePath.indexOf("/",1));
Scott Main7e447ed2013-02-19 17:22:37 -080013var GOOGLE_DATA; // combined data for google service apis, used for search suggest
Scott Main1b3db112012-07-03 14:06:22 -070014
Scott Main25e73002013-03-27 15:24:06 -070015// Ensure that all ajax getScript() requests allow caching
16$.ajaxSetup({
17 cache: true
18});
Scott Maine4d8f1b2012-06-21 18:03:05 -070019
20/****** ON LOAD SET UP STUFF *********/
21
22var navBarIsFixed = false;
23$(document).ready(function() {
Scott Main7e447ed2013-02-19 17:22:37 -080024
25 // load json file for Android API search suggestions
26 $.getScript(toRoot + 'reference/lists.js');
27 // load json files for Google services API suggestions
Scott Main9f2971d2013-02-26 13:07:41 -080028 $.getScript(toRoot + 'reference/gcm_lists.js', function(data, textStatus, jqxhr) {
Scott Main7e447ed2013-02-19 17:22:37 -080029 // once the GCM json (GCM_DATA) is loaded, load the GMS json (GMS_DATA) and merge the data
30 if(jqxhr.status === 200) {
Scott Main9f2971d2013-02-26 13:07:41 -080031 $.getScript(toRoot + 'reference/gms_lists.js', function(data, textStatus, jqxhr) {
Scott Main7e447ed2013-02-19 17:22:37 -080032 if(jqxhr.status === 200) {
33 // combine GCM and GMS data
34 GOOGLE_DATA = GMS_DATA;
35 var start = GOOGLE_DATA.length;
36 for (var i=0; i<GCM_DATA.length; i++) {
37 GOOGLE_DATA.push({id:start+i, label:GCM_DATA[i].label,
38 link:GCM_DATA[i].link, type:GCM_DATA[i].type});
39 }
40 }
41 });
42 }
43 });
44
45 // layout hosted on devsite is special
Scott Main015d6162013-01-29 09:01:52 -080046 if (devsite) {
47 // move the lang selector into the overflow menu
48 $("#moremenu .mid div.header:last").after($("#language").detach());
49 }
50
Scott Maine4d8f1b2012-06-21 18:03:05 -070051 // init the fullscreen toggle click event
52 $('#nav-swap .fullscreen').click(function(){
53 if ($(this).hasClass('disabled')) {
54 toggleFullscreen(true);
55 } else {
56 toggleFullscreen(false);
57 }
58 });
59
60 // initialize the divs with custom scrollbars
61 $('.scroll-pane').jScrollPane( {verticalGutter:0} );
62
63 // add HRs below all H2s (except for a few other h2 variants)
Scott Maindb3678b2012-10-23 14:13:41 -070064 $('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 -070065
66 // set search's onkeyup handler here so we can show suggestions
67 // even while search results are visible
Scott Main1b3db112012-07-03 14:06:22 -070068 $("#search_autocomplete").keyup(function() {return search_changed(event, false, toRoot)});
Scott Maine4d8f1b2012-06-21 18:03:05 -070069
70 // set up the search close button
71 $('.search .close').click(function() {
72 $searchInput = $('#search_autocomplete');
73 $searchInput.attr('value', '');
74 $(this).addClass("hide");
75 $("#search-container").removeClass('active');
76 $("#search_autocomplete").blur();
77 search_focus_changed($searchInput.get(), false); // see search_autocomplete.js
78 hideResults(); // see search_autocomplete.js
79 });
80 $('.search').click(function() {
Scott Main7e447ed2013-02-19 17:22:37 -080081 if (!$('#search_autocomplete').is(":focus")) {
Scott Maine4d8f1b2012-06-21 18:03:05 -070082 $('#search_autocomplete').focus();
83 }
84 });
85
86 // Set up quicknav
87 var quicknav_open = false;
88 $("#btn-quicknav").click(function() {
89 if (quicknav_open) {
90 $(this).removeClass('active');
91 quicknav_open = false;
92 collapse();
93 } else {
94 $(this).addClass('active');
95 quicknav_open = true;
96 expand();
97 }
98 })
99
100 var expand = function() {
101 $('#header-wrap').addClass('quicknav');
102 $('#quicknav').stop().show().animate({opacity:'1'});
103 }
104
105 var collapse = function() {
106 $('#quicknav').stop().animate({opacity:'0'}, 100, function() {
107 $(this).hide();
108 $('#header-wrap').removeClass('quicknav');
109 });
110 }
111
112
113 //Set up search
114 $("#search_autocomplete").focus(function() {
115 $("#search-container").addClass('active');
116 })
117 $("#search-container").mouseover(function() {
118 $("#search-container").addClass('active');
119 $("#search_autocomplete").focus();
120 })
121 $("#search-container").mouseout(function() {
122 if ($("#search_autocomplete").is(":focus")) return;
123 if ($("#search_autocomplete").val() == '') {
124 setTimeout(function(){
125 $("#search-container").removeClass('active');
126 $("#search_autocomplete").blur();
127 },250);
128 }
129 })
130 $("#search_autocomplete").blur(function() {
131 if ($("#search_autocomplete").val() == '') {
132 $("#search-container").removeClass('active');
133 }
134 })
135
136
137 // prep nav expandos
138 var pagePath = document.location.pathname;
139 // account for intl docs by removing the intl/*/ path
140 if (pagePath.indexOf("/intl/") == 0) {
141 pagePath = pagePath.substr(pagePath.indexOf("/",6)); // start after intl/ to get last /
142 }
Scott Mainac2aef52013-02-12 14:15:23 -0800143
Scott Maine4d8f1b2012-06-21 18:03:05 -0700144 if (pagePath.indexOf(SITE_ROOT) == 0) {
145 if (pagePath == '' || pagePath.charAt(pagePath.length - 1) == '/') {
146 pagePath += 'index.html';
147 }
148 }
149
Scott Main01a25452013-02-12 17:32:27 -0800150 // Need a copy of the pagePath before it gets changed in the next block;
151 // it's needed to perform proper tab highlighting in offline docs (see rootDir below)
152 var pagePathOriginal = pagePath;
Scott Maine4d8f1b2012-06-21 18:03:05 -0700153 if (SITE_ROOT.match(/\.\.\//) || SITE_ROOT == '') {
154 // If running locally, SITE_ROOT will be a relative path, so account for that by
155 // finding the relative URL to this page. This will allow us to find links on the page
156 // leading back to this page.
157 var pathParts = pagePath.split('/');
158 var relativePagePathParts = [];
159 var upDirs = (SITE_ROOT.match(/(\.\.\/)+/) || [''])[0].length / 3;
160 for (var i = 0; i < upDirs; i++) {
161 relativePagePathParts.push('..');
162 }
163 for (var i = 0; i < upDirs; i++) {
164 relativePagePathParts.push(pathParts[pathParts.length - (upDirs - i) - 1]);
165 }
166 relativePagePathParts.push(pathParts[pathParts.length - 1]);
167 pagePath = relativePagePathParts.join('/');
168 } else {
169 // Otherwise the page path is already an absolute URL
170 }
171
Scott Mainac2aef52013-02-12 14:15:23 -0800172 // Highlight the header tabs...
173 // highlight Design tab
174 if ($("body").hasClass("design")) {
175 $("#header li.design a").addClass("selected");
176
177 // highlight Develop tab
178 } else if ($("body").hasClass("develop") || $("body").hasClass("google")) {
179 $("#header li.develop a").addClass("selected");
Scott Mainac2aef52013-02-12 14:15:23 -0800180 // In Develop docs, also highlight appropriate sub-tab
Scott Main01a25452013-02-12 17:32:27 -0800181 var rootDir = pagePathOriginal.substring(1,pagePathOriginal.indexOf('/', 1));
Scott Mainac2aef52013-02-12 14:15:23 -0800182 if (rootDir == "training") {
183 $("#nav-x li.training a").addClass("selected");
184 } else if (rootDir == "guide") {
185 $("#nav-x li.guide a").addClass("selected");
186 } else if (rootDir == "reference") {
187 // If the root is reference, but page is also part of Google Services, select Google
188 if ($("body").hasClass("google")) {
189 $("#nav-x li.google a").addClass("selected");
190 } else {
191 $("#nav-x li.reference a").addClass("selected");
192 }
193 } else if ((rootDir == "tools") || (rootDir == "sdk")) {
194 $("#nav-x li.tools a").addClass("selected");
195 } else if ($("body").hasClass("google")) {
196 $("#nav-x li.google a").addClass("selected");
197 }
198
199 // highlight Distribute tab
200 } else if ($("body").hasClass("distribute")) {
201 $("#header li.distribute a").addClass("selected");
202 }
203
Scott Mainf6145542013-04-01 16:38:11 -0700204 // set global variable so we can highlight the sidenav a bit later (such as for google reference)
205 // and highlight the sidenav
206 mPagePath = pagePath;
207 highlightSidenav();
Scott Mainac2aef52013-02-12 14:15:23 -0800208
Scott Mainf6145542013-04-01 16:38:11 -0700209 // set up prev/next links if they exist
Scott Maine4d8f1b2012-06-21 18:03:05 -0700210 var $selNavLink = $('#nav').find('a[href="' + pagePath + '"]');
Scott Main5a1123e2012-09-26 12:51:28 -0700211 var $selListItem;
Scott Maine4d8f1b2012-06-21 18:03:05 -0700212 if ($selNavLink.length) {
Scott Mainac2aef52013-02-12 14:15:23 -0800213 $selListItem = $selNavLink.closest('li');
Scott Maine4d8f1b2012-06-21 18:03:05 -0700214
215 // set up prev links
216 var $prevLink = [];
217 var $prevListItem = $selListItem.prev('li');
218
219 var crossBoundaries = ($("body.design").length > 0) || ($("body.guide").length > 0) ? true :
220false; // navigate across topic boundaries only in design docs
221 if ($prevListItem.length) {
222 if ($prevListItem.hasClass('nav-section')) {
Scott Main5a1123e2012-09-26 12:51:28 -0700223 // jump to last topic of previous section
224 $prevLink = $prevListItem.find('a:last');
225 } else if (!$selListItem.hasClass('nav-section')) {
Scott Maine4d8f1b2012-06-21 18:03:05 -0700226 // jump to previous topic in this section
227 $prevLink = $prevListItem.find('a:eq(0)');
228 }
229 } else {
230 // jump to this section's index page (if it exists)
231 var $parentListItem = $selListItem.parents('li');
232 $prevLink = $selListItem.parents('li').find('a');
233
234 // except if cross boundaries aren't allowed, and we're at the top of a section already
235 // (and there's another parent)
236 if (!crossBoundaries && $parentListItem.hasClass('nav-section')
237 && $selListItem.hasClass('nav-section')) {
238 $prevLink = [];
239 }
240 }
241
Scott Maine4d8f1b2012-06-21 18:03:05 -0700242 // set up next links
243 var $nextLink = [];
Scott Maine4d8f1b2012-06-21 18:03:05 -0700244 var startClass = false;
245 var training = $(".next-class-link").length; // decides whether to provide "next class" link
246 var isCrossingBoundary = false;
247
248 if ($selListItem.hasClass('nav-section')) {
249 // we're on an index page, jump to the first topic
Scott Mainb505ca62012-07-26 18:00:14 -0700250 $nextLink = $selListItem.find('ul:eq(0)').find('a:eq(0)');
Scott Maine4d8f1b2012-06-21 18:03:05 -0700251
252 // if there aren't any children, go to the next section (required for About pages)
253 if($nextLink.length == 0) {
254 $nextLink = $selListItem.next('li').find('a');
Scott Mainb505ca62012-07-26 18:00:14 -0700255 } else if ($('.topic-start-link').length) {
256 // as long as there's a child link and there is a "topic start link" (we're on a landing)
257 // then set the landing page "start link" text to be the first doc title
258 $('.topic-start-link').text($nextLink.text().toUpperCase());
Scott Maine4d8f1b2012-06-21 18:03:05 -0700259 }
260
Scott Main5a1123e2012-09-26 12:51:28 -0700261 // If the selected page has a description, then it's a class or article homepage
262 if ($selListItem.find('a[description]').length) {
263 // this means we're on a class landing page
Scott Maine4d8f1b2012-06-21 18:03:05 -0700264 startClass = true;
265 }
266 } else {
267 // jump to the next topic in this section (if it exists)
268 $nextLink = $selListItem.next('li').find('a:eq(0)');
269 if (!$nextLink.length) {
Scott Main5a1123e2012-09-26 12:51:28 -0700270 isCrossingBoundary = true;
271 // no more topics in this section, jump to the first topic in the next section
272 $nextLink = $selListItem.parents('li:eq(0)').next('li.nav-section').find('a:eq(0)');
273 if (!$nextLink.length) { // Go up another layer to look for next page (lesson > class > course)
274 $nextLink = $selListItem.parents('li:eq(1)').next('li.nav-section').find('a:eq(0)');
Scott Maine4d8f1b2012-06-21 18:03:05 -0700275 }
276 }
277 }
Scott Main5a1123e2012-09-26 12:51:28 -0700278
279 if (startClass) {
280 $('.start-class-link').attr('href', $nextLink.attr('href')).removeClass("hide");
281
282 // if there's no training bar (below the start button),
283 // then we need to add a bottom border to button
284 if (!$("#tb").length) {
285 $('.start-class-link').css({'border-bottom':'1px solid #DADADA'});
Scott Maine4d8f1b2012-06-21 18:03:05 -0700286 }
Scott Main5a1123e2012-09-26 12:51:28 -0700287 } else if (isCrossingBoundary && !$('body.design').length) { // Design always crosses boundaries
288 $('.content-footer.next-class').show();
289 $('.next-page-link').attr('href','')
290 .removeClass("hide").addClass("disabled")
291 .click(function() { return false; });
292
293 $('.next-class-link').attr('href',$nextLink.attr('href'))
294 .removeClass("hide").append($nextLink.html());
295 $('.next-class-link').find('.new').empty();
296 } else {
297 $('.next-page-link').attr('href', $nextLink.attr('href')).removeClass("hide");
298 }
299
300 if (!startClass && $prevLink.length) {
301 var prevHref = $prevLink.attr('href');
302 if (prevHref == SITE_ROOT + 'index.html') {
303 // Don't show Previous when it leads to the homepage
304 } else {
305 $('.prev-page-link').attr('href', $prevLink.attr('href')).removeClass("hide");
306 }
307 }
308
309 // If this is a training 'article', there should be no prev/next nav
310 // ... if the grandparent is the "nav" ... and it has no child list items...
311 if (training && $selListItem.parents('ul').eq(1).is('[id="nav"]') &&
312 !$selListItem.find('li').length) {
313 $('.next-page-link,.prev-page-link').attr('href','').addClass("disabled")
314 .click(function() { return false; });
Scott Maine4d8f1b2012-06-21 18:03:05 -0700315 }
316
317 }
Scott Main5a1123e2012-09-26 12:51:28 -0700318
319
320
321 // Set up the course landing pages for Training with class names and descriptions
322 if ($('body.trainingcourse').length) {
323 var $classLinks = $selListItem.find('ul li a').not('#nav .nav-section .nav-section ul a');
324 var $classDescriptions = $classLinks.attr('description');
325
326 var $olClasses = $('<ol class="class-list"></ol>');
327 var $liClass;
328 var $imgIcon;
329 var $h2Title;
330 var $pSummary;
331 var $olLessons;
332 var $liLesson;
333 $classLinks.each(function(index) {
334 $liClass = $('<li></li>');
335 $h2Title = $('<a class="title" href="'+$(this).attr('href')+'"><h2>' + $(this).html()+'</h2><span></span></a>');
336 $pSummary = $('<p class="description">' + $(this).attr('description') + '</p>');
337
338 $olLessons = $('<ol class="lesson-list"></ol>');
339
340 $lessons = $(this).closest('li').find('ul li a');
341
342 if ($lessons.length) {
343 $imgIcon = $('<img src="'+toRoot+'assets/images/resource-tutorial.png" alt=""/>');
344 $lessons.each(function(index) {
345 $olLessons.append('<li><a href="'+$(this).attr('href')+'">' + $(this).html()+'</a></li>');
346 });
347 } else {
348 $imgIcon = $('<img src="'+toRoot+'assets/images/resource-article.png" alt=""/>');
349 $pSummary.addClass('article');
350 }
351
352 $liClass.append($h2Title).append($imgIcon).append($pSummary).append($olLessons);
353 $olClasses.append($liClass);
354 });
355 $('.jd-descr').append($olClasses);
356 }
357
Scott Maine4d8f1b2012-06-21 18:03:05 -0700358
359
360
361 // Set up expand/collapse behavior
362 $('#nav li.nav-section .nav-section-header').click(function() {
363 var section = $(this).closest('li.nav-section');
364 if (section.hasClass('expanded')) {
365 /* hide me */
366 // if (section.hasClass('selected') || section.find('li').hasClass('selected')) {
367 // /* but not if myself or my descendents are selected */
368 // return;
369 // }
370 section.children('ul').slideUp(250, function() {
371 section.closest('li').removeClass('expanded');
372 resizeNav();
373 });
374 } else {
375 /* show me */
376 // first hide all other siblings
377 var $others = $('li.nav-section.expanded', $(this).closest('ul'));
378 $others.removeClass('expanded').children('ul').slideUp(250);
379
380 // now expand me
381 section.closest('li').addClass('expanded');
382 section.children('ul').slideDown(250, function() {
383 resizeNav();
384 });
385 }
386 });
387
388 $(".scroll-pane").scroll(function(event) {
389 event.preventDefault();
390 return false;
391 });
392
393 /* Resize nav height when window height changes */
394 $(window).resize(function() {
395 if ($('#side-nav').length == 0) return;
396 var stylesheet = $('link[rel="stylesheet"][class="fullscreen"]');
397 setNavBarLeftPos(); // do this even if sidenav isn't fixed because it could become fixed
398 // make sidenav behave when resizing the window and side-scolling is a concern
399 if (navBarIsFixed) {
400 if ((stylesheet.attr("disabled") == "disabled") || stylesheet.length == 0) {
401 updateSideNavPosition();
402 } else {
403 updateSidenavFullscreenWidth();
404 }
405 }
406 resizeNav();
407 });
408
409
410 // Set up fixed navbar
411 var prevScrollLeft = 0; // used to compare current position to previous position of horiz scroll
412 $(window).scroll(function(event) {
413 if ($('#side-nav').length == 0) return;
414 if (event.target.nodeName == "DIV") {
415 // Dump scroll event if the target is a DIV, because that means the event is coming
416 // from a scrollable div and so there's no need to make adjustments to our layout
417 return;
418 }
419 var scrollTop = $(window).scrollTop();
420 var headerHeight = $('#header').outerHeight();
421 var subheaderHeight = $('#nav-x').outerHeight();
422 var searchResultHeight = $('#searchResults').is(":visible") ?
423 $('#searchResults').outerHeight() : 0;
424 var totalHeaderHeight = headerHeight + subheaderHeight + searchResultHeight;
Scott Mainb8d06a52012-12-19 18:38:24 -0800425 // we set the navbar fixed when the scroll position is beyond the height of the site header...
Scott Maine4d8f1b2012-06-21 18:03:05 -0700426 var navBarShouldBeFixed = scrollTop > totalHeaderHeight;
Scott Mainb8d06a52012-12-19 18:38:24 -0800427 // ... except if the document content is shorter than the sidenav height.
428 // (this is necessary to avoid crazy behavior on OSX Lion due to overscroll bouncing)
429 if ($("#doc-col").height() < $("#side-nav").height()) {
430 navBarShouldBeFixed = false;
431 }
Scott Maine4d8f1b2012-06-21 18:03:05 -0700432
433 var scrollLeft = $(window).scrollLeft();
434 // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match
435 if (navBarIsFixed && (scrollLeft != prevScrollLeft)) {
436 updateSideNavPosition();
437 prevScrollLeft = scrollLeft;
438 }
439
440 // Don't continue if the header is sufficently far away
441 // (to avoid intensive resizing that slows scrolling)
442 if (navBarIsFixed && navBarShouldBeFixed) {
443 return;
444 }
445
446 if (navBarIsFixed != navBarShouldBeFixed) {
447 if (navBarShouldBeFixed) {
448 // make it fixed
449 var width = $('#devdoc-nav').width();
450 $('#devdoc-nav')
451 .addClass('fixed')
452 .css({'width':width+'px'})
453 .prependTo('#body-content');
454 // add neato "back to top" button
455 $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'});
456
457 // update the sidenaav position for side scrolling
458 updateSideNavPosition();
459 } else {
460 // make it static again
461 $('#devdoc-nav')
462 .removeClass('fixed')
463 .css({'width':'auto','margin':''})
464 .prependTo('#side-nav');
465 $('#devdoc-nav a.totop').hide();
466 }
467 navBarIsFixed = navBarShouldBeFixed;
468 }
469
470 resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance
471 });
472
473
474 var navBarLeftPos;
475 if ($('#devdoc-nav').length) {
476 setNavBarLeftPos();
477 }
478
479
480 // Stop expand/collapse behavior when clicking on nav section links (since we're navigating away
481 // from the page)
482 $('.nav-section-header').find('a:eq(0)').click(function(evt) {
483 window.location.href = $(this).attr('href');
484 return false;
485 });
486
487 // Set up play-on-hover <video> tags.
488 $('video.play-on-hover').bind('click', function(){
489 $(this).get(0).load(); // in case the video isn't seekable
490 $(this).get(0).play();
491 });
492
493 // Set up tooltips
494 var TOOLTIP_MARGIN = 10;
Scott Maindb3678b2012-10-23 14:13:41 -0700495 $('acronym,.tooltip-link').each(function() {
Scott Maine4d8f1b2012-06-21 18:03:05 -0700496 var $target = $(this);
497 var $tooltip = $('<div>')
498 .addClass('tooltip-box')
Scott Maindb3678b2012-10-23 14:13:41 -0700499 .append($target.attr('title'))
Scott Maine4d8f1b2012-06-21 18:03:05 -0700500 .hide()
501 .appendTo('body');
502 $target.removeAttr('title');
503
504 $target.hover(function() {
505 // in
506 var targetRect = $target.offset();
507 targetRect.width = $target.width();
508 targetRect.height = $target.height();
509
510 $tooltip.css({
511 left: targetRect.left,
512 top: targetRect.top + targetRect.height + TOOLTIP_MARGIN
513 });
514 $tooltip.addClass('below');
515 $tooltip.show();
516 }, function() {
517 // out
518 $tooltip.hide();
519 });
520 });
521
522 // Set up <h2> deeplinks
523 $('h2').click(function() {
524 var id = $(this).attr('id');
525 if (id) {
526 document.location.hash = id;
527 }
528 });
529
530 //Loads the +1 button
531 var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
532 po.src = 'https://apis.google.com/js/plusone.js';
533 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
534
535
536 // Revise the sidenav widths to make room for the scrollbar
537 // which avoids the visible width from changing each time the bar appears
538 var $sidenav = $("#side-nav");
539 var sidenav_width = parseInt($sidenav.innerWidth());
540
541 $("#devdoc-nav #nav").css("width", sidenav_width - 4 + "px"); // 4px is scrollbar width
542
543
544 $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller
545
546 if ($(".scroll-pane").length > 1) {
547 // Check if there's a user preference for the panel heights
548 var cookieHeight = readCookie("reference_height");
549 if (cookieHeight) {
550 restoreHeight(cookieHeight);
551 }
552 }
553
554 resizeNav();
555
Scott Main015d6162013-01-29 09:01:52 -0800556 /* init the language selector based on user cookie for lang */
557 loadLangPref();
558 changeNavLang(getLangPref());
559
560 /* setup event handlers to ensure the overflow menu is visible while picking lang */
561 $("#language select")
562 .mousedown(function() {
563 $("div.morehover").addClass("hover"); })
564 .blur(function() {
565 $("div.morehover").removeClass("hover"); });
566
567 /* some global variable setup */
568 resizePackagesNav = $("#resize-packages-nav");
569 classesNav = $("#classes-nav");
570 devdocNav = $("#devdoc-nav");
571
572 var cookiePath = "";
573 if (location.href.indexOf("/reference/") != -1) {
574 cookiePath = "reference_";
575 } else if (location.href.indexOf("/guide/") != -1) {
576 cookiePath = "guide_";
577 } else if (location.href.indexOf("/tools/") != -1) {
578 cookiePath = "tools_";
579 } else if (location.href.indexOf("/training/") != -1) {
580 cookiePath = "training_";
581 } else if (location.href.indexOf("/design/") != -1) {
582 cookiePath = "design_";
583 } else if (location.href.indexOf("/distribute/") != -1) {
584 cookiePath = "distribute_";
585 }
Scott Maine4d8f1b2012-06-21 18:03:05 -0700586
587});
Scott Main7e447ed2013-02-19 17:22:37 -0800588// END of the onload event
Scott Maine4d8f1b2012-06-21 18:03:05 -0700589
590
Scott Mainf6145542013-04-01 16:38:11 -0700591function highlightSidenav() {
592 // select current page in sidenav and header, and set up prev/next links if they exist
593 var $selNavLink = $('#nav').find('a[href="' + mPagePath + '"]');
594 var $selListItem;
595 if ($selNavLink.length) {
596
597 // Find this page's <li> in sidenav and set selected
598 $selListItem = $selNavLink.closest('li');
599 $selListItem.addClass('selected');
600
601 // Traverse up the tree and expand all parent nav-sections
602 $selNavLink.parents('li.nav-section').each(function() {
603 $(this).addClass('expanded');
604 $(this).children('ul').show();
605 });
606 }
607}
608
Scott Maine4d8f1b2012-06-21 18:03:05 -0700609
610function toggleFullscreen(enable) {
611 var delay = 20;
612 var enabled = true;
613 var stylesheet = $('link[rel="stylesheet"][class="fullscreen"]');
614 if (enable) {
615 // Currently NOT USING fullscreen; enable fullscreen
616 stylesheet.removeAttr('disabled');
617 $('#nav-swap .fullscreen').removeClass('disabled');
618 $('#devdoc-nav').css({left:''});
619 setTimeout(updateSidenavFullscreenWidth,delay); // need to wait a moment for css to switch
620 enabled = true;
621 } else {
622 // Currently USING fullscreen; disable fullscreen
623 stylesheet.attr('disabled', 'disabled');
624 $('#nav-swap .fullscreen').addClass('disabled');
625 setTimeout(updateSidenavFixedWidth,delay); // need to wait a moment for css to switch
626 enabled = false;
627 }
628 writeCookie("fullscreen", enabled, null, null);
629 setNavBarLeftPos();
630 resizeNav(delay);
631 updateSideNavPosition();
632 setTimeout(initSidenavHeightResize,delay);
633}
634
635
636function setNavBarLeftPos() {
637 navBarLeftPos = $('#body-content').offset().left;
638}
639
640
641function updateSideNavPosition() {
642 var newLeft = $(window).scrollLeft() - navBarLeftPos;
643 $('#devdoc-nav').css({left: -newLeft});
644 $('#devdoc-nav .totop').css({left: -(newLeft - parseInt($('#side-nav').css('margin-left')))});
645}
646
647
648
649
650
651
652
653
654// TODO: use $(document).ready instead
655function addLoadEvent(newfun) {
656 var current = window.onload;
657 if (typeof window.onload != 'function') {
658 window.onload = newfun;
659 } else {
660 window.onload = function() {
661 current();
662 newfun();
663 }
664 }
665}
666
667var agent = navigator['userAgent'].toLowerCase();
668// If a mobile phone, set flag and do mobile setup
669if ((agent.indexOf("mobile") != -1) || // android, iphone, ipod
670 (agent.indexOf("blackberry") != -1) ||
671 (agent.indexOf("webos") != -1) ||
672 (agent.indexOf("mini") != -1)) { // opera mini browsers
673 isMobile = true;
674}
675
676
Scott Maine4d8f1b2012-06-21 18:03:05 -0700677addLoadEvent( function() {
678 $("pre:not(.no-pretty-print)").addClass("prettyprint");
679 prettyPrint();
680} );
681
Scott Maine4d8f1b2012-06-21 18:03:05 -0700682
683
684
685/* ######### RESIZE THE SIDENAV HEIGHT ########## */
686
687function resizeNav(delay) {
688 var $nav = $("#devdoc-nav");
689 var $window = $(window);
690 var navHeight;
691
692 // Get the height of entire window and the total header height.
693 // Then figure out based on scroll position whether the header is visible
694 var windowHeight = $window.height();
695 var scrollTop = $window.scrollTop();
696 var headerHeight = $('#header').outerHeight();
697 var subheaderHeight = $('#nav-x').outerHeight();
698 var headerVisible = (scrollTop < (headerHeight + subheaderHeight));
699
700 // get the height of space between nav and top of window.
701 // Could be either margin or top position, depending on whether the nav is fixed.
702 var topMargin = (parseInt($nav.css('margin-top')) || parseInt($nav.css('top'))) + 1;
703 // add 1 for the #side-nav bottom margin
704
705 // Depending on whether the header is visible, set the side nav's height.
706 if (headerVisible) {
707 // The sidenav height grows as the header goes off screen
708 navHeight = windowHeight - (headerHeight + subheaderHeight - scrollTop) - topMargin;
709 } else {
710 // Once header is off screen, the nav height is almost full window height
711 navHeight = windowHeight - topMargin;
712 }
713
714
715
716 $scrollPanes = $(".scroll-pane");
717 if ($scrollPanes.length > 1) {
718 // subtract the height of the api level widget and nav swapper from the available nav height
719 navHeight -= ($('#api-nav-header').outerHeight(true) + $('#nav-swap').outerHeight(true));
720
721 $("#swapper").css({height:navHeight + "px"});
722 if ($("#nav-tree").is(":visible")) {
723 $("#nav-tree").css({height:navHeight});
724 }
725
726 var classesHeight = navHeight - parseInt($("#resize-packages-nav").css("height")) - 10 + "px";
727 //subtract 10px to account for drag bar
728
729 // if the window becomes small enough to make the class panel height 0,
730 // then the package panel should begin to shrink
731 if (parseInt(classesHeight) <= 0) {
732 $("#resize-packages-nav").css({height:navHeight - 10}); //subtract 10px for drag bar
733 $("#packages-nav").css({height:navHeight - 10});
734 }
735
736 $("#classes-nav").css({'height':classesHeight, 'margin-top':'10px'});
737 $("#classes-nav .jspContainer").css({height:classesHeight});
738
739
740 } else {
741 $nav.height(navHeight);
742 }
743
744 if (delay) {
745 updateFromResize = true;
746 delayedReInitScrollbars(delay);
747 } else {
748 reInitScrollbars();
749 }
750
751}
752
753var updateScrollbars = false;
754var updateFromResize = false;
755
756/* Re-initialize the scrollbars to account for changed nav size.
757 * This method postpones the actual update by a 1/4 second in order to optimize the
758 * scroll performance while the header is still visible, because re-initializing the
759 * scroll panes is an intensive process.
760 */
761function delayedReInitScrollbars(delay) {
762 // If we're scheduled for an update, but have received another resize request
763 // before the scheduled resize has occured, just ignore the new request
764 // (and wait for the scheduled one).
765 if (updateScrollbars && updateFromResize) {
766 updateFromResize = false;
767 return;
768 }
769
770 // We're scheduled for an update and the update request came from this method's setTimeout
771 if (updateScrollbars && !updateFromResize) {
772 reInitScrollbars();
773 updateScrollbars = false;
774 } else {
775 updateScrollbars = true;
776 updateFromResize = false;
777 setTimeout('delayedReInitScrollbars()',delay);
778 }
779}
780
781/* Re-initialize the scrollbars to account for changed nav size. */
782function reInitScrollbars() {
783 var pane = $(".scroll-pane").each(function(){
784 var api = $(this).data('jsp');
785 if (!api) { setTimeout(reInitScrollbars,300); return;}
786 api.reinitialise( {verticalGutter:0} );
787 });
788 $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller
789}
790
791
792/* Resize the height of the nav panels in the reference,
793 * and save the new size to a cookie */
794function saveNavPanels() {
795 var basePath = getBaseUri(location.pathname);
796 var section = basePath.substring(1,basePath.indexOf("/",1));
797 writeCookie("height", resizePackagesNav.css("height"), section, null);
798}
799
800
801
802function restoreHeight(packageHeight) {
803 $("#resize-packages-nav").height(packageHeight);
804 $("#packages-nav").height(packageHeight);
805 // var classesHeight = navHeight - packageHeight;
806 // $("#classes-nav").css({height:classesHeight});
807 // $("#classes-nav .jspContainer").css({height:classesHeight});
808}
809
810
811
812/* ######### END RESIZE THE SIDENAV HEIGHT ########## */
813
814
815
816
817
818/** Scroll the jScrollPane to make the currently selected item visible
819 This is called when the page finished loading. */
820function scrollIntoView(nav) {
821 var $nav = $("#"+nav);
822 var element = $nav.jScrollPane({/* ...settings... */});
823 var api = element.data('jsp');
824
825 if ($nav.is(':visible')) {
826 var $selected = $(".selected", $nav);
827 if ($selected.length == 0) return;
828
829 var selectedOffset = $selected.position().top;
830 if (selectedOffset + 90 > $nav.height()) { // add 90 so that we scroll up even
831 // if the current item is close to the bottom
832 api.scrollTo(0, selectedOffset - ($nav.height() / 4), false); // scroll the item into view
833 // to be 1/4 of the way from the top
834 }
835 }
836}
837
838
839
840
841
842
843/* Show popup dialogs */
844function showDialog(id) {
845 $dialog = $("#"+id);
846 $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>');
847 $dialog.wrapInner('<div/>');
848 $dialog.removeClass("hide");
849}
850
851
852
853
854
855/* ######### COOKIES! ########## */
856
857function readCookie(cookie) {
858 var myCookie = cookie_namespace+"_"+cookie+"=";
859 if (document.cookie) {
860 var index = document.cookie.indexOf(myCookie);
861 if (index != -1) {
862 var valStart = index + myCookie.length;
863 var valEnd = document.cookie.indexOf(";", valStart);
864 if (valEnd == -1) {
865 valEnd = document.cookie.length;
866 }
867 var val = document.cookie.substring(valStart, valEnd);
868 return val;
869 }
870 }
871 return 0;
872}
873
874function writeCookie(cookie, val, section, expiration) {
875 if (val==undefined) return;
876 section = section == null ? "_" : "_"+section+"_";
877 if (expiration == null) {
878 var date = new Date();
879 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week
880 expiration = date.toGMTString();
881 }
882 var cookieValue = cookie_namespace + section + cookie + "=" + val
883 + "; expires=" + expiration+"; path=/";
884 document.cookie = cookieValue;
885}
886
887/* ######### END COOKIES! ########## */
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913/*
914
915REMEMBER THE PREVIOUS PAGE FOR EACH TAB
916
917function loadLast(cookiePath) {
918 var location = window.location.href;
919 if (location.indexOf("/"+cookiePath+"/") != -1) {
920 return true;
921 }
922 var lastPage = readCookie(cookiePath + "_lastpage");
923 if (lastPage) {
924 window.location = lastPage;
925 return false;
926 }
927 return true;
928}
929
930
931
932$(window).unload(function(){
933 var path = getBaseUri(location.pathname);
934 if (path.indexOf("/reference/") != -1) {
935 writeCookie("lastpage", path, "reference", null);
936 } else if (path.indexOf("/guide/") != -1) {
937 writeCookie("lastpage", path, "guide", null);
938 } else if ((path.indexOf("/resources/") != -1) || (path.indexOf("/training/") != -1)) {
939 writeCookie("lastpage", path, "resources", null);
940 }
941});
942
943*/
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958function toggle(obj, slide) {
959 var ul = $("ul:first", obj);
960 var li = ul.parent();
961 if (li.hasClass("closed")) {
962 if (slide) {
963 ul.slideDown("fast");
964 } else {
965 ul.show();
966 }
967 li.removeClass("closed");
968 li.addClass("open");
969 $(".toggle-img", li).attr("title", "hide pages");
970 } else {
971 ul.slideUp("fast");
972 li.removeClass("open");
973 li.addClass("closed");
974 $(".toggle-img", li).attr("title", "show pages");
975 }
976}
977
978
979
980
981
982function buildToggleLists() {
983 $(".toggle-list").each(
984 function(i) {
985 $("div:first", this).append("<a class='toggle-img' href='#' title='show pages' onClick='toggle(this.parentNode.parentNode, true); return false;'></a>");
986 $(this).addClass("closed");
987 });
988}
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021/* REFERENCE NAV SWAP */
1022
1023
1024function getNavPref() {
1025 var v = readCookie('reference_nav');
1026 if (v != NAV_PREF_TREE) {
1027 v = NAV_PREF_PANELS;
1028 }
1029 return v;
1030}
1031
1032function chooseDefaultNav() {
1033 nav_pref = getNavPref();
1034 if (nav_pref == NAV_PREF_TREE) {
1035 $("#nav-panels").toggle();
1036 $("#panel-link").toggle();
1037 $("#nav-tree").toggle();
1038 $("#tree-link").toggle();
1039 }
1040}
1041
1042function swapNav() {
1043 if (nav_pref == NAV_PREF_TREE) {
1044 nav_pref = NAV_PREF_PANELS;
1045 } else {
1046 nav_pref = NAV_PREF_TREE;
1047 init_default_navtree(toRoot);
1048 }
1049 var date = new Date();
1050 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
1051 writeCookie("nav", nav_pref, "reference", date.toGMTString());
1052
1053 $("#nav-panels").toggle();
1054 $("#panel-link").toggle();
1055 $("#nav-tree").toggle();
1056 $("#tree-link").toggle();
1057
1058 resizeNav();
1059
1060 // Gross nasty hack to make tree view show up upon first swap by setting height manually
1061 $("#nav-tree .jspContainer:visible")
1062 .css({'height':$("#nav-tree .jspContainer .jspPane").height() +'px'});
1063 // Another nasty hack to make the scrollbar appear now that we have height
1064 resizeNav();
1065
1066 if ($("#nav-tree").is(':visible')) {
1067 scrollIntoView("nav-tree");
1068 } else {
1069 scrollIntoView("packages-nav");
1070 scrollIntoView("classes-nav");
1071 }
1072}
1073
1074
1075
Scott Mainf5089842012-08-14 16:31:07 -07001076/* ############################################ */
Scott Maine4d8f1b2012-06-21 18:03:05 -07001077/* ########## LOCALIZATION ############ */
Scott Mainf5089842012-08-14 16:31:07 -07001078/* ############################################ */
Scott Maine4d8f1b2012-06-21 18:03:05 -07001079
1080function getBaseUri(uri) {
1081 var intlUrl = (uri.substring(0,6) == "/intl/");
1082 if (intlUrl) {
1083 base = uri.substring(uri.indexOf('intl/')+5,uri.length);
1084 base = base.substring(base.indexOf('/')+1, base.length);
1085 //alert("intl, returning base url: /" + base);
1086 return ("/" + base);
1087 } else {
1088 //alert("not intl, returning uri as found.");
1089 return uri;
1090 }
1091}
1092
1093function requestAppendHL(uri) {
1094//append "?hl=<lang> to an outgoing request (such as to blog)
1095 var lang = getLangPref();
1096 if (lang) {
1097 var q = 'hl=' + lang;
1098 uri += '?' + q;
1099 window.location = uri;
1100 return false;
1101 } else {
1102 return true;
1103 }
1104}
1105
1106
Scott Maine4d8f1b2012-06-21 18:03:05 -07001107function changeNavLang(lang) {
Scott Main6eb95f12012-10-02 17:12:23 -07001108 var $links = $("#devdoc-nav,#header,#nav-x,.training-nav-top,.content-footer").find("a["+lang+"-lang]");
1109 $links.each(function(i){ // for each link with a translation
1110 var $link = $(this);
1111 if (lang != "en") { // No need to worry about English, because a language change invokes new request
1112 // put the desired language from the attribute as the text
1113 $link.text($link.attr(lang+"-lang"))
Scott Maine4d8f1b2012-06-21 18:03:05 -07001114 }
Scott Main6eb95f12012-10-02 17:12:23 -07001115 });
Scott Maine4d8f1b2012-06-21 18:03:05 -07001116}
1117
Scott Main015d6162013-01-29 09:01:52 -08001118function changeLangPref(lang, submit) {
Scott Maine4d8f1b2012-06-21 18:03:05 -07001119 var date = new Date();
1120 expires = date.toGMTString(date.setTime(date.getTime()+(10*365*24*60*60*1000)));
1121 // keep this for 50 years
1122 //alert("expires: " + expires)
1123 writeCookie("pref_lang", lang, null, expires);
Scott Main015d6162013-01-29 09:01:52 -08001124
1125 // ####### TODO: Remove this condition once we're stable on devsite #######
1126 // This condition is only needed if we still need to support legacy GAE server
1127 if (devsite) {
1128 // Switch language when on Devsite server
1129 if (submit) {
1130 $("#setlang").submit();
1131 }
1132 } else {
1133 // Switch language when on legacy GAE server
Scott Main015d6162013-01-29 09:01:52 -08001134 if (submit) {
1135 window.location = getBaseUri(location.pathname);
1136 }
Scott Maine4d8f1b2012-06-21 18:03:05 -07001137 }
1138}
1139
1140function loadLangPref() {
1141 var lang = readCookie("pref_lang");
1142 if (lang != 0) {
1143 $("#language").find("option[value='"+lang+"']").attr("selected",true);
1144 }
1145}
1146
1147function getLangPref() {
1148 var lang = $("#language").find(":selected").attr("value");
1149 if (!lang) {
1150 lang = readCookie("pref_lang");
1151 }
1152 return (lang != 0) ? lang : 'en';
1153}
1154
1155/* ########## END LOCALIZATION ############ */
1156
1157
1158
1159
1160
1161
1162/* Used to hide and reveal supplemental content, such as long code samples.
1163 See the companion CSS in android-developer-docs.css */
1164function toggleContent(obj) {
1165 var div = $(obj.parentNode.parentNode);
1166 var toggleMe = $(".toggle-content-toggleme",div);
1167 if (div.hasClass("closed")) { // if it's closed, open it
1168 toggleMe.slideDown();
1169 $(".toggle-content-text", obj).toggle();
1170 div.removeClass("closed").addClass("open");
1171 $(".toggle-content-img", div).attr("title", "hide").attr("src", toRoot
1172 + "assets/images/triangle-opened.png");
1173 } else { // if it's open, close it
1174 toggleMe.slideUp('fast', function() { // Wait until the animation is done before closing arrow
1175 $(".toggle-content-text", obj).toggle();
1176 div.removeClass("open").addClass("closed");
1177 $(".toggle-content-img", div).attr("title", "show").attr("src", toRoot
1178 + "assets/images/triangle-closed.png");
1179 });
1180 }
1181 return false;
1182}
Scott Mainf5089842012-08-14 16:31:07 -07001183
1184
Scott Maindb3678b2012-10-23 14:13:41 -07001185/* New version of expandable content */
1186function toggleExpandable(link,id) {
1187 if($(id).is(':visible')) {
1188 $(id).slideUp();
1189 $(link).removeClass('expanded');
1190 } else {
1191 $(id).slideDown();
1192 $(link).addClass('expanded');
1193 }
1194}
1195
1196function hideExpandable(ids) {
1197 $(ids).slideUp();
Scott Main55d99832012-11-12 23:03:59 -08001198 $(ids).prev('h4').find('a.expandable').removeClass('expanded');
Scott Maindb3678b2012-10-23 14:13:41 -07001199}
1200
Scott Mainf5089842012-08-14 16:31:07 -07001201
1202
1203
1204
Robert Lyd2dd6e52012-11-29 21:28:48 -08001205/*
Scott Mainf5089842012-08-14 16:31:07 -07001206 * Slideshow 1.0
1207 * Used on /index.html and /develop/index.html for carousel
1208 *
1209 * Sample usage:
1210 * HTML -
1211 * <div class="slideshow-container">
1212 * <a href="" class="slideshow-prev">Prev</a>
1213 * <a href="" class="slideshow-next">Next</a>
1214 * <ul>
1215 * <li class="item"><img src="images/marquee1.jpg"></li>
1216 * <li class="item"><img src="images/marquee2.jpg"></li>
1217 * <li class="item"><img src="images/marquee3.jpg"></li>
1218 * <li class="item"><img src="images/marquee4.jpg"></li>
1219 * </ul>
1220 * </div>
1221 *
1222 * <script type="text/javascript">
1223 * $('.slideshow-container').dacSlideshow({
1224 * auto: true,
1225 * btnPrev: '.slideshow-prev',
1226 * btnNext: '.slideshow-next'
1227 * });
1228 * </script>
1229 *
1230 * Options:
1231 * btnPrev: optional identifier for previous button
1232 * btnNext: optional identifier for next button
Scott Maineb410352013-01-14 19:03:40 -08001233 * btnPause: optional identifier for pause button
Scott Mainf5089842012-08-14 16:31:07 -07001234 * auto: whether or not to auto-proceed
1235 * speed: animation speed
1236 * autoTime: time between auto-rotation
1237 * easing: easing function for transition
1238 * start: item to select by default
1239 * scroll: direction to scroll in
1240 * pagination: whether or not to include dotted pagination
1241 *
1242 */
1243
1244 (function($) {
1245 $.fn.dacSlideshow = function(o) {
1246
1247 //Options - see above
1248 o = $.extend({
1249 btnPrev: null,
1250 btnNext: null,
Scott Maineb410352013-01-14 19:03:40 -08001251 btnPause: null,
Scott Mainf5089842012-08-14 16:31:07 -07001252 auto: true,
1253 speed: 500,
1254 autoTime: 12000,
1255 easing: null,
1256 start: 0,
1257 scroll: 1,
1258 pagination: true
1259
1260 }, o || {});
1261
1262 //Set up a carousel for each
1263 return this.each(function() {
1264
1265 var running = false;
1266 var animCss = o.vertical ? "top" : "left";
1267 var sizeCss = o.vertical ? "height" : "width";
1268 var div = $(this);
1269 var ul = $("ul", div);
1270 var tLi = $("li", ul);
1271 var tl = tLi.size();
1272 var timer = null;
1273
1274 var li = $("li", ul);
1275 var itemLength = li.size();
1276 var curr = o.start;
1277
1278 li.css({float: o.vertical ? "none" : "left"});
1279 ul.css({margin: "0", padding: "0", position: "relative", "list-style-type": "none", "z-index": "1"});
1280 div.css({position: "relative", "z-index": "2", left: "0px"});
1281
1282 var liSize = o.vertical ? height(li) : width(li);
1283 var ulSize = liSize * itemLength;
1284 var divSize = liSize;
1285
1286 li.css({width: li.width(), height: li.height()});
1287 ul.css(sizeCss, ulSize+"px").css(animCss, -(curr*liSize));
1288
1289 div.css(sizeCss, divSize+"px");
1290
1291 //Pagination
1292 if (o.pagination) {
1293 var pagination = $("<div class='pagination'></div>");
1294 var pag_ul = $("<ul></ul>");
1295 if (tl > 1) {
1296 for (var i=0;i<tl;i++) {
1297 var li = $("<li>"+i+"</li>");
1298 pag_ul.append(li);
1299 if (i==o.start) li.addClass('active');
1300 li.click(function() {
1301 go(parseInt($(this).text()));
1302 })
1303 }
1304 pagination.append(pag_ul);
1305 div.append(pagination);
1306 }
1307 }
1308
1309 //Previous button
1310 if(o.btnPrev)
1311 $(o.btnPrev).click(function(e) {
1312 e.preventDefault();
1313 return go(curr-o.scroll);
1314 });
1315
1316 //Next button
1317 if(o.btnNext)
1318 $(o.btnNext).click(function(e) {
1319 e.preventDefault();
1320 return go(curr+o.scroll);
1321 });
Scott Maineb410352013-01-14 19:03:40 -08001322
1323 //Pause button
1324 if(o.btnPause)
1325 $(o.btnPause).click(function(e) {
1326 e.preventDefault();
1327 if ($(this).hasClass('paused')) {
1328 startRotateTimer();
1329 } else {
1330 pauseRotateTimer();
1331 }
1332 });
Scott Mainf5089842012-08-14 16:31:07 -07001333
1334 //Auto rotation
1335 if(o.auto) startRotateTimer();
1336
1337 function startRotateTimer() {
1338 clearInterval(timer);
1339 timer = setInterval(function() {
1340 if (curr == tl-1) {
1341 go(0);
1342 } else {
1343 go(curr+o.scroll);
1344 }
1345 }, o.autoTime);
Scott Maineb410352013-01-14 19:03:40 -08001346 $(o.btnPause).removeClass('paused');
1347 }
1348
1349 function pauseRotateTimer() {
1350 clearInterval(timer);
1351 $(o.btnPause).addClass('paused');
Scott Mainf5089842012-08-14 16:31:07 -07001352 }
1353
1354 //Go to an item
1355 function go(to) {
1356 if(!running) {
1357
1358 if(to<0) {
1359 to = itemLength-1;
1360 } else if (to>itemLength-1) {
1361 to = 0;
1362 }
1363 curr = to;
1364
1365 running = true;
1366
1367 ul.animate(
1368 animCss == "left" ? { left: -(curr*liSize) } : { top: -(curr*liSize) } , o.speed, o.easing,
1369 function() {
1370 running = false;
1371 }
1372 );
1373
1374 $(o.btnPrev + "," + o.btnNext).removeClass("disabled");
1375 $( (curr-o.scroll<0 && o.btnPrev)
1376 ||
1377 (curr+o.scroll > itemLength && o.btnNext)
1378 ||
1379 []
1380 ).addClass("disabled");
1381
1382
1383 var nav_items = $('li', pagination);
1384 nav_items.removeClass('active');
1385 nav_items.eq(to).addClass('active');
1386
1387
1388 }
1389 if(o.auto) startRotateTimer();
1390 return false;
1391 };
1392 });
1393 };
1394
1395 function css(el, prop) {
1396 return parseInt($.css(el[0], prop)) || 0;
1397 };
1398 function width(el) {
1399 return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
1400 };
1401 function height(el) {
1402 return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
1403 };
1404
1405 })(jQuery);
1406
1407
Robert Lyd2dd6e52012-11-29 21:28:48 -08001408/*
Scott Mainf5089842012-08-14 16:31:07 -07001409 * dacSlideshow 1.0
1410 * Used on develop/index.html for side-sliding tabs
1411 *
1412 * Sample usage:
1413 * HTML -
1414 * <div class="slideshow-container">
1415 * <a href="" class="slideshow-prev">Prev</a>
1416 * <a href="" class="slideshow-next">Next</a>
1417 * <ul>
1418 * <li class="item"><img src="images/marquee1.jpg"></li>
1419 * <li class="item"><img src="images/marquee2.jpg"></li>
1420 * <li class="item"><img src="images/marquee3.jpg"></li>
1421 * <li class="item"><img src="images/marquee4.jpg"></li>
1422 * </ul>
1423 * </div>
1424 *
1425 * <script type="text/javascript">
1426 * $('.slideshow-container').dacSlideshow({
1427 * auto: true,
1428 * btnPrev: '.slideshow-prev',
1429 * btnNext: '.slideshow-next'
1430 * });
1431 * </script>
1432 *
1433 * Options:
1434 * btnPrev: optional identifier for previous button
1435 * btnNext: optional identifier for next button
1436 * auto: whether or not to auto-proceed
1437 * speed: animation speed
1438 * autoTime: time between auto-rotation
1439 * easing: easing function for transition
1440 * start: item to select by default
1441 * scroll: direction to scroll in
1442 * pagination: whether or not to include dotted pagination
1443 *
1444 */
1445 (function($) {
1446 $.fn.dacTabbedList = function(o) {
1447
1448 //Options - see above
1449 o = $.extend({
1450 speed : 250,
1451 easing: null,
1452 nav_id: null,
1453 frame_id: null
1454 }, o || {});
1455
1456 //Set up a carousel for each
1457 return this.each(function() {
1458
1459 var curr = 0;
1460 var running = false;
1461 var animCss = "margin-left";
1462 var sizeCss = "width";
1463 var div = $(this);
1464
1465 var nav = $(o.nav_id, div);
1466 var nav_li = $("li", nav);
1467 var nav_size = nav_li.size();
1468 var frame = div.find(o.frame_id);
1469 var content_width = $(frame).find('ul').width();
1470 //Buttons
1471 $(nav_li).click(function(e) {
1472 go($(nav_li).index($(this)));
1473 })
1474
1475 //Go to an item
1476 function go(to) {
1477 if(!running) {
1478 curr = to;
1479 running = true;
1480
1481 frame.animate({ 'margin-left' : -(curr*content_width) }, o.speed, o.easing,
1482 function() {
1483 running = false;
1484 }
1485 );
1486
1487
1488 nav_li.removeClass('active');
1489 nav_li.eq(to).addClass('active');
1490
1491
1492 }
1493 return false;
1494 };
1495 });
1496 };
1497
1498 function css(el, prop) {
1499 return parseInt($.css(el[0], prop)) || 0;
1500 };
1501 function width(el) {
1502 return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
1503 };
1504 function height(el) {
1505 return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
1506 };
1507
1508 })(jQuery);
1509
1510
1511
1512
1513
1514/* ######################################################## */
1515/* ################ SEARCH SUGGESTIONS ################## */
1516/* ######################################################## */
1517
1518
Scott Main7e447ed2013-02-19 17:22:37 -08001519
Scott Mainf5089842012-08-14 16:31:07 -07001520var gSelectedIndex = -1;
Scott Mainf5089842012-08-14 16:31:07 -07001521var gMatches = new Array();
1522var gLastText = "";
Scott Mainf5089842012-08-14 16:31:07 -07001523var gInitialized = false;
Scott Main7e447ed2013-02-19 17:22:37 -08001524var ROW_COUNT_FRAMEWORK = 20; // max number of results in list
1525var gListLength = 0;
1526
1527
1528var gGoogleMatches = new Array();
1529var ROW_COUNT_GOOGLE = 15; // max number of results in list
1530var gGoogleListLength = 0;
Scott Mainf5089842012-08-14 16:31:07 -07001531
Scott Mainde295272013-03-25 15:48:35 -07001532function onSuggestionClick(link) {
1533 // When user clicks a suggested document, track it
1534 _gaq.push(['_trackEvent', 'Suggestion Click', 'clicked: ' + $(link).text(),
1535 'from: ' + $("#search_autocomplete").val()]);
1536}
1537
Scott Mainf5089842012-08-14 16:31:07 -07001538function set_item_selected($li, selected)
1539{
1540 if (selected) {
1541 $li.attr('class','jd-autocomplete jd-selected');
1542 } else {
1543 $li.attr('class','jd-autocomplete');
1544 }
1545}
1546
1547function set_item_values(toroot, $li, match)
1548{
1549 var $link = $('a',$li);
1550 $link.html(match.__hilabel || match.label);
1551 $link.attr('href',toroot + match.link);
1552}
1553
Scott Main7e447ed2013-02-19 17:22:37 -08001554function new_suggestion() {
1555 var $list = $("#search_filtered");
1556 var $li = $("<li class='jd-autocomplete'></li>");
1557 $list.append($li);
1558
1559 $li.mousedown(function() {
1560 window.location = this.firstChild.getAttribute("href");
1561 });
1562 $li.mouseover(function() {
1563 $('#search_filtered li').removeClass('jd-selected');
1564 $(this).addClass('jd-selected');
1565 gSelectedIndex = $('#search_filtered li').index(this);
1566 });
Scott Mainde295272013-03-25 15:48:35 -07001567 $li.append("<a onclick='onSuggestionClick(this)'></a>");
Scott Main7e447ed2013-02-19 17:22:37 -08001568 $li.attr('class','show-item');
1569 return $li;
1570}
1571
Scott Mainf5089842012-08-14 16:31:07 -07001572function sync_selection_table(toroot)
1573{
1574 var $list = $("#search_filtered");
1575 var $li; //list item jquery object
1576 var i; //list item iterator
Scott Mainf5089842012-08-14 16:31:07 -07001577
Scott Main7e447ed2013-02-19 17:22:37 -08001578 // reset the list
1579 $("li",$list).remove();
1580
Scott Mainf5089842012-08-14 16:31:07 -07001581 //if we have results, make the table visible and initialize result info
Scott Main7e447ed2013-02-19 17:22:37 -08001582 if ((gMatches.length > 0) || (gGoogleMatches.length > 0)) {
1583 // reveal suggestion list
Scott Mainf5089842012-08-14 16:31:07 -07001584 $('#search_filtered_div').removeClass('no-display');
Scott Main7e447ed2013-02-19 17:22:37 -08001585 var listIndex = 0; // list index position
1586
1587 // ########### ANDROID RESULTS #############
1588 if (gMatches.length > 0) {
1589
1590 // determine android results to show
1591 gListLength = gMatches.length < ROW_COUNT_FRAMEWORK ?
1592 gMatches.length : ROW_COUNT_FRAMEWORK;
1593 for (i=0; i<gListLength; i++) {
1594 var $li = new_suggestion();
1595 set_item_values(toroot, $li, gMatches[i]);
1596 set_item_selected($li, i == gSelectedIndex);
Scott Mainf5089842012-08-14 16:31:07 -07001597 }
1598 }
Scott Main7e447ed2013-02-19 17:22:37 -08001599
1600 // ########### GOOGLE RESULTS #############
1601 if (gGoogleMatches.length > 0) {
1602 // show header for list
1603 $list.append("<li class='header'>in Google Services:</li>");
1604
1605 // determine google results to show
1606 gGoogleListLength = gGoogleMatches.length < ROW_COUNT_GOOGLE ? gGoogleMatches.length : ROW_COUNT_GOOGLE;
1607 for (i=0; i<gGoogleListLength; i++) {
1608 var $li = new_suggestion();
1609 set_item_values(toroot, $li, gGoogleMatches[i]);
1610 set_item_selected($li, i == gSelectedIndex);
1611 }
Scott Mainf5089842012-08-14 16:31:07 -07001612 }
Scott Main7e447ed2013-02-19 17:22:37 -08001613
Scott Mainf5089842012-08-14 16:31:07 -07001614 //if we have no results, hide the table
1615 } else {
1616 $('#search_filtered_div').addClass('no-display');
1617 }
1618}
1619
1620function search_changed(e, kd, toroot)
1621{
1622 var search = document.getElementById("search_autocomplete");
1623 var text = search.value.replace(/(^ +)|( +$)/g, '');
1624
1625 // show/hide the close button
1626 if (text != '') {
1627 $(".search .close").removeClass("hide");
1628 } else {
1629 $(".search .close").addClass("hide");
1630 }
1631
1632 // 13 = enter
1633 if (e.keyCode == 13) {
1634 $('#search_filtered_div').addClass('no-display');
1635 if (!$('#search_filtered_div').hasClass('no-display') || (gSelectedIndex < 0)) {
Scott Main7e447ed2013-02-19 17:22:37 -08001636 if ($("#searchResults").is(":hidden") && (search.value != "")) {
1637 // if results aren't showing (and text not empty), return true to allow search to execute
Scott Mainf5089842012-08-14 16:31:07 -07001638 return true;
1639 } else {
1640 // otherwise, results are already showing, so allow ajax to auto refresh the results
1641 // and ignore this Enter press to avoid the reload.
1642 return false;
1643 }
1644 } else if (kd && gSelectedIndex >= 0) {
Scott Main7e447ed2013-02-19 17:22:37 -08001645 window.location = $("a",$('#search_filtered li')[gSelectedIndex]).attr("href");
Scott Mainf5089842012-08-14 16:31:07 -07001646 return false;
1647 }
1648 }
1649 // 38 -- arrow up
1650 else if (kd && (e.keyCode == 38)) {
Scott Main7e447ed2013-02-19 17:22:37 -08001651 if ($($("#search_filtered li")[gSelectedIndex-1]).hasClass("header")) {
1652 $('#search_filtered_div li').removeClass('jd-selected');
Scott Mainf5089842012-08-14 16:31:07 -07001653 gSelectedIndex--;
Scott Main7e447ed2013-02-19 17:22:37 -08001654 $('#search_filtered_div li:nth-child('+(gSelectedIndex+1)+')').addClass('jd-selected');
1655 }
1656 if (gSelectedIndex >= 0) {
1657 $('#search_filtered_div li').removeClass('jd-selected');
1658 gSelectedIndex--;
1659 $('#search_filtered_div li:nth-child('+(gSelectedIndex+1)+')').addClass('jd-selected');
Scott Mainf5089842012-08-14 16:31:07 -07001660 }
1661 return false;
1662 }
1663 // 40 -- arrow down
1664 else if (kd && (e.keyCode == 40)) {
Scott Main7e447ed2013-02-19 17:22:37 -08001665 if ($($("#search_filtered li")[gSelectedIndex+1]).hasClass("header")) {
1666 $('#search_filtered_div li').removeClass('jd-selected');
Scott Mainf5089842012-08-14 16:31:07 -07001667 gSelectedIndex++;
Scott Main7e447ed2013-02-19 17:22:37 -08001668 $('#search_filtered_div li:nth-child('+(gSelectedIndex+1)+')').addClass('jd-selected');
1669 }
1670 if ((gSelectedIndex < $("ul#search_filtered li").length-1) ||
1671 ($($("#search_filtered li")[gSelectedIndex+1]).hasClass("header"))) {
1672 $('#search_filtered_div li').removeClass('jd-selected');
1673 gSelectedIndex++;
1674 $('#search_filtered_div li:nth-child('+(gSelectedIndex+1)+')').addClass('jd-selected');
Scott Mainf5089842012-08-14 16:31:07 -07001675 }
1676 return false;
1677 }
Scott Main7e447ed2013-02-19 17:22:37 -08001678 // if key-up event and not arrow down/up,
1679 // read the search query and add suggestsions to gMatches
Scott Mainf5089842012-08-14 16:31:07 -07001680 else if (!kd && (e.keyCode != 40) && (e.keyCode != 38)) {
1681 gMatches = new Array();
1682 matchedCount = 0;
Scott Main7e447ed2013-02-19 17:22:37 -08001683 gGoogleMatches = new Array();
1684 matchedCountGoogle = 0;
Scott Mainf5089842012-08-14 16:31:07 -07001685 gSelectedIndex = -1;
Scott Main7e447ed2013-02-19 17:22:37 -08001686
1687 // Search for Android matches
Scott Mainf5089842012-08-14 16:31:07 -07001688 for (var i=0; i<DATA.length; i++) {
1689 var s = DATA[i];
1690 if (text.length != 0 &&
1691 s.label.toLowerCase().indexOf(text.toLowerCase()) != -1) {
1692 gMatches[matchedCount] = s;
1693 matchedCount++;
1694 }
1695 }
Scott Main7e447ed2013-02-19 17:22:37 -08001696 rank_autocomplete_results(text, gMatches);
Scott Mainf5089842012-08-14 16:31:07 -07001697 for (var i=0; i<gMatches.length; i++) {
1698 var s = gMatches[i];
Scott Main7e447ed2013-02-19 17:22:37 -08001699 }
1700
1701
1702 // Search for Google matches
1703 for (var i=0; i<GOOGLE_DATA.length; i++) {
1704 var s = GOOGLE_DATA[i];
1705 if (text.length != 0 &&
1706 s.label.toLowerCase().indexOf(text.toLowerCase()) != -1) {
1707 gGoogleMatches[matchedCountGoogle] = s;
1708 matchedCountGoogle++;
Scott Mainf5089842012-08-14 16:31:07 -07001709 }
1710 }
Scott Main7e447ed2013-02-19 17:22:37 -08001711 rank_autocomplete_results(text, gGoogleMatches);
1712 for (var i=0; i<gGoogleMatches.length; i++) {
1713 var s = gGoogleMatches[i];
1714 }
1715
Scott Mainf5089842012-08-14 16:31:07 -07001716 highlight_autocomplete_result_labels(text);
1717 sync_selection_table(toroot);
Scott Main7e447ed2013-02-19 17:22:37 -08001718
1719
Scott Mainf5089842012-08-14 16:31:07 -07001720 return true; // allow the event to bubble up to the search api
1721 }
1722}
1723
Scott Main7e447ed2013-02-19 17:22:37 -08001724/* Order the result list based on match quality */
1725function rank_autocomplete_results(query, matches) {
Scott Mainf5089842012-08-14 16:31:07 -07001726 query = query || '';
Scott Main7e447ed2013-02-19 17:22:37 -08001727 if (!matches || !matches.length)
Scott Mainf5089842012-08-14 16:31:07 -07001728 return;
1729
1730 // helper function that gets the last occurence index of the given regex
1731 // in the given string, or -1 if not found
1732 var _lastSearch = function(s, re) {
1733 if (s == '')
1734 return -1;
1735 var l = -1;
1736 var tmp;
1737 while ((tmp = s.search(re)) >= 0) {
1738 if (l < 0) l = 0;
1739 l += tmp;
1740 s = s.substr(tmp + 1);
1741 }
1742 return l;
1743 };
1744
1745 // helper function that counts the occurrences of a given character in
1746 // a given string
1747 var _countChar = function(s, c) {
1748 var n = 0;
1749 for (var i=0; i<s.length; i++)
1750 if (s.charAt(i) == c) ++n;
1751 return n;
1752 };
1753
1754 var queryLower = query.toLowerCase();
1755 var queryAlnum = (queryLower.match(/\w+/) || [''])[0];
1756 var partPrefixAlnumRE = new RegExp('\\b' + queryAlnum);
1757 var partExactAlnumRE = new RegExp('\\b' + queryAlnum + '\\b');
1758
1759 var _resultScoreFn = function(result) {
1760 // scores are calculated based on exact and prefix matches,
1761 // and then number of path separators (dots) from the last
1762 // match (i.e. favoring classes and deep package names)
1763 var score = 1.0;
1764 var labelLower = result.label.toLowerCase();
1765 var t;
1766 t = _lastSearch(labelLower, partExactAlnumRE);
1767 if (t >= 0) {
1768 // exact part match
1769 var partsAfter = _countChar(labelLower.substr(t + 1), '.');
1770 score *= 200 / (partsAfter + 1);
1771 } else {
1772 t = _lastSearch(labelLower, partPrefixAlnumRE);
1773 if (t >= 0) {
1774 // part prefix match
1775 var partsAfter = _countChar(labelLower.substr(t + 1), '.');
1776 score *= 20 / (partsAfter + 1);
1777 }
1778 }
1779
1780 return score;
1781 };
1782
Scott Main7e447ed2013-02-19 17:22:37 -08001783 for (var i=0; i<matches.length; i++) {
1784 matches[i].__resultScore = _resultScoreFn(matches[i]);
Scott Mainf5089842012-08-14 16:31:07 -07001785 }
1786
Scott Main7e447ed2013-02-19 17:22:37 -08001787 matches.sort(function(a,b){
Scott Mainf5089842012-08-14 16:31:07 -07001788 var n = b.__resultScore - a.__resultScore;
1789 if (n == 0) // lexicographical sort if scores are the same
1790 n = (a.label < b.label) ? -1 : 1;
1791 return n;
1792 });
1793}
1794
Scott Main7e447ed2013-02-19 17:22:37 -08001795/* Add emphasis to part of string that matches query */
Scott Mainf5089842012-08-14 16:31:07 -07001796function highlight_autocomplete_result_labels(query) {
1797 query = query || '';
Scott Main7e447ed2013-02-19 17:22:37 -08001798 if ((!gMatches || !gMatches.length) && (!gGoogleMatches || !gGoogleMatches.length))
Scott Mainf5089842012-08-14 16:31:07 -07001799 return;
1800
1801 var queryLower = query.toLowerCase();
1802 var queryAlnumDot = (queryLower.match(/[\w\.]+/) || [''])[0];
1803 var queryRE = new RegExp(
1804 '(' + queryAlnumDot.replace(/\./g, '\\.') + ')', 'ig');
1805 for (var i=0; i<gMatches.length; i++) {
1806 gMatches[i].__hilabel = gMatches[i].label.replace(
1807 queryRE, '<b>$1</b>');
1808 }
Scott Main7e447ed2013-02-19 17:22:37 -08001809 for (var i=0; i<gGoogleMatches.length; i++) {
1810 gGoogleMatches[i].__hilabel = gGoogleMatches[i].label.replace(
1811 queryRE, '<b>$1</b>');
1812 }
Scott Mainf5089842012-08-14 16:31:07 -07001813}
1814
1815function search_focus_changed(obj, focused)
1816{
1817 if (!focused) {
1818 if(obj.value == ""){
1819 $(".search .close").addClass("hide");
1820 }
1821 document.getElementById("search_filtered_div").className = "no-display";
1822 }
1823}
1824
1825function submit_search() {
1826 var query = document.getElementById('search_autocomplete').value;
1827 location.hash = 'q=' + query;
1828 loadSearchResults();
1829 $("#searchResults").slideDown('slow');
1830 return false;
1831}
1832
1833
1834function hideResults() {
1835 $("#searchResults").slideUp();
1836 $(".search .close").addClass("hide");
1837 location.hash = '';
1838
1839 $("#search_autocomplete").val("").blur();
1840
1841 // reset the ajax search callback to nothing, so results don't appear unless ENTER
1842 searchControl.setSearchStartingCallback(this, function(control, searcher, query) {});
1843 return false;
1844}
1845
1846
1847
1848/* ########################################################## */
1849/* ################ CUSTOM SEARCH ENGINE ################## */
1850/* ########################################################## */
1851
1852google.load('search', '1');
1853var searchControl;
1854
1855function loadSearchResults() {
1856 document.getElementById("search_autocomplete").style.color = "#000";
1857
1858 // create search control
1859 searchControl = new google.search.SearchControl();
1860
1861 // use our existing search form and use tabs when multiple searchers are used
1862 drawOptions = new google.search.DrawOptions();
1863 drawOptions.setDrawMode(google.search.SearchControl.DRAW_MODE_TABBED);
1864 drawOptions.setInput(document.getElementById("search_autocomplete"));
1865
1866 // configure search result options
1867 searchOptions = new google.search.SearcherOptions();
1868 searchOptions.setExpandMode(GSearchControl.EXPAND_MODE_OPEN);
1869
1870 // configure each of the searchers, for each tab
1871 devSiteSearcher = new google.search.WebSearch();
1872 devSiteSearcher.setUserDefinedLabel("All");
1873 devSiteSearcher.setSiteRestriction("001482626316274216503:zu90b7s047u");
1874
1875 designSearcher = new google.search.WebSearch();
1876 designSearcher.setUserDefinedLabel("Design");
1877 designSearcher.setSiteRestriction("http://developer.android.com/design/");
1878
1879 trainingSearcher = new google.search.WebSearch();
1880 trainingSearcher.setUserDefinedLabel("Training");
1881 trainingSearcher.setSiteRestriction("http://developer.android.com/training/");
1882
1883 guidesSearcher = new google.search.WebSearch();
1884 guidesSearcher.setUserDefinedLabel("Guides");
1885 guidesSearcher.setSiteRestriction("http://developer.android.com/guide/");
1886
1887 referenceSearcher = new google.search.WebSearch();
1888 referenceSearcher.setUserDefinedLabel("Reference");
1889 referenceSearcher.setSiteRestriction("http://developer.android.com/reference/");
1890
Scott Maindf08ada2012-12-03 08:54:37 -08001891 googleSearcher = new google.search.WebSearch();
1892 googleSearcher.setUserDefinedLabel("Google Services");
1893 googleSearcher.setSiteRestriction("http://developer.android.com/google/");
1894
Scott Mainf5089842012-08-14 16:31:07 -07001895 blogSearcher = new google.search.WebSearch();
1896 blogSearcher.setUserDefinedLabel("Blog");
1897 blogSearcher.setSiteRestriction("http://android-developers.blogspot.com");
1898
1899 // add each searcher to the search control
1900 searchControl.addSearcher(devSiteSearcher, searchOptions);
1901 searchControl.addSearcher(designSearcher, searchOptions);
1902 searchControl.addSearcher(trainingSearcher, searchOptions);
1903 searchControl.addSearcher(guidesSearcher, searchOptions);
1904 searchControl.addSearcher(referenceSearcher, searchOptions);
Scott Maindf08ada2012-12-03 08:54:37 -08001905 searchControl.addSearcher(googleSearcher, searchOptions);
Scott Mainf5089842012-08-14 16:31:07 -07001906 searchControl.addSearcher(blogSearcher, searchOptions);
1907
1908 // configure result options
1909 searchControl.setResultSetSize(google.search.Search.LARGE_RESULTSET);
1910 searchControl.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
1911 searchControl.setTimeoutInterval(google.search.SearchControl.TIMEOUT_SHORT);
1912 searchControl.setNoResultsString(google.search.SearchControl.NO_RESULTS_DEFAULT_STRING);
1913
1914 // upon ajax search, refresh the url and search title
1915 searchControl.setSearchStartingCallback(this, function(control, searcher, query) {
1916 updateResultTitle(query);
1917 var query = document.getElementById('search_autocomplete').value;
1918 location.hash = 'q=' + query;
1919 });
1920
Scott Mainde295272013-03-25 15:48:35 -07001921 // once search results load, set up click listeners
1922 searchControl.setSearchCompleteCallback(this, function(control, searcher, query) {
1923 addResultClickListeners();
1924 });
1925
Scott Mainf5089842012-08-14 16:31:07 -07001926 // draw the search results box
1927 searchControl.draw(document.getElementById("leftSearchControl"), drawOptions);
1928
1929 // get query and execute the search
1930 searchControl.execute(decodeURI(getQuery(location.hash)));
1931
1932 document.getElementById("search_autocomplete").focus();
1933 addTabListeners();
1934}
1935// End of loadSearchResults
1936
1937
1938google.setOnLoadCallback(function(){
1939 if (location.hash.indexOf("q=") == -1) {
1940 // if there's no query in the url, don't search and make sure results are hidden
1941 $('#searchResults').hide();
1942 return;
1943 } else {
1944 // first time loading search results for this page
1945 $('#searchResults').slideDown('slow');
1946 $(".search .close").removeClass("hide");
1947 loadSearchResults();
1948 }
1949}, true);
1950
1951// when an event on the browser history occurs (back, forward, load) requery hash and do search
1952$(window).hashchange( function(){
1953 // Exit if the hash isn't a search query or there's an error in the query
1954 if ((location.hash.indexOf("q=") == -1) || (query == "undefined")) {
1955 // If the results pane is open, close it.
1956 if (!$("#searchResults").is(":hidden")) {
1957 hideResults();
1958 }
1959 return;
1960 }
1961
1962 // Otherwise, we have a search to do
1963 var query = decodeURI(getQuery(location.hash));
1964 searchControl.execute(query);
1965 $('#searchResults').slideDown('slow');
1966 $("#search_autocomplete").focus();
1967 $(".search .close").removeClass("hide");
1968
1969 updateResultTitle(query);
1970});
1971
1972function updateResultTitle(query) {
1973 $("#searchTitle").html("Results for <em>" + escapeHTML(query) + "</em>");
1974}
1975
1976// forcefully regain key-up event control (previously jacked by search api)
1977$("#search_autocomplete").keyup(function(event) {
1978 return search_changed(event, false, toRoot);
1979});
1980
1981// add event listeners to each tab so we can track the browser history
1982function addTabListeners() {
1983 var tabHeaders = $(".gsc-tabHeader");
1984 for (var i = 0; i < tabHeaders.length; i++) {
1985 $(tabHeaders[i]).attr("id",i).click(function() {
1986 /*
1987 // make a copy of the page numbers for the search left pane
1988 setTimeout(function() {
1989 // remove any residual page numbers
1990 $('#searchResults .gsc-tabsArea .gsc-cursor-box.gs-bidi-start-align').remove();
1991 // move the page numbers to the left position; make a clone,
1992 // because the element is drawn to the DOM only once
1993 // and because we're going to remove it (previous line),
1994 // we need it to be available to move again as the user navigates
1995 $('#searchResults .gsc-webResult .gsc-cursor-box.gs-bidi-start-align:visible')
1996 .clone().appendTo('#searchResults .gsc-tabsArea');
1997 }, 200);
1998 */
1999 });
2000 }
2001 setTimeout(function(){$(tabHeaders[0]).click()},200);
2002}
2003
Scott Mainde295272013-03-25 15:48:35 -07002004// add analytics tracking events to each result link
2005function addResultClickListeners() {
2006 $("#searchResults a.gs-title").each(function(index, link) {
2007 // When user clicks enter for Google search results, track it
2008 $(link).click(function() {
2009 _gaq.push(['_trackEvent', 'Google Click', 'clicked: ' + $(this).text(),
2010 'from: ' + $("#search_autocomplete").val()]);
2011 });
2012 });
2013}
2014
Scott Mainf5089842012-08-14 16:31:07 -07002015
2016function getQuery(hash) {
2017 var queryParts = hash.split('=');
2018 return queryParts[1];
2019}
2020
2021/* returns the given string with all HTML brackets converted to entities
2022 TODO: move this to the site's JS library */
2023function escapeHTML(string) {
2024 return string.replace(/</g,"&lt;")
2025 .replace(/>/g,"&gt;");
2026}
2027
2028
2029
2030
2031
2032
2033
2034/* ######################################################## */
2035/* ################# JAVADOC REFERENCE ################### */
2036/* ######################################################## */
2037
Scott Main65511c02012-09-07 15:51:32 -07002038/* Initialize some droiddoc stuff, but only if we're in the reference */
Robert Ly67d75f12012-12-03 12:53:42 -08002039if (location.pathname.indexOf("/reference")) {
2040 if(!location.pathname.indexOf("/reference-gms/packages.html")
2041 && !location.pathname.indexOf("/reference-gcm/packages.html")
2042 && !location.pathname.indexOf("/reference/com/google") == 0) {
2043 $(document).ready(function() {
2044 // init available apis based on user pref
2045 changeApiLevel();
2046 initSidenavHeightResize()
2047 });
2048 }
Scott Main65511c02012-09-07 15:51:32 -07002049}
Scott Mainf5089842012-08-14 16:31:07 -07002050
2051var API_LEVEL_COOKIE = "api_level";
2052var minLevel = 1;
2053var maxLevel = 1;
2054
2055/******* SIDENAV DIMENSIONS ************/
2056
2057 function initSidenavHeightResize() {
2058 // Change the drag bar size to nicely fit the scrollbar positions
2059 var $dragBar = $(".ui-resizable-s");
2060 $dragBar.css({'width': $dragBar.parent().width() - 5 + "px"});
2061
2062 $( "#resize-packages-nav" ).resizable({
2063 containment: "#nav-panels",
2064 handles: "s",
2065 alsoResize: "#packages-nav",
2066 resize: function(event, ui) { resizeNav(); }, /* resize the nav while dragging */
2067 stop: function(event, ui) { saveNavPanels(); } /* once stopped, save the sizes to cookie */
2068 });
2069
2070 }
2071
2072function updateSidenavFixedWidth() {
2073 if (!navBarIsFixed) return;
2074 $('#devdoc-nav').css({
2075 'width' : $('#side-nav').css('width'),
2076 'margin' : $('#side-nav').css('margin')
2077 });
2078 $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'});
2079
2080 initSidenavHeightResize();
2081}
2082
2083function updateSidenavFullscreenWidth() {
2084 if (!navBarIsFixed) return;
2085 $('#devdoc-nav').css({
2086 'width' : $('#side-nav').css('width'),
2087 'margin' : $('#side-nav').css('margin')
2088 });
2089 $('#devdoc-nav .totop').css({'left': 'inherit'});
2090
2091 initSidenavHeightResize();
2092}
2093
2094function buildApiLevelSelector() {
2095 maxLevel = SINCE_DATA.length;
2096 var userApiLevel = parseInt(readCookie(API_LEVEL_COOKIE));
2097 userApiLevel = userApiLevel == 0 ? maxLevel : userApiLevel; // If there's no cookie (zero), use the max by default
2098
2099 minLevel = parseInt($("#doc-api-level").attr("class"));
2100 // Handle provisional api levels; the provisional level will always be the highest possible level
2101 // Provisional api levels will also have a length; other stuff that's just missing a level won't,
2102 // so leave those kinds of entities at the default level of 1 (for example, the R.styleable class)
2103 if (isNaN(minLevel) && minLevel.length) {
2104 minLevel = maxLevel;
2105 }
2106 var select = $("#apiLevelSelector").html("").change(changeApiLevel);
2107 for (var i = maxLevel-1; i >= 0; i--) {
2108 var option = $("<option />").attr("value",""+SINCE_DATA[i]).append(""+SINCE_DATA[i]);
2109 // if (SINCE_DATA[i] < minLevel) option.addClass("absent"); // always false for strings (codenames)
2110 select.append(option);
2111 }
2112
2113 // get the DOM element and use setAttribute cuz IE6 fails when using jquery .attr('selected',true)
2114 var selectedLevelItem = $("#apiLevelSelector option[value='"+userApiLevel+"']").get(0);
2115 selectedLevelItem.setAttribute('selected',true);
2116}
2117
2118function changeApiLevel() {
2119 maxLevel = SINCE_DATA.length;
2120 var selectedLevel = maxLevel;
2121
2122 selectedLevel = parseInt($("#apiLevelSelector option:selected").val());
2123 toggleVisisbleApis(selectedLevel, "body");
2124
2125 var date = new Date();
2126 date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
2127 var expiration = date.toGMTString();
2128 writeCookie(API_LEVEL_COOKIE, selectedLevel, null, expiration);
2129
2130 if (selectedLevel < minLevel) {
2131 var thing = ($("#jd-header").html().indexOf("package") != -1) ? "package" : "class";
Scott Main8f24ca82012-11-16 10:34:22 -08002132 $("#naMessage").show().html("<div><p><strong>This " + thing
2133 + " requires API level " + minLevel + " or higher.</strong></p>"
2134 + "<p>This document is hidden because your selected API level for the documentation is "
2135 + selectedLevel + ". You can change the documentation API level with the selector "
2136 + "above the left navigation.</p>"
2137 + "<p>For more information about specifying the API level your app requires, "
2138 + "read <a href='" + toRoot + "training/basics/supporting-devices/platforms.html'"
2139 + ">Supporting Different Platform Versions</a>.</p>"
2140 + "<input type='button' value='OK, make this page visible' "
2141 + "title='Change the API level to " + minLevel + "' "
2142 + "onclick='$(\"#apiLevelSelector\").val(\"" + minLevel + "\");changeApiLevel();' />"
2143 + "</div>");
Scott Mainf5089842012-08-14 16:31:07 -07002144 } else {
2145 $("#naMessage").hide();
2146 }
2147}
2148
2149function toggleVisisbleApis(selectedLevel, context) {
2150 var apis = $(".api",context);
2151 apis.each(function(i) {
2152 var obj = $(this);
2153 var className = obj.attr("class");
2154 var apiLevelIndex = className.lastIndexOf("-")+1;
2155 var apiLevelEndIndex = className.indexOf(" ", apiLevelIndex);
2156 apiLevelEndIndex = apiLevelEndIndex != -1 ? apiLevelEndIndex : className.length;
2157 var apiLevel = className.substring(apiLevelIndex, apiLevelEndIndex);
2158 if (apiLevel.length == 0) { // for odd cases when the since data is actually missing, just bail
2159 return;
2160 }
2161 apiLevel = parseInt(apiLevel);
2162
2163 // Handle provisional api levels; if this item's level is the provisional one, set it to the max
2164 var selectedLevelNum = parseInt(selectedLevel)
2165 var apiLevelNum = parseInt(apiLevel);
2166 if (isNaN(apiLevelNum)) {
2167 apiLevelNum = maxLevel;
2168 }
2169
2170 // Grey things out that aren't available and give a tooltip title
2171 if (apiLevelNum > selectedLevelNum) {
2172 obj.addClass("absent").attr("title","Requires API Level \""
2173 + apiLevel + "\" or higher");
2174 }
2175 else obj.removeClass("absent").removeAttr("title");
2176 });
2177}
2178
2179
2180
2181
2182/* ################# SIDENAV TREE VIEW ################### */
2183
2184function new_node(me, mom, text, link, children_data, api_level)
2185{
2186 var node = new Object();
2187 node.children = Array();
2188 node.children_data = children_data;
2189 node.depth = mom.depth + 1;
2190
2191 node.li = document.createElement("li");
2192 mom.get_children_ul().appendChild(node.li);
2193
2194 node.label_div = document.createElement("div");
2195 node.label_div.className = "label";
2196 if (api_level != null) {
2197 $(node.label_div).addClass("api");
2198 $(node.label_div).addClass("api-level-"+api_level);
2199 }
2200 node.li.appendChild(node.label_div);
2201
2202 if (children_data != null) {
2203 node.expand_toggle = document.createElement("a");
2204 node.expand_toggle.href = "javascript:void(0)";
2205 node.expand_toggle.onclick = function() {
2206 if (node.expanded) {
2207 $(node.get_children_ul()).slideUp("fast");
2208 node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
2209 node.expanded = false;
2210 } else {
2211 expand_node(me, node);
2212 }
2213 };
2214 node.label_div.appendChild(node.expand_toggle);
2215
2216 node.plus_img = document.createElement("img");
2217 node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
2218 node.plus_img.className = "plus";
2219 node.plus_img.width = "8";
2220 node.plus_img.border = "0";
2221 node.expand_toggle.appendChild(node.plus_img);
2222
2223 node.expanded = false;
2224 }
2225
2226 var a = document.createElement("a");
2227 node.label_div.appendChild(a);
2228 node.label = document.createTextNode(text);
2229 a.appendChild(node.label);
2230 if (link) {
2231 a.href = me.toroot + link;
2232 } else {
2233 if (children_data != null) {
2234 a.className = "nolink";
2235 a.href = "javascript:void(0)";
2236 a.onclick = node.expand_toggle.onclick;
2237 // This next line shouldn't be necessary. I'll buy a beer for the first
2238 // person who figures out how to remove this line and have the link
2239 // toggle shut on the first try. --joeo@android.com
2240 node.expanded = false;
2241 }
2242 }
2243
2244
2245 node.children_ul = null;
2246 node.get_children_ul = function() {
2247 if (!node.children_ul) {
2248 node.children_ul = document.createElement("ul");
2249 node.children_ul.className = "children_ul";
2250 node.children_ul.style.display = "none";
2251 node.li.appendChild(node.children_ul);
2252 }
2253 return node.children_ul;
2254 };
2255
2256 return node;
2257}
2258
Robert Lyd2dd6e52012-11-29 21:28:48 -08002259
2260
2261
Scott Mainf5089842012-08-14 16:31:07 -07002262function expand_node(me, node)
2263{
2264 if (node.children_data && !node.expanded) {
2265 if (node.children_visited) {
2266 $(node.get_children_ul()).slideDown("fast");
2267 } else {
2268 get_node(me, node);
2269 if ($(node.label_div).hasClass("absent")) {
2270 $(node.get_children_ul()).addClass("absent");
2271 }
2272 $(node.get_children_ul()).slideDown("fast");
2273 }
2274 node.plus_img.src = me.toroot + "assets/images/triangle-opened-small.png";
2275 node.expanded = true;
2276
2277 // perform api level toggling because new nodes are new to the DOM
2278 var selectedLevel = $("#apiLevelSelector option:selected").val();
2279 toggleVisisbleApis(selectedLevel, "#side-nav");
2280 }
2281}
2282
2283function get_node(me, mom)
2284{
2285 mom.children_visited = true;
2286 for (var i in mom.children_data) {
2287 var node_data = mom.children_data[i];
2288 mom.children[i] = new_node(me, mom, node_data[0], node_data[1],
2289 node_data[2], node_data[3]);
2290 }
2291}
2292
2293function this_page_relative(toroot)
2294{
2295 var full = document.location.pathname;
2296 var file = "";
2297 if (toroot.substr(0, 1) == "/") {
2298 if (full.substr(0, toroot.length) == toroot) {
2299 return full.substr(toroot.length);
2300 } else {
2301 // the file isn't under toroot. Fail.
2302 return null;
2303 }
2304 } else {
2305 if (toroot != "./") {
2306 toroot = "./" + toroot;
2307 }
2308 do {
2309 if (toroot.substr(toroot.length-3, 3) == "../" || toroot == "./") {
2310 var pos = full.lastIndexOf("/");
2311 file = full.substr(pos) + file;
2312 full = full.substr(0, pos);
2313 toroot = toroot.substr(0, toroot.length-3);
2314 }
2315 } while (toroot != "" && toroot != "/");
2316 return file.substr(1);
2317 }
2318}
2319
2320function find_page(url, data)
2321{
2322 var nodes = data;
2323 var result = null;
2324 for (var i in nodes) {
2325 var d = nodes[i];
2326 if (d[1] == url) {
2327 return new Array(i);
2328 }
2329 else if (d[2] != null) {
2330 result = find_page(url, d[2]);
2331 if (result != null) {
2332 return (new Array(i).concat(result));
2333 }
2334 }
2335 }
2336 return null;
2337}
2338
Scott Mainf5089842012-08-14 16:31:07 -07002339function init_default_navtree(toroot) {
Scott Main25e73002013-03-27 15:24:06 -07002340 // load json file for navtree data
2341 $.getScript(toRoot + 'navtree_data.js', function(data, textStatus, jqxhr) {
2342 // when the file is loaded, initialize the tree
2343 if(jqxhr.status === 200) {
2344 init_navtree("tree-list", toroot, NAVTREE_DATA);
2345 }
2346 });
Scott Mainf5089842012-08-14 16:31:07 -07002347
2348 // perform api level toggling because because the whole tree is new to the DOM
2349 var selectedLevel = $("#apiLevelSelector option:selected").val();
2350 toggleVisisbleApis(selectedLevel, "#side-nav");
2351}
2352
2353function init_navtree(navtree_id, toroot, root_nodes)
2354{
2355 var me = new Object();
2356 me.toroot = toroot;
2357 me.node = new Object();
2358
2359 me.node.li = document.getElementById(navtree_id);
2360 me.node.children_data = root_nodes;
2361 me.node.children = new Array();
2362 me.node.children_ul = document.createElement("ul");
2363 me.node.get_children_ul = function() { return me.node.children_ul; };
2364 //me.node.children_ul.className = "children_ul";
2365 me.node.li.appendChild(me.node.children_ul);
2366 me.node.depth = 0;
2367
2368 get_node(me, me.node);
2369
2370 me.this_page = this_page_relative(toroot);
2371 me.breadcrumbs = find_page(me.this_page, root_nodes);
2372 if (me.breadcrumbs != null && me.breadcrumbs.length != 0) {
2373 var mom = me.node;
2374 for (var i in me.breadcrumbs) {
2375 var j = me.breadcrumbs[i];
2376 mom = mom.children[j];
2377 expand_node(me, mom);
2378 }
2379 mom.label_div.className = mom.label_div.className + " selected";
2380 addLoadEvent(function() {
2381 scrollIntoView("nav-tree");
2382 });
2383 }
2384}
2385
Robert Lyd2dd6e52012-11-29 21:28:48 -08002386/* TODO: eliminate redundancy with non-google functions */
2387function init_google_navtree(navtree_id, toroot, root_nodes)
2388{
2389 var me = new Object();
2390 me.toroot = toroot;
2391 me.node = new Object();
2392
2393 me.node.li = document.getElementById(navtree_id);
2394 me.node.children_data = root_nodes;
2395 me.node.children = new Array();
2396 me.node.children_ul = document.createElement("ul");
2397 me.node.get_children_ul = function() { return me.node.children_ul; };
2398 //me.node.children_ul.className = "children_ul";
2399 me.node.li.appendChild(me.node.children_ul);
2400 me.node.depth = 0;
2401
2402 get_google_node(me, me.node);
Robert Lyd2dd6e52012-11-29 21:28:48 -08002403}
2404
2405function new_google_node(me, mom, text, link, children_data, api_level)
2406{
2407 var node = new Object();
2408 var child;
2409 node.children = Array();
2410 node.children_data = children_data;
2411 node.depth = mom.depth + 1;
2412 node.get_children_ul = function() {
2413 if (!node.children_ul) {
Scott Mainac71b2b2012-11-30 14:40:58 -08002414 node.children_ul = document.createElement("ul");
2415 node.children_ul.className = "tree-list-children";
Robert Lyd2dd6e52012-11-29 21:28:48 -08002416 node.li.appendChild(node.children_ul);
2417 }
2418 return node.children_ul;
2419 };
2420 node.li = document.createElement("li");
2421
2422 mom.get_children_ul().appendChild(node.li);
2423
2424
2425 if(link) {
2426 child = document.createElement("a");
2427
2428 }
2429 else {
2430 child = document.createElement("span");
Scott Mainac71b2b2012-11-30 14:40:58 -08002431 child.className = "tree-list-subtitle";
Robert Lyd2dd6e52012-11-29 21:28:48 -08002432
2433 }
2434 if (children_data != null) {
2435 node.li.className="nav-section";
2436 node.label_div = document.createElement("div");
2437 node.label_div.className = "nav-section-header-ref";
2438 node.li.appendChild(node.label_div);
2439 get_google_node(me, node);
2440 node.label_div.appendChild(child);
2441 }
2442 else {
2443 node.li.appendChild(child);
2444 }
2445 if(link) {
2446 child.href = me.toroot + link;
2447 }
2448 node.label = document.createTextNode(text);
2449 child.appendChild(node.label);
2450
2451 node.children_ul = null;
2452
2453 return node;
2454}
2455
2456function get_google_node(me, mom)
2457{
2458 mom.children_visited = true;
2459 var linkText;
2460 for (var i in mom.children_data) {
2461 var node_data = mom.children_data[i];
2462 linkText = node_data[0];
2463
2464 if(linkText.match("^"+"com.google.android")=="com.google.android"){
2465 linkText = linkText.substr(19, linkText.length);
2466 }
2467 mom.children[i] = new_google_node(me, mom, linkText, node_data[1],
2468 node_data[2], node_data[3]);
2469 }
2470}
2471function showGoogleRefTree() {
2472 init_default_google_navtree(toRoot);
2473 init_default_gcm_navtree(toRoot);
Robert Lyd2dd6e52012-11-29 21:28:48 -08002474}
2475
2476function init_default_google_navtree(toroot) {
Scott Mainf6145542013-04-01 16:38:11 -07002477 // load json file for navtree data
2478 $.getScript(toRoot + 'gms_navtree_data.js', function(data, textStatus, jqxhr) {
2479 // when the file is loaded, initialize the tree
2480 if(jqxhr.status === 200) {
2481 init_google_navtree("gms-tree-list", toroot, GMS_NAVTREE_DATA);
2482 highlightSidenav();
2483 resizeNav();
2484 }
2485 });
Robert Lyd2dd6e52012-11-29 21:28:48 -08002486}
2487
2488function init_default_gcm_navtree(toroot) {
Scott Mainf6145542013-04-01 16:38:11 -07002489 // load json file for navtree data
2490 $.getScript(toRoot + 'gcm_navtree_data.js', function(data, textStatus, jqxhr) {
2491 // when the file is loaded, initialize the tree
2492 if(jqxhr.status === 200) {
2493 init_google_navtree("gcm-tree-list", toroot, GCM_NAVTREE_DATA);
2494 highlightSidenav();
2495 resizeNav();
2496 }
2497 });
Robert Lyd2dd6e52012-11-29 21:28:48 -08002498}
2499
Scott Mainf5089842012-08-14 16:31:07 -07002500/* TOGGLE INHERITED MEMBERS */
2501
2502/* Toggle an inherited class (arrow toggle)
2503 * @param linkObj The link that was clicked.
2504 * @param expand 'true' to ensure it's expanded. 'false' to ensure it's closed.
2505 * 'null' to simply toggle.
2506 */
2507function toggleInherited(linkObj, expand) {
2508 var base = linkObj.getAttribute("id");
2509 var list = document.getElementById(base + "-list");
2510 var summary = document.getElementById(base + "-summary");
2511 var trigger = document.getElementById(base + "-trigger");
2512 var a = $(linkObj);
2513 if ( (expand == null && a.hasClass("closed")) || expand ) {
2514 list.style.display = "none";
2515 summary.style.display = "block";
2516 trigger.src = toRoot + "assets/images/triangle-opened.png";
2517 a.removeClass("closed");
2518 a.addClass("opened");
2519 } else if ( (expand == null && a.hasClass("opened")) || (expand == false) ) {
2520 list.style.display = "block";
2521 summary.style.display = "none";
2522 trigger.src = toRoot + "assets/images/triangle-closed.png";
2523 a.removeClass("opened");
2524 a.addClass("closed");
2525 }
2526 return false;
2527}
2528
2529/* Toggle all inherited classes in a single table (e.g. all inherited methods)
2530 * @param linkObj The link that was clicked.
2531 * @param expand 'true' to ensure it's expanded. 'false' to ensure it's closed.
2532 * 'null' to simply toggle.
2533 */
2534function toggleAllInherited(linkObj, expand) {
2535 var a = $(linkObj);
2536 var table = $(a.parent().parent().parent()); // ugly way to get table/tbody
2537 var expandos = $(".jd-expando-trigger", table);
2538 if ( (expand == null && a.text() == "[Expand]") || expand ) {
2539 expandos.each(function(i) {
2540 toggleInherited(this, true);
2541 });
2542 a.text("[Collapse]");
2543 } else if ( (expand == null && a.text() == "[Collapse]") || (expand == false) ) {
2544 expandos.each(function(i) {
2545 toggleInherited(this, false);
2546 });
2547 a.text("[Expand]");
2548 }
2549 return false;
2550}
2551
2552/* Toggle all inherited members in the class (link in the class title)
2553 */
2554function toggleAllClassInherited() {
2555 var a = $("#toggleAllClassInherited"); // get toggle link from class title
2556 var toggles = $(".toggle-all", $("#body-content"));
2557 if (a.text() == "[Expand All]") {
2558 toggles.each(function(i) {
2559 toggleAllInherited(this, true);
2560 });
2561 a.text("[Collapse All]");
2562 } else {
2563 toggles.each(function(i) {
2564 toggleAllInherited(this, false);
2565 });
2566 a.text("[Expand All]");
2567 }
2568 return false;
2569}
2570
2571/* Expand all inherited members in the class. Used when initiating page search */
2572function ensureAllInheritedExpanded() {
2573 var toggles = $(".toggle-all", $("#body-content"));
2574 toggles.each(function(i) {
2575 toggleAllInherited(this, true);
2576 });
2577 $("#toggleAllClassInherited").text("[Collapse All]");
2578}
2579
2580
2581/* HANDLE KEY EVENTS
2582 * - Listen for Ctrl+F (Cmd on Mac) and expand all inherited members (to aid page search)
2583 */
2584var agent = navigator['userAgent'].toLowerCase();
2585var mac = agent.indexOf("macintosh") != -1;
2586
2587$(document).keydown( function(e) {
2588var control = mac ? e.metaKey && !e.ctrlKey : e.ctrlKey; // get ctrl key
2589 if (control && e.which == 70) { // 70 is "F"
2590 ensureAllInheritedExpanded();
2591 }
2592});