docs/source/_static/js/theme.js
9ace345c
 // The MIT License (MIT)
 
 // Copyright (c) 2013-2018 Dave Snider, Read the Docs, Inc. & contributors
 
 // Permission is hereby granted, free of charge, to any person obtaining a copy of
 // this software and associated documentation files (the "Software"), to deal in
 // the Software without restriction, including without limitation the rights to
 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 // the Software, and to permit persons to whom the Software is furnished to do so,
 // subject to the following conditions:
 
 // The above copyright notice and this permission notice shall be included in all
 // copies or substantial portions of the Software.
 
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
6351da5a
 // var jQuery = (typeof(window) != 'undefined') ? window.jQuery : require('jquery');
a43aeeea
 
 // Sphinx theme nav state
 function ThemeNav () {
 
     var nav = {
         navBar: null,
         win: null,
         winScroll: false,
         winResize: false,
         linkScroll: false,
         winPosition: 0,
         winHeight: null,
         docHeight: null,
         isRunning: false
     };
 
     nav.enable = function (withStickyNav) {
         var self = this;
 
         // TODO this can likely be removed once the theme javascript is broken
         // out from the RTD assets. This just ensures old projects that are
         // calling `enable()` get the sticky menu on by default. All other cals
         // to `enable` should include an argument for enabling the sticky menu.
         if (typeof(withStickyNav) == 'undefined') {
             withStickyNav = true;
         }
 
         if (self.isRunning) {
             // Only allow enabling nav logic once
             return;
         }
 
         self.isRunning = true;
         jQuery(function ($) {
             self.init($);
 
             self.reset();
             self.win.on('hashchange', self.reset);
 
             if (withStickyNav) {
                 // Set scroll monitor
                 self.win.on('scroll', function () {
                     if (!self.linkScroll) {
                         if (!self.winScroll) {
                             self.winScroll = true;
                             requestAnimationFrame(function() { self.onScroll(); });
                         }
                     }
                 });
             }
 
             // Set resize monitor
             self.win.on('resize', function () {
                 if (!self.winResize) {
                     self.winResize = true;
                     requestAnimationFrame(function() { self.onResize(); });
                 }
             });
 
             self.onResize();
         });
 
     };
 
     // TODO remove this with a split in theme and Read the Docs JS logic as
     // well, it's only here to support 0.3.0 installs of our theme.
     nav.enableSticky = function() {
         this.enable(true);
     };
 
     nav.init = function ($) {
         var doc = $(document),
             self = this;
 
         this.navBar = $('div.wy-side-scroll:first');
         this.win = $(window);
 
         // Set up javascript UX bits
         $(document)
             // Shift nav in mobile when clicking the menu.
             .on('click', "[data-toggle='wy-nav-top']", function() {
                 $("[data-toggle='wy-nav-shift']").toggleClass("shift");
                 $("[data-toggle='rst-versions']").toggleClass("shift");
             })
 
             // Nav menu link click operations
             .on('click', ".wy-menu-vertical .current ul li a", function() {
                 var target = $(this);
                 // Close menu when you click a link.
                 $("[data-toggle='wy-nav-shift']").removeClass("shift");
                 $("[data-toggle='rst-versions']").toggleClass("shift");
                 // Handle dynamic display of l3 and l4 nav lists
                 self.toggleCurrent(target);
                 self.hashChange();
             })
             .on('click', "[data-toggle='rst-current-version']", function() {
                 $("[data-toggle='rst-versions']").toggleClass("shift-up");
             })
 
         // Make tables responsive
         $("table.docutils:not(.field-list,.footnote,.citation)")
             .wrap("<div class='wy-table-responsive'></div>");
 
         // Add extra class to responsive tables that contain
         // footnotes or citations so that we can target them for styling
         $("table.docutils.footnote")
             .wrap("<div class='wy-table-responsive footnote'></div>");
         $("table.docutils.citation")
             .wrap("<div class='wy-table-responsive citation'></div>");
 
         // Add expand links to all parents of nested ul
         $('.wy-menu-vertical ul').not('.simple').siblings('a').each(function () {
             var link = $(this);
                 expand = $('<span class="toctree-expand"></span>');
             expand.on('click', function (ev) {
                 self.toggleCurrent(link);
                 ev.stopPropagation();
                 return false;
             });
             link.prepend(expand);
         });
     };
 
     nav.reset = function () {
         // Get anchor from URL and open up nested nav
         var anchor = encodeURI(window.location.hash) || '#';
 
         try {
             var vmenu = $('.wy-menu-vertical');
             var link = vmenu.find('[href="' + anchor + '"]');
             if (link.length === 0) {
                 // this link was not found in the sidebar.
                 // Find associated id element, then its closest section
                 // in the document and try with that one.
                 var id_elt = $('.document [id="' + anchor.substring(1) + '"]');
                 var closest_section = id_elt.closest('div.section');
                 link = vmenu.find('[href="#' + closest_section.attr("id") + '"]');
                 if (link.length === 0) {
                     // still not found in the sidebar. fall back to main section
                     link = vmenu.find('[href="#"]');
                 }
             }
             // If we found a matching link then reset current and re-apply
             // otherwise retain the existing match
             if (link.length > 0) {
                 $('.wy-menu-vertical .current').removeClass('current');
                 link.addClass('current');
                 link.closest('li.toctree-l1').addClass('current');
                 link.closest('li.toctree-l1').parent().addClass('current');
                 link.closest('li.toctree-l1').addClass('current');
                 link.closest('li.toctree-l2').addClass('current');
                 link.closest('li.toctree-l3').addClass('current');
                 link.closest('li.toctree-l4').addClass('current');
                 link[0].scrollIntoView();
             }
         }
         catch (err) {
             console.log("Error expanding nav for anchor", err);
         }
 
     };
 
     nav.onScroll = function () {
         this.winScroll = false;
         var newWinPosition = this.win.scrollTop(),
             winBottom = newWinPosition + this.winHeight,
             navPosition = this.navBar.scrollTop(),
             newNavPosition = navPosition + (newWinPosition - this.winPosition);
         if (newWinPosition < 0 || winBottom > this.docHeight) {
             return;
         }
         this.navBar.scrollTop(newNavPosition);
         this.winPosition = newWinPosition;
     };
 
     nav.onResize = function () {
         this.winResize = false;
         this.winHeight = this.win.height();
         this.docHeight = $(document).height();
     };
 
     nav.hashChange = function () {
         this.linkScroll = true;
         this.win.one('hashchange', function () {
             this.linkScroll = false;
         });
     };
 
     nav.toggleCurrent = function (elem) {
         var parent_li = elem.closest('li');
         parent_li.siblings('li.current').removeClass('current');
         parent_li.siblings().find('li.current').removeClass('current');
         parent_li.find('> ul li.current').removeClass('current');
         parent_li.toggleClass('current');
     }
 
     return nav;
 };
 
 module.exports.ThemeNav = ThemeNav();
 
 if (typeof(window) != 'undefined') {
     window.SphinxRtdTheme = {
         Navigation: module.exports.ThemeNav,
         // TODO remove this once static assets are split up between the theme
         // and Read the Docs. For now, this patches 0.3.0 to be backwards
         // compatible with a pre-0.3.0 layout.html
         StickyNav: module.exports.ThemeNav,
     };
 }
 
 
 // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
 // https://gist.github.com/paulirish/1579671
 // MIT license
 
 (function() {
     var lastTime = 0;
     var vendors = ['ms', 'moz', 'webkit', 'o'];
     for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
         window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
         window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
                                    || window[vendors[x]+'CancelRequestAnimationFrame'];
     }
 
     if (!window.requestAnimationFrame)
         window.requestAnimationFrame = function(callback, element) {
             var currTime = new Date().getTime();
             var timeToCall = Math.max(0, 16 - (currTime - lastTime));
             var id = window.setTimeout(function() { callback(currTime + timeToCall); },
               timeToCall);
             lastTime = currTime + timeToCall;
             return id;
         };
 
     if (!window.cancelAnimationFrame)
         window.cancelAnimationFrame = function(id) {
             clearTimeout(id);
         };
 }());