1/* 2 * Copyright 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17$(document).ready(function() { 18 prettyPrint(); 19 preventParentScrolls('nav'); 20 21 var sluggify_ = function(s) { 22 return (s || '').replace(/ /g, '-').replace(/[^\w-]/g, '').toLowerCase(); 23 }; 24 25 $('h2, h3, h4.includetoc').each(function() { 26 $(this).attr('id', 'toc_' + sluggify_($(this).data('tocid') || $(this).data('toctitle') || $(this).text())); 27 $(this).click(function() { 28 smoothScrollToId($(this).attr('id')); 29 }); 30 }); 31 32 var buildNav_ = function(queries, $contentRoot, $navRoot) { 33 if (!queries || !queries.length) { 34 return; 35 } 36 37 $contentRoot.find(queries[0]).each(function() { 38 var $navNode = $('<div>') 39 .text($(this).html()) 40 .appendTo($navRoot); 41 buildNav_(queries.splice(1), $(this), $navNode); 42 }); 43 }; 44 45 buildNav(); 46}); 47 48function buildNav() { 49 var currentLevel = 2; 50 var $currentParent = $('nav'); 51 var $currentNode = null; 52 53 $('#page-content').find('h2, h3, h4.includetoc').each(function() { 54 var level = $(this).get(0).tagName.substring(1); 55 56 if (level < currentLevel) { 57 // ascend 58 for (var i = 0; i < (currentLevel - level); i++) { 59 $currentParent = $currentParent.parents('div.children, nav').first(); 60 } 61 62 } else if (level > currentLevel) { 63 // descend 64 $currentParent = $('<div>') 65 .addClass('children') 66 .appendTo($currentNode); 67 } 68 69 var tocId = $(this).attr('id'); 70 var navId = tocId.replace(/toc_/, 'nav_'); 71 72 $interactionNode = $('<span>') 73 .html($(this).data('toctitle') || $(this).html()) 74 .data('target', tocId) 75 .click(function() { 76 smoothScrollToId($(this).data('target')); 77 }); 78 79 $currentNode = $('<div>') 80 .attr('id', navId) 81 .addClass('item') 82 .append($interactionNode) 83 .appendTo($currentParent); 84 85 currentLevel = level; 86 }); 87 88 var headerPositionCache = []; 89 var rebuildHeaderPositionCache_ = function() { 90 headerPositionCache = []; 91 $('#page-content').find('h2, h3, h4.includetoc').each(function() { 92 headerPositionCache.push({ 93 id: $(this).attr('id').replace(/toc_/, 'nav_'), 94 top: $(this).offset().top 95 }); 96 }); 97 }; 98 99 var updateSelectedNavPosition_ = function() { 100 $('nav .item').removeClass('selected'); 101 var scrollTop = $(window).scrollTop(); 102 for (var i = headerPositionCache.length - 1; i >= 0; i--) { 103 if (scrollTop >= headerPositionCache[i].top) { 104 $('#' + headerPositionCache[i].id).addClass('selected'); 105 break; 106 } 107 } 108 }; 109 110 rebuildHeaderPositionCache_(); 111 $(window).resize(function() { 112 rebuildHeaderPositionCache_(); 113 updateSelectedNavPosition_(); 114 }); 115 116 $(window).scroll(function() { 117 updateSelectedNavPosition_(); 118 }); 119} 120 121function smoothScrollToId(id) { 122 var $target = $('#' + id); 123 $('body').animate({ scrollTop: $target.offset().top }, 200, 'swing', function() { 124 document.location.hash = id; 125 }); 126} 127 128// Based on http://stackoverflow.com/questions/5802467/prevent-scrolling-of-parent-element 129function preventParentScrolls($el) { 130 $($el).on('DOMMouseScroll mousewheel', function(ev) { 131 var $this = $(this), 132 scrollTop = this.scrollTop, 133 scrollHeight = this.scrollHeight, 134 height = $this.height(), 135 delta = (ev.type == 'DOMMouseScroll' ? 136 ev.originalEvent.detail * -40 : 137 ev.originalEvent.wheelDelta), 138 up = delta > 0; 139 140 if (!up && -delta > scrollHeight - height - scrollTop) { 141 // Scrolling down, but this will take us past the bottom. 142 $this.scrollTop(scrollHeight); 143 } else if (up && delta > scrollTop) { 144 // Scrolling up, but this will take us past the top. 145 $this.scrollTop(0); 146 } else { 147 $this.scrollTop(scrollTop - delta); 148 } 149 150 ev.stopPropagation(); 151 ev.preventDefault(); 152 ev.returnValue = false; 153 return false; 154 }); 155}