1/* 2 * doctools.js 3 * ~~~~~~~~~~~ 4 * 5 * Sphinx JavaScript utilities for all documentation. 6 * 7 * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. 8 * :license: BSD, see LICENSE for details. 9 * 10 */ 11 12/** 13 * select a different prefix for underscore 14 */ 15$u = _.noConflict(); 16 17/** 18 * make the code below compatible with browsers without 19 * an installed firebug like debugger 20if (!window.console || !console.firebug) { 21 var names = ["log", "debug", "info", "warn", "error", "assert", "dir", 22 "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", 23 "profile", "profileEnd"]; 24 window.console = {}; 25 for (var i = 0; i < names.length; ++i) 26 window.console[names[i]] = function() {}; 27} 28 */ 29 30/** 31 * small helper function to urldecode strings 32 */ 33jQuery.urldecode = function(x) { 34 return decodeURIComponent(x).replace(/\+/g, ' '); 35}; 36 37/** 38 * small helper function to urlencode strings 39 */ 40jQuery.urlencode = encodeURIComponent; 41 42/** 43 * This function returns the parsed url parameters of the 44 * current request. Multiple values per key are supported, 45 * it will always return arrays of strings for the value parts. 46 */ 47jQuery.getQueryParameters = function(s) { 48 if (typeof s == 'undefined') 49 s = document.location.search; 50 var parts = s.substr(s.indexOf('?') + 1).split('&'); 51 var result = {}; 52 for (var i = 0; i < parts.length; i++) { 53 var tmp = parts[i].split('=', 2); 54 var key = jQuery.urldecode(tmp[0]); 55 var value = jQuery.urldecode(tmp[1]); 56 if (key in result) 57 result[key].push(value); 58 else 59 result[key] = [value]; 60 } 61 return result; 62}; 63 64/** 65 * highlight a given string on a jquery object by wrapping it in 66 * span elements with the given class name. 67 */ 68jQuery.fn.highlightText = function(text, className) { 69 function highlight(node) { 70 if (node.nodeType == 3) { 71 var val = node.nodeValue; 72 var pos = val.toLowerCase().indexOf(text); 73 if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { 74 var span = document.createElement("span"); 75 span.className = className; 76 span.appendChild(document.createTextNode(val.substr(pos, text.length))); 77 node.parentNode.insertBefore(span, node.parentNode.insertBefore( 78 document.createTextNode(val.substr(pos + text.length)), 79 node.nextSibling)); 80 node.nodeValue = val.substr(0, pos); 81 } 82 } 83 else if (!jQuery(node).is("button, select, textarea")) { 84 jQuery.each(node.childNodes, function() { 85 highlight(this); 86 }); 87 } 88 } 89 return this.each(function() { 90 highlight(this); 91 }); 92}; 93 94/* 95 * backward compatibility for jQuery.browser 96 * This will be supported until firefox bug is fixed. 97 */ 98if (!jQuery.browser) { 99 jQuery.uaMatch = function(ua) { 100 ua = ua.toLowerCase(); 101 102 var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 103 /(webkit)[ \/]([\w.]+)/.exec(ua) || 104 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 105 /(msie) ([\w.]+)/.exec(ua) || 106 ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || 107 []; 108 109 return { 110 browser: match[ 1 ] || "", 111 version: match[ 2 ] || "0" 112 }; 113 }; 114 jQuery.browser = {}; 115 jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; 116} 117 118/** 119 * Small JavaScript module for the documentation. 120 */ 121var Documentation = { 122 123 init : function() { 124 this.fixFirefoxAnchorBug(); 125 this.highlightSearchWords(); 126 this.initIndexTable(); 127 128 }, 129 130 /** 131 * i18n support 132 */ 133 TRANSLATIONS : {}, 134 PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, 135 LOCALE : 'unknown', 136 137 // gettext and ngettext don't access this so that the functions 138 // can safely bound to a different name (_ = Documentation.gettext) 139 gettext : function(string) { 140 var translated = Documentation.TRANSLATIONS[string]; 141 if (typeof translated == 'undefined') 142 return string; 143 return (typeof translated == 'string') ? translated : translated[0]; 144 }, 145 146 ngettext : function(singular, plural, n) { 147 var translated = Documentation.TRANSLATIONS[singular]; 148 if (typeof translated == 'undefined') 149 return (n == 1) ? singular : plural; 150 return translated[Documentation.PLURALEXPR(n)]; 151 }, 152 153 addTranslations : function(catalog) { 154 for (var key in catalog.messages) 155 this.TRANSLATIONS[key] = catalog.messages[key]; 156 this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); 157 this.LOCALE = catalog.locale; 158 }, 159 160 /** 161 * add context elements like header anchor links 162 */ 163 addContextElements : function() { 164 $('div[id] > :header:first').each(function() { 165 $('<a class="headerlink">\u00B6</a>'). 166 attr('href', '#' + this.id). 167 attr('title', _('Permalink to this headline')). 168 appendTo(this); 169 }); 170 $('dt[id]').each(function() { 171 $('<a class="headerlink">\u00B6</a>'). 172 attr('href', '#' + this.id). 173 attr('title', _('Permalink to this definition')). 174 appendTo(this); 175 }); 176 }, 177 178 /** 179 * workaround a firefox stupidity 180 * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 181 */ 182 fixFirefoxAnchorBug : function() { 183 if (document.location.hash) 184 window.setTimeout(function() { 185 document.location.href += ''; 186 }, 10); 187 }, 188 189 /** 190 * highlight the search words provided in the url in the text 191 */ 192 highlightSearchWords : function() { 193 var params = $.getQueryParameters(); 194 var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; 195 if (terms.length) { 196 var body = $('div.body'); 197 if (!body.length) { 198 body = $('body'); 199 } 200 window.setTimeout(function() { 201 $.each(terms, function() { 202 body.highlightText(this.toLowerCase(), 'highlighted'); 203 }); 204 }, 10); 205 $('<p class="highlight-link"><a href="javascript:Documentation.' + 206 'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>') 207 .appendTo($('#searchbox')); 208 } 209 }, 210 211 /** 212 * init the domain index toggle buttons 213 */ 214 initIndexTable : function() { 215 var togglers = $('img.toggler').click(function() { 216 var src = $(this).attr('src'); 217 var idnum = $(this).attr('id').substr(7); 218 $('tr.cg-' + idnum).toggle(); 219 if (src.substr(-9) == 'minus.png') 220 $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); 221 else 222 $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); 223 }).css('display', ''); 224 if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { 225 togglers.click(); 226 } 227 }, 228 229 /** 230 * helper function to hide the search marks again 231 */ 232 hideSearchWords : function() { 233 $('#searchbox .highlight-link').fadeOut(300); 234 $('span.highlighted').removeClass('highlighted'); 235 }, 236 237 /** 238 * make the url absolute 239 */ 240 makeURL : function(relativeURL) { 241 return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; 242 }, 243 244 /** 245 * get the current relative url 246 */ 247 getCurrentURL : function() { 248 var path = document.location.pathname; 249 var parts = path.split(/\//); 250 $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { 251 if (this == '..') 252 parts.pop(); 253 }); 254 var url = parts.join('/'); 255 return path.substring(url.lastIndexOf('/') + 1, path.length - 1); 256 }, 257 258 initOnKeyListeners: function() { 259 $(document).keyup(function(event) { 260 var activeElementType = document.activeElement.tagName; 261 // don't navigate when in search box or textarea 262 if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { 263 switch (event.keyCode) { 264 case 37: // left 265 var prevHref = $('link[rel="prev"]').prop('href'); 266 if (prevHref) { 267 window.location.href = prevHref; 268 return false; 269 } 270 case 39: // right 271 var nextHref = $('link[rel="next"]').prop('href'); 272 if (nextHref) { 273 window.location.href = nextHref; 274 return false; 275 } 276 } 277 } 278 }); 279 } 280}; 281 282// quick alias for translations 283_ = Documentation.gettext; 284 285$(document).ready(function() { 286 Documentation.init(); 287});