5 * Sphinx JavaScript utilities for all documentation.
7 * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
8 * :license: BSD, see LICENSE for details.
13 * select a different prefix for underscore
18 * make the code below compatible with browsers without
19 * an installed firebug like debugger
20 if (!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"];
25 for (var i = 0; i < names.length; ++i)
26 window.console[names[i]] = function() {};
31 * small helper function to urldecode strings
33 jQuery
.urldecode = function(x
) {
34 return decodeURIComponent(x
).replace(/\+/g, ' ');
38 * small helper function to urlencode strings
40 jQuery
.urlencode
= encodeURIComponent
;
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.
47 jQuery
.getQueryParameters = function(s
) {
48 if (typeof s
=== 'undefined')
49 s
= document
.location
.search
;
50 var parts
= s
.substr(s
.indexOf('?') + 1).split('&');
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]);
57 result
[key
].push(value
);
59 result
[key
] = [value
];
65 * highlight a given string on a jquery object by wrapping it in
66 * span elements with the given class name.
68 jQuery
.fn
.highlightText = function(text
, className
) {
69 function highlight(node
, addItems
) {
70 if (node
.nodeType
=== 3) {
71 var val
= node
.nodeValue
;
72 var pos
= val
.toLowerCase().indexOf(text
);
74 !jQuery(node
.parentNode
).hasClass(className
) &&
75 !jQuery(node
.parentNode
).hasClass("nohighlight")) {
77 var isInSVG
= jQuery(node
).closest("body, svg, foreignObject").is("svg");
79 span
= document
.createElementNS("http://www.w3.org/2000/svg", "tspan");
81 span
= document
.createElement("span");
82 span
.className
= className
;
84 span
.appendChild(document
.createTextNode(val
.substr(pos
, text
.length
)));
85 node
.parentNode
.insertBefore(span
, node
.parentNode
.insertBefore(
86 document
.createTextNode(val
.substr(pos
+ text
.length
)),
88 node
.nodeValue
= val
.substr(0, pos
);
90 var bbox
= span
.getBBox();
91 var rect
= document
.createElementNS("http://www.w3.org/2000/svg", "rect");
92 rect
.x
.baseVal
.value
= bbox
.x
;
93 rect
.y
.baseVal
.value
= bbox
.y
;
94 rect
.width
.baseVal
.value
= bbox
.width
;
95 rect
.height
.baseVal
.value
= bbox
.height
;
96 rect
.setAttribute('class', className
);
97 var parentOfText
= node
.parentNode
.parentNode
;
99 "parent": node
.parentNode
,
104 else if (!jQuery(node
).is("button, select, textarea")) {
105 jQuery
.each(node
.childNodes
, function() {
106 highlight(this, addItems
);
111 var result
= this.each(function() {
112 highlight(this, addItems
);
114 for (var i
= 0; i
< addItems
.length
; ++i
) {
115 jQuery(addItems
[i
].parent
).before(addItems
[i
].target
);
121 * backward compatibility for jQuery.browser
122 * This will be supported until firefox bug is fixed.
124 if (!jQuery
.browser
) {
125 jQuery
.uaMatch = function(ua
) {
126 ua
= ua
.toLowerCase();
128 var match
= /(chrome)[ \/]([\w.]+)/.exec(ua
) ||
129 /(webkit)[ \/]([\w.]+)/.exec(ua
) ||
130 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua
) ||
131 /(msie) ([\w.]+)/.exec(ua
) ||
132 ua
.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua
) ||
136 browser
: match
[ 1 ] || "",
137 version
: match
[ 2 ] || "0"
141 jQuery
.browser
[jQuery
.uaMatch(navigator
.userAgent
).browser
] = true;
145 * Small JavaScript module for the documentation.
147 var Documentation
= {
150 this.fixFirefoxAnchorBug();
151 this.highlightSearchWords();
152 this.initIndexTable();
153 if (DOCUMENTATION_OPTIONS
.NAVIGATION_WITH_KEYS
) {
154 this.initOnKeyListeners();
162 PLURAL_EXPR : function(n
) { return n
=== 1 ? 0 : 1; },
165 // gettext and ngettext don't access this so that the functions
166 // can safely bound to a different name (_ = Documentation.gettext)
167 gettext : function(string
) {
168 var translated
= Documentation
.TRANSLATIONS
[string
];
169 if (typeof translated
=== 'undefined')
171 return (typeof translated
=== 'string') ? translated
: translated
[0];
174 ngettext : function(singular
, plural
, n
) {
175 var translated
= Documentation
.TRANSLATIONS
[singular
];
176 if (typeof translated
=== 'undefined')
177 return (n
== 1) ? singular
: plural
;
178 return translated
[Documentation
.PLURALEXPR(n
)];
181 addTranslations : function(catalog
) {
182 for (var key
in catalog
.messages
)
183 this.TRANSLATIONS
[key
] = catalog
.messages
[key
];
184 this.PLURAL_EXPR
= new Function('n', 'return +(' + catalog
.plural_expr
+ ')');
185 this.LOCALE
= catalog
.locale
;
189 * add context elements like header anchor links
191 addContextElements : function() {
192 $('div[id] > :header:first').each(function() {
193 $('<a class="headerlink">\u00B6</a>').
194 attr('href', '#' + this.id
).
195 attr('title', _('Permalink to this headline')).
198 $('dt[id]').each(function() {
199 $('<a class="headerlink">\u00B6</a>').
200 attr('href', '#' + this.id
).
201 attr('title', _('Permalink to this definition')).
207 * workaround a firefox stupidity
208 * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
210 fixFirefoxAnchorBug : function() {
211 if (document
.location
.hash
&& $.browser
.mozilla
)
212 window
.setTimeout(function() {
213 document
.location
.href
+= '';
218 * highlight the search words provided in the url in the text
220 highlightSearchWords : function() {
221 var params
= $.getQueryParameters();
222 var terms
= (params
.highlight
) ? params
.highlight
[0].split(/\s+/) : [];
224 var body
= $('div.body');
228 window
.setTimeout(function() {
229 $.each(terms
, function() {
230 body
.highlightText(this.toLowerCase(), 'highlighted');
233 $('<p class="highlight-link"><a href="javascript:Documentation.' +
234 'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
235 .appendTo($('#searchbox'));
240 * init the domain index toggle buttons
242 initIndexTable : function() {
243 var togglers
= $('img.toggler').click(function() {
244 var src
= $(this).attr('src');
245 var idnum
= $(this).attr('id').substr(7);
246 $('tr.cg-' + idnum
).toggle();
247 if (src
.substr(-9) === 'minus.png')
248 $(this).attr('src', src
.substr(0, src
.length
-9) + 'plus.png');
250 $(this).attr('src', src
.substr(0, src
.length
-8) + 'minus.png');
251 }).css('display', '');
252 if (DOCUMENTATION_OPTIONS
.COLLAPSE_INDEX
) {
258 * helper function to hide the search marks again
260 hideSearchWords : function() {
261 $('#searchbox .highlight-link').fadeOut(300);
262 $('span.highlighted').removeClass('highlighted');
266 * make the url absolute
268 makeURL : function(relativeURL
) {
269 return DOCUMENTATION_OPTIONS
.URL_ROOT
+ '/' + relativeURL
;
273 * get the current relative url
275 getCurrentURL : function() {
276 var path
= document
.location
.pathname
;
277 var parts
= path
.split(/\//);
278 $.each(DOCUMENTATION_OPTIONS
.URL_ROOT
.split(/\//), function() {
282 var url
= parts
.join('/');
283 return path
.substring(url
.lastIndexOf('/') + 1, path
.length
- 1);
286 initOnKeyListeners: function() {
287 $(document
).keyup(function(event
) {
288 var activeElementType
= document
.activeElement
.tagName
;
289 // don't navigate when in search box or textarea
290 if (activeElementType
!== 'TEXTAREA' && activeElementType
!== 'INPUT' && activeElementType
!== 'SELECT') {
291 switch (event
.keyCode
) {
293 var prevHref
= $('link[rel="prev"]').prop('href');
295 window
.location
.href
= prevHref
;
299 var nextHref
= $('link[rel="next"]').prop('href');
301 window
.location
.href
= nextHref
;
310 // quick alias for translations
311 _
= Documentation
.gettext
;
313 $(document
).ready(function() {
314 Documentation
.init();