Home | History | Annotate | Download | only in docs
      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 
     48 function 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 
    121 function 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
    129 function 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 }