1 var navBarIsFixed = false; 2 $(document).ready(function() { 3 // init the fullscreen toggle click event 4 $('#nav-swap .fullscreen').click(function(){ 5 if ($(this).hasClass('disabled')) { 6 toggleFullscreen(true); 7 } else { 8 toggleFullscreen(false); 9 } 10 }); 11 12 // initialize the divs with custom scrollbars 13 $('.scroll-pane').jScrollPane( {verticalGutter:0} ); 14 15 // add HRs below all H2s (except for a few other h2 variants) 16 $('h2').not('#qv h2').not('#tb h2').not('#devdoc-nav h2').css({marginBottom:0}).after('<hr/>'); 17 18 // set search's onkeyup handler here so we can show suggestions even while search results are visible 19 $("#search_autocomplete").keyup(function() {return search_changed(event, false, '/')}); 20 21 // set up the search close button 22 $('.search .close').click(function() { 23 $searchInput = $('#search_autocomplete'); 24 $searchInput.attr('value', ''); 25 $(this).addClass("hide"); 26 $("#search-container").removeClass('active'); 27 $("#search_autocomplete").blur(); 28 search_focus_changed($searchInput.get(), false); // see search_autocomplete.js 29 hideResults(); // see search_autocomplete.js 30 }); 31 $('.search').click(function() { 32 if (!$('#search_autocomplete').is(":focused")) { 33 $('#search_autocomplete').focus(); 34 } 35 }); 36 37 // Set up quicknav 38 var quicknav_open = false; 39 $("#btn-quicknav").click(function() { 40 if (quicknav_open) { 41 $(this).removeClass('active'); 42 quicknav_open = false; 43 collapse(); 44 } else { 45 $(this).addClass('active'); 46 quicknav_open = true; 47 expand(); 48 } 49 }) 50 51 var expand = function() { 52 $('#header-wrap').addClass('quicknav'); 53 $('#quicknav').stop().show().animate({opacity:'1'}); 54 } 55 56 var collapse = function() { 57 $('#quicknav').stop().animate({opacity:'0'}, 100, function() { 58 $(this).hide(); 59 $('#header-wrap').removeClass('quicknav'); 60 }); 61 } 62 63 64 //Set up search 65 $("#search_autocomplete").focus(function() { 66 $("#search-container").addClass('active'); 67 }) 68 $("#search-container").mouseover(function() { 69 $("#search-container").addClass('active'); 70 $("#search_autocomplete").focus(); 71 }) 72 $("#search-container").mouseout(function() { 73 if ($("#search_autocomplete").is(":focus")) return; 74 if ($("#search_autocomplete").val() == '') { 75 setTimeout(function(){ 76 $("#search-container").removeClass('active'); 77 $("#search_autocomplete").blur(); 78 },250); 79 } 80 }) 81 $("#search_autocomplete").blur(function() { 82 if ($("#search_autocomplete").val() == '') { 83 $("#search-container").removeClass('active'); 84 } 85 }) 86 87 88 // prep nav expandos 89 var pagePath = document.location.pathname; 90 // account for intl docs by removing the intl/*/ path 91 if (pagePath.indexOf("/intl/") == 0) { 92 pagePath = pagePath.substr(pagePath.indexOf("/",6)); // start after intl/ to get last / 93 } 94 95 if (pagePath.indexOf(SITE_ROOT) == 0) { 96 if (pagePath == '' || pagePath.charAt(pagePath.length - 1) == '/') { 97 pagePath += 'index.html'; 98 } 99 } 100 101 if (SITE_ROOT.match(/\.\.\//) || SITE_ROOT == '') { 102 // If running locally, SITE_ROOT will be a relative path, so account for that by 103 // finding the relative URL to this page. This will allow us to find links on the page 104 // leading back to this page. 105 var pathParts = pagePath.split('/'); 106 var relativePagePathParts = []; 107 var upDirs = (SITE_ROOT.match(/(\.\.\/)+/) || [''])[0].length / 3; 108 for (var i = 0; i < upDirs; i++) { 109 relativePagePathParts.push('..'); 110 } 111 for (var i = 0; i < upDirs; i++) { 112 relativePagePathParts.push(pathParts[pathParts.length - (upDirs - i) - 1]); 113 } 114 relativePagePathParts.push(pathParts[pathParts.length - 1]); 115 pagePath = relativePagePathParts.join('/'); 116 } else { 117 // Otherwise the page path is already an absolute URL 118 } 119 120 // select current page in sidenav and set up prev/next links if they exist 121 var $selNavLink = $('#nav').find('a[href="' + pagePath + '"]'); 122 if ($selNavLink.length) { 123 $selListItem = $selNavLink.closest('li'); 124 125 $selListItem.addClass('selected'); 126 $selListItem.closest('li.nav-section').addClass('expanded'); 127 $selListItem.closest('li.nav-section').children('ul').show(); 128 $selListItem.closest('li.nav-section').parent().closest('li.nav-section').addClass('expanded'); 129 $selListItem.closest('li.nav-section').parent().closest('ul').show(); 130 131 132 // $selListItem.closest('li.nav-section').closest('li.nav-section').addClass('expanded'); 133 // $selListItem.closest('li.nav-section').closest('li.nav-section').children('ul').show(); 134 135 // set up prev links 136 var $prevLink = []; 137 var $prevListItem = $selListItem.prev('li'); 138 139 var crossBoundaries = ($("body.design").length > 0) || ($("body.guide").length > 0) ? true : false; // navigate across topic boundaries only in design docs 140 if ($prevListItem.length) { 141 if ($prevListItem.hasClass('nav-section')) { 142 if (crossBoundaries) { 143 // jump to last topic of previous section 144 $prevLink = $prevListItem.find('a:last'); 145 } 146 } else { 147 // jump to previous topic in this section 148 $prevLink = $prevListItem.find('a:eq(0)'); 149 } 150 } else { 151 // jump to this section's index page (if it exists) 152 var $parentListItem = $selListItem.parents('li'); 153 $prevLink = $selListItem.parents('li').find('a'); 154 155 // except if cross boundaries aren't allowed, and we're at the top of a section already (and there's another parent) 156 if (!crossBoundaries && $parentListItem.hasClass('nav-section') && $selListItem.hasClass('nav-section')) { 157 $prevLink = []; 158 } 159 } 160 161 if ($prevLink.length) { 162 var prevHref = $prevLink.attr('href'); 163 if (prevHref == SITE_ROOT + 'index.html') { 164 // Don't show Previous when it leads to the homepage 165 } else { 166 $('.prev-page-link').attr('href', $prevLink.attr('href')).removeClass("hide"); 167 } 168 } 169 170 // set up next links 171 var $nextLink = []; 172 var startCourse = false; 173 var startClass = false; 174 var training = $(".next-class-link").length; // decides whether to provide "next class" link 175 var isCrossingBoundary = false; 176 177 if ($selListItem.hasClass('nav-section')) { 178 // we're on an index page, jump to the first topic 179 $nextLink = $selListItem.find('ul').find('a:eq(0)'); 180 181 // if there aren't any children, go to the next section (required for About pages) 182 if($nextLink.length == 0) { 183 $nextLink = $selListItem.next('li').find('a'); 184 } 185 186 // Handle some Training specialties 187 if ($selListItem.parent().is("#nav") && $(".start-course-link").length) { 188 // this means we're at the very top of the TOC hierarchy 189 startCourse = true; 190 } else if ($(".start-class-link").length) { 191 // this means this page has children but is not at the top (it's a class, not a course) 192 startClass = true; 193 } 194 } else { 195 // jump to the next topic in this section (if it exists) 196 $nextLink = $selListItem.next('li').find('a:eq(0)'); 197 if (!$nextLink.length) { 198 if (crossBoundaries || training) { 199 // no more topics in this section, jump to the first topic in the next section 200 $nextLink = $selListItem.parents('li:eq(0)').next('li.nav-section').find('a:eq(0)'); 201 isCrossingBoundary = true; 202 } 203 } 204 } 205 if ($nextLink.length) { 206 if (startCourse || startClass) { 207 if (startCourse) { 208 $('.start-course-link').attr('href', $nextLink.attr('href')).removeClass("hide"); 209 } else { 210 $('.start-class-link').attr('href', $nextLink.attr('href')).removeClass("hide"); 211 } 212 // if there's no training bar (below the start button), then we need to add a bottom border to button 213 if (!$("#tb").length) { 214 $('.start-course-link').css({'border-bottom':'1px solid #DADADA'}); 215 $('.start-class-link').css({'border-bottom':'1px solid #DADADA'}); 216 } 217 } else if (training && isCrossingBoundary) { 218 $('.content-footer.next-class').show(); 219 $('.next-page-link').attr('href','').removeClass("hide").addClass("disabled").click(function() { 220 return false; 221 }); 222 $('.next-class-link').attr('href',$nextLink.attr('href')).removeClass("hide").append($nextLink.html()); 223 $('.next-class-link').find('.new').empty(); 224 } else { 225 $('.next-page-link').attr('href', $nextLink.attr('href')).removeClass("hide"); 226 } 227 } 228 229 } 230 231 232 233 // Set up expand/collapse behavior 234 $('#nav li.nav-section .nav-section-header').click(function() { 235 var section = $(this).closest('li.nav-section'); 236 if (section.hasClass('expanded')) { 237 /* hide me */ 238 // if (section.hasClass('selected') || section.find('li').hasClass('selected')) { 239 // /* but not if myself or my descendents are selected */ 240 // return; 241 // } 242 section.children('ul').slideUp(250, function() { 243 section.closest('li').removeClass('expanded'); 244 resizeNav(); 245 }); 246 } else { 247 /* show me */ 248 // first hide all other siblings 249 var $others = $('li.nav-section.expanded', $(this).closest('ul')); 250 $others.removeClass('expanded').children('ul').slideUp(250); 251 252 // now expand me 253 section.closest('li').addClass('expanded'); 254 section.children('ul').slideDown(250, function() { 255 resizeNav(); 256 }); 257 } 258 }); 259 260 $(".scroll-pane").scroll(function(event) { 261 event.preventDefault(); 262 return false; 263 }); 264 265 /* Resize nav height when window height changes */ 266 $(window).resize(function() { 267 var stylesheet = $('link[rel="stylesheet"][title="fullscreen"]'); 268 setNavBarLeftPos(); // do this even if sidenav isn't fixed because it could become fixed 269 // make sidenav behave when resizing the window and side-scolling is a concern 270 if (navBarIsFixed) { 271 if ((stylesheet.attr("disabled") == "disabled") || stylesheet.length == 0) { 272 updateSideNavPosition(); 273 } else { 274 updateSidenavFullscreenWidth(); 275 } 276 } 277 resizeNav(); 278 }); 279 280 281 // Set up fixed navbar 282 var prevScrollLeft = 0; // used to compare current position to previous position of horiz scroll 283 $(window).scroll(function(event) { 284 if (event.target.nodeName == "DIV") { 285 // Dump scroll event if the target is a DIV, because that means the event is coming 286 // from a scrollable div and so there's no need to make adjustments to our layout 287 return; 288 } 289 var scrollTop = $(window).scrollTop(); 290 var headerHeight = $('#header').outerHeight(); 291 var subheaderHeight = $('#nav-x').outerHeight(); 292 var searchResultHeight = $('#searchResults').is(":visible") ? $('#searchResults').outerHeight() : 0; 293 var totalHeaderHeight = headerHeight + subheaderHeight + searchResultHeight; 294 var navBarShouldBeFixed = scrollTop > totalHeaderHeight; 295 296 var scrollLeft = $(window).scrollLeft(); 297 // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match 298 if (navBarIsFixed && (scrollLeft != prevScrollLeft)) { 299 updateSideNavPosition(); 300 prevScrollLeft = scrollLeft; 301 } 302 303 // Don't continue if the header is sufficently far away (to avoid intensive resizing that slows scrolling) 304 if (navBarIsFixed && navBarShouldBeFixed) { 305 return; 306 } 307 308 if (navBarIsFixed != navBarShouldBeFixed) { 309 if (navBarShouldBeFixed) { 310 // make it fixed 311 var width = $('#devdoc-nav').width(); 312 var margin = $('#devdoc-nav').parent().css('margin'); 313 $('#devdoc-nav') 314 .addClass('fixed') 315 .css({'width':width+'px','margin':margin}) 316 .prependTo('#body-content'); 317 // add neato "back to top" button 318 $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'}); 319 320 // update the sidenaav position for side scrolling 321 updateSideNavPosition(); 322 } else { 323 // make it static again 324 $('#devdoc-nav') 325 .removeClass('fixed') 326 .css({'width':'auto','margin':''}) 327 .prependTo('#side-nav'); 328 $('#devdoc-nav a.totop').hide(); 329 } 330 navBarIsFixed = navBarShouldBeFixed; 331 } 332 333 resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance reasons 334 }); 335 336 337 var navBarLeftPos; 338 if ($('#devdoc-nav').length) { 339 setNavBarLeftPos(); 340 } 341 342 343 // Stop expand/collapse behavior when clicking on nav section links (since we're navigating away 344 // from the page) 345 $('.nav-section-header').find('a:eq(0)').click(function(evt) { 346 window.location.href = $(this).attr('href'); 347 return false; 348 }); 349 350 // Set up play-on-hover <video> tags. 351 $('video.play-on-hover').bind('click', function(){ 352 $(this).get(0).load(); // in case the video isn't seekable 353 $(this).get(0).play(); 354 }); 355 356 // Set up tooltips 357 var TOOLTIP_MARGIN = 10; 358 $('acronym').each(function() { 359 var $target = $(this); 360 var $tooltip = $('<div>') 361 .addClass('tooltip-box') 362 .text($target.attr('title')) 363 .hide() 364 .appendTo('body'); 365 $target.removeAttr('title'); 366 367 $target.hover(function() { 368 // in 369 var targetRect = $target.offset(); 370 targetRect.width = $target.width(); 371 targetRect.height = $target.height(); 372 373 $tooltip.css({ 374 left: targetRect.left, 375 top: targetRect.top + targetRect.height + TOOLTIP_MARGIN 376 }); 377 $tooltip.addClass('below'); 378 $tooltip.show(); 379 }, function() { 380 // out 381 $tooltip.hide(); 382 }); 383 }); 384 385 // Set up <h2> deeplinks 386 $('h2').click(function() { 387 var id = $(this).attr('id'); 388 if (id) { 389 document.location.hash = id; 390 } 391 }); 392 393 //Loads the +1 button 394 var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; 395 po.src = 'https://apis.google.com/js/plusone.js'; 396 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); 397 398 399 // Revise the sidenav widths to make room for the scrollbar 400 // which avoids the visible width from changing each time the bar appears 401 var $sidenav = $("#side-nav"); 402 var sidenav_width = parseInt($sidenav.innerWidth()); 403 404 $("#devdoc-nav #nav").css("width", sidenav_width - 4 + "px"); // 4px is scrollbar width 405 406 407 $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller 408 409 if ($(".scroll-pane").length > 1) { 410 // Check if there's a user preference for the panel heights 411 var cookieHeight = readCookie("reference_height"); 412 if (cookieHeight) { 413 restoreHeight(cookieHeight); 414 } 415 } 416 417 resizeNav(); 418 419 420 }); 421 422 423 424 function toggleFullscreen(enable) { 425 var delay = 20; 426 var enabled = false; 427 var stylesheet = $('link[rel="stylesheet"][title="fullscreen"]'); 428 if (enable) { 429 // Currently NOT USING fullscreen; enable fullscreen 430 stylesheet.removeAttr('disabled'); 431 $('#nav-swap .fullscreen').removeClass('disabled'); 432 $('#devdoc-nav').css({left:''}); 433 setTimeout(updateSidenavFullscreenWidth,delay); // need to wait a moment for css to switch 434 enabled = true; 435 } else { 436 // Currently USING fullscreen; disable fullscreen 437 stylesheet.attr('disabled', 'disabled'); 438 $('#nav-swap .fullscreen').addClass('disabled'); 439 setTimeout(updateSidenavFixedWidth,delay); // need to wait a moment for css to switch 440 enabled = false; 441 } 442 writeCookie("fullscreen", enabled, null, null); 443 setNavBarLeftPos(); 444 resizeNav(delay); 445 setTimeout(initSidenavHeightResize,delay); 446 } 447 448 449 function setNavBarLeftPos() { 450 navBarLeftPos = $('#body-content').offset().left; 451 } 452 453 454 function updateSideNavPosition() { 455 var newLeft = $(window).scrollLeft() - navBarLeftPos; 456 $('#devdoc-nav').css({left: -newLeft}); 457 $('#devdoc-nav .totop').css({left: -(newLeft - parseInt($('#side-nav').css('margin-left')))}); 458 } 459