PageSourceSearch

https://aragog.rs/book/book.js

js aragog.rs collected 2026-10-08 05:19:49 UTC 23,730 bytes, 646 lines download raw bytes

1"use strict";
2
3// Fix back button cache problem
4window.onunload = function () { };
5
6// Global variable, shared between modules
7function playpen_text(playpen) {
8    let code_block = playpen.querySelector("code");
9
10    if (window.ace && code_block.classList.contains("editable")) {
11        let editor = window.ace.edit(code_block);
12        return editor.getValue();
13    } else {
14        return code_block.textContent;
15    }
16}
17
18(function codeSnippets() {
19    function fetch_with_timeout(url, options, timeout = 6000) {
20        return Promise.race([
21            fetch(url, options),
22            new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
23        ]);
24    }
25
26    var playpens = Array.from(document.querySelectorAll(".playpen"));
27    if (playpens.length > 0) {
28        fetch_with_timeout("https://play.rust-lang.org/meta/crates", {
29            headers: {
30                'Content-Type': "application/json",
31            },
32            method: 'POST',
33            mode: 'cors',
34        })
35        .then(response => response.json())
36        .then(response => {
37            // get list of crates available in the rust playground
38            let playground_crates = response.crates.map(item => item["id"]);
39            playpens.forEach(block => handle_crate_list_update(block, playground_crates));
40        });
41    }
42
43    function handle_crate_list_update(playpen_block, playground_crates) {
44        // update the play buttons after receiving the response
45        update_play_button(playpen_block, playground_crates);
46
47        // and install on change listener to dynamically update ACE editors
48        if (window.ace) {
49            let code_block = playpen_block.querySelector("code");
50            if (code_block.classList.contains("editable")) {
51                let editor = window.ace.edit(code_block);
52                editor.addEventListener("change", function (e) {
53                    update_play_button(playpen_block, playground_crates);
54                });
55                // add Ctrl-Enter command to execute rust code
56                editor.commands.addCommand({
57                    name: "run",
58                    bindKey: {
59                        win: "Ctrl-Enter",
60                        mac: "Ctrl-Enter"
61                    },
62                    exec: _editor => run_rust_code(playpen_block)
63                });
64            }
65        }
66    }
67
68    // updates the visibility of play button based on `no_run` class and
69    // used crates vs ones available on http://play.rust-lang.org
70    function update_play_button(pre_block, playground_crates) {
71        var play_button = pre_block.querySelector(".play-button");
72
73        // skip if code is `no_run`
74        if (pre_block.querySelector('code').classList.contains("no_run")) {
75            play_button.classList.add("hidden");
76            return;
77        }
78
79        // get list of `extern crate`'s from snippet
80        var txt = playpen_text(pre_block);
81        var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g;
82        var snippet_crates = [];
83        var item;
84        while (item = re.exec(txt)) {
85            snippet_crates.push(item[1]);
86        }
87
88        // check if all used crates are available on play.rust-lang.org
89        var all_available = snippet_crates.every(function (elem) {
90            return playground_crates.indexOf(elem) > -1;
91        });
92
93        if (all_available) {
94            play_button.classList.remove("hidden");
95        } else {
96            play_button.classList.add("hidden");
97        }
98    }
99
100    function run_rust_code(code_block) {
101        var result_block = code_block.querySelector(".result");
102        if (!result_block) {
103            result_block = document.createElement('code');
104            result_block.className = 'result hljs language-bash';
105
106            code_block.append(result_block);
107        }
108
109        let text = playpen_text(code_block);
110        let classes = code_block.querySelector('code').classList;
111        let has_2018 = classes.contains("edition2018");
112        let edition = has_2018 ? "2018" : "2015";
113
114        var params = {
115            version: "stable",
116            optimize: "0",
117            code: text,
118            edition: edition
119        };
120
121        if (text.indexOf("#![feature") !== -1) {
122            params.version = "nightly";
123        }
124
125        result_block.innerText = "Running...";
126
127        fetch_with_timeout("https://play.rust-lang.org/evaluate.json", {
128            headers: {
129                'Content-Type': "application/json",
130            },
131            method: 'POST',
132            mode: 'cors',
133            body: JSON.stringify(params)
134        })
135        .then(response => response.json())
136        .then(response => result_block.innerText = response.result)
137        .catch(error => result_block.innerText = "Playground Communication: " + error.message);
138    }
139
140    // Syntax highlighting Configuration
141    hljs.configure({
142        tabReplace: '    ', // 4 spaces
143        languages: [],      // Languages used for auto-detection
144    });
145
146    let code_nodes = Array
147        .from(document.querySelectorAll('code'))
148        // Don't highlight `inline code` blocks in headers.
149        .filter(function (node) {return !node.parentElement.classList.contains("header"); });
150
151    if (window.ace) {
152        // language-rust class needs to be removed for editable
153        // blocks or highlightjs will capture events
154        Array
155            .from(document.querySelectorAll('code.editable'))
156            .forEach(function (block) { block.classList.remove('language-rust'); });
157
158        Array
159            .from(document.querySelectorAll('code:not(.editable)'))
160            .forEach(function (block) { hljs.highlightBlock(block); });
161    } else {
162        code_nodes.forEach(function (block) { hljs.highlightBlock(block); });
163    }
164
165    // Adding the hljs class gives code blocks the color css
166    // even if highlighting doesn't apply
167    code_nodes.forEach(function (block) { block.classList.add('hljs'); });
168
169    Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) {
170
171        var lines = Array.from(block.querySelectorAll('.boring'));
172        // If no lines were hidden, return
173        if (!lines.length) { return; }
174        block.classList.add("hide-boring");
175
176        var buttons = document.createElement('div');
177        buttons.className = 'buttons';
178        buttons.innerHTML = "<button class=\"fa fa-expand\" title=\"Show hidden lines\" aria-label=\"Show hidden lines\"></button>";
179
180        // add expand button
181        var pre_block = block.parentNode;
182        pre_block.insertBefore(buttons, pre_block.firstChild);
183
184        pre_block.querySelector('.buttons').addEventListener('click', function (e) {
185            if (e.target.classList.contains('fa-expand')) {
186                e.target.classList.remove('fa-expand');
187                e.target.classList.add('fa-compress');
188                e.target.title = 'Hide lines';
189                e.target.setAttribute('aria-label', e.target.title);
190
191                block.classList.remove('hide-boring');
192            } else if (e.target.classList.contains('fa-compress')) {
193                e.target.classList.remove('fa-compress');
194                e.target.classList.add('fa-expand');
195                e.target.title = 'Show hidden lines';
196                e.target.setAttribute('aria-label', e.target.title);
197
198                block.classList.add('hide-boring');
199            }
200        });
201    });
202
203    if (window.playpen_copyable) {
204        Array.from(document.querySelectorAll('pre code')).forEach(function (block) {
205            var pre_block = block.parentNode;
206            if (!pre_block.classList.contains('playpen')) {
207                var buttons = pre_block.querySelector(".buttons");
208                if (!buttons) {
209                    buttons = document.createElement('div');
210                    buttons.className = 'buttons';
211                    pre_block.insertBefore(buttons, pre_block.firstChild);
212                }
213
214                var clipButton = document.createElement('button');
215                clipButton.className = 'fa fa-copy clip-button';
216                clipButton.title = 'Copy to clipboard';
217                clipButton.setAttribute('aria-label', clipButton.title);
218                clipButton.innerHTML = '<i class=\"tooltiptext\"></i>';
219
220                buttons.insertBefore(clipButton, buttons.firstChild);
221            }
222        });
223    }
224
225    // Process playpen code blocks
226    Array.from(document.querySelectorAll(".playpen")).forEach(function (pre_block) {
227        // Add play button
228        var buttons = pre_block.querySelector(".buttons");
229        if (!buttons) {
230            buttons = document.createElement('div');
231            buttons.className = 'buttons';
232            pre_block.insertBefore(buttons, pre_block.firstChild);
233        }
234
235        var runCodeButton = document.createElement('button');
236        runCodeButton.className = 'fa fa-play play-button';
237        runCodeButton.hidden = true;
238        runCodeButton.title = 'Run this code';
239        runCodeButton.setAttribute('aria-label', runCodeButton.title);
240
241        buttons.insertBefore(runCodeButton, buttons.firstChild);
242        runCodeButton.addEventListener('click', function (e) {
243            run_rust_code(pre_block);
244        });
245
246        if (window.playpen_copyable) {
247            var copyCodeClipboardButton = document.createElement('button');
248            copyCodeClipboardButton.className = 'fa fa-copy clip-button';
249            copyCodeClipboardButton.innerHTML = '<i class="tooltiptext"></i>';
250            copyCodeClipboardButton.title = 'Copy to clipboard';
251            copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
252
253            buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild);
254        }
255
256        let code_block = pre_block.querySelector("code");
257        if (window.ace && code_block.classList.contains("editable")) {
258            var undoChangesButton = document.createElement('button');
259            undoChangesButton.className = 'fa fa-history reset-button';
260            undoChangesButton.title = 'Undo changes';
261            undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
262
263            buttons.insertBefore(undoChangesButton, buttons.firstChild);
264
265            undoChangesButton.addEventListener('click', function () {
266                let editor = window.ace.edit(code_block);
267                editor.setValue(editor.originalCode);
268                editor.clearSelection();
269            });
270        }
271    });
272})();
273
274(function themes() {
275    var html = document.querySelector('html');
276    var themeToggleButton = document.getElementById('theme-toggle');
277    var themePopup = document.getElementById('theme-list');
278    var themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
279    var stylesheets = {
280        ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"),
281        tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"),
282        highlight: document.querySelector("[href$='highlight.css']"),
283    };
284
285    function showThemes() {
286        themePopup.style.display = 'block';
287        themeToggleButton.setAttribute('aria-expanded', true);
288        themePopup.querySelector("button#" + get_theme()).focus();
289    }
290
291    function hideThemes() {
292        themePopup.style.display = 'none';
293        themeToggleButton.setAttribute('aria-expanded', false);
294        themeToggleButton.focus();
295    }
296
297    function get_theme() {
298        var theme;
299        try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { }
300        if (theme === null || theme === undefined) {
301            return default_theme;
302        } else {
303            return theme;
304        }
305    }
306
307    function set_theme(theme, store = true) {
308        let ace_theme;
309
310        if (theme == 'coal' || theme == 'navy') {
311            stylesheets.ayuHighlight.disabled = true;
312            stylesheets.tomorrowNight.disabled = false;
313            stylesheets.highlight.disabled = true;
314
315            ace_theme = "ace/theme/tomorrow_night";
316        } else if (theme == 'ayu') {
317            stylesheets.ayuHighlight.disabled = false;
318            stylesheets.tomorrowNight.disabled = true;
319            stylesheets.highlight.disabled = true;
320            ace_theme = "ace/theme/tomorrow_night";
321        } else {
322            stylesheets.ayuHighlight.disabled = true;
323            stylesheets.tomorrowNight.disabled = true;
324            stylesheets.highlight.disabled = false;
325            ace_theme = "ace/theme/dawn";
326        }
327
328        setTimeout(function () {
329            themeColorMetaTag.content = getComputedStyle(document.body).backgroundColor;
330        }, 1);
331
332        if (window.ace && window.editors) {
333            window.editors.forEach(function (editor) {
334                editor.setTheme(ace_theme);
335            });
336        }
337
338        var previousTheme = get_theme();
339
340        if (store) {
341            try { localStorage.setItem('mdbook-theme', theme); } catch (e) { }
342        }
343
344        html.classList.remove(previousTheme);
345        html.classList.add(theme);
346    }
347
348    // Set theme
349    var theme = get_theme();
350
351    set_theme(theme, false);
352
353    themeToggleButton.addEventListener('click', function () {
354        if (themePopup.style.display === 'block') {
355            hideThemes();
356        } else {
357            showThemes();
358        }
359    });
360
361    themePopup.addEventListener('click', function (e) {
362        var theme = e.target.id || e.target.parentElement.id;
363        set_theme(theme);
364    });
365
366    themePopup.addEventListener('focusout', function(e) {
367        // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
368        if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) {
369            hideThemes();
370        }
371    });
372
373    // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628
374    document.addEventListener('click', function(e) {
375        if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) {
376            hideThemes();
377        }
378    });
379
380    document.addEventListener('keydown', function (e) {
381        if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
382        if (!themePopup.contains(e.target)) { return; }
383
384        switch (e.key) {
385            case 'Escape':
386                e.preventDefault();
387                hideThemes();
388                break;
389            case 'ArrowUp':
390                e.preventDefault();
391                var li = document.activeElement.parentElement;
392                if (li && li.previousElementSibling) {
393                    li.previousElementSibling.querySelector('button').focus();
394                }
395                break;
396            case 'ArrowDown':
397                e.preventDefault();
398                var li = document.activeElement.parentElement;
399                if (li && li.nextElementSibling) {
400                    li.nextElementSibling.querySelector('button').focus();
401                }
402                break;
403            case 'Home':
404                e.preventDefault();
405                themePopup.querySelector('li:first-child button').focus();
406                break;
407            case 'End':
408                e.preventDefault();
409                themePopup.querySelector('li:last-child button').focus();
410                break;
411        }
412    });
413})();
414
415(function sidebar() {
416    var html = document.querySelector("html");
417    var sidebar = document.getElementById("sidebar");
418    var sidebarLinks = document.querySelectorAll('#sidebar a');
419    var sidebarToggleButton = document.getElementById("sidebar-toggle");
420    var sidebarResizeHandle = document.getElementById("sidebar-resize-handle");
421    var firstContact = null;
422
423    function showSidebar() {
424        html.classList.remove('sidebar-hidden')
425        html.classList.add('sidebar-visible');
426        Array.from(sidebarLinks).forEach(function (link) {
427            link.setAttribute('tabIndex', 0);
428        });
429        sidebarToggleButton.setAttribute('aria-expanded', true);
430        sidebar.setAttribute('aria-hidden', false);
431        try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { }
432    }
433
434
435    var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle');
436
437    function toggleSection(ev) {
438        ev.currentTarget.parentElement.classList.toggle('expanded');
439    }
440
441    Array.from(sidebarAnchorToggles).forEach(function (el) {
442        el.addEventListener('click', toggleSection);
443    });
444
445    function hideSidebar() {
446        html.classList.remove('sidebar-visible')
447        html.classList.add('sidebar-hidden');
448        Array.from(sidebarLinks).forEach(function (link) {
449            link.setAttribute('tabIndex', -1);
450        });
451        sidebarToggleButton.setAttribute('aria-expanded', false);
452        sidebar.setAttribute('aria-hidden', true);
453        try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { }
454    }
455
456    // Toggle sidebar
457    sidebarToggleButton.addEventListener('click', function sidebarToggle() {
458        if (html.classList.contains("sidebar-hidden")) {
459            showSidebar();
460        } else if (html.classList.contains("sidebar-visible")) {
461            hideSidebar();
462        } else {
463            if (getComputedStyle(sidebar)['transform'] === 'none') {
464                hideSidebar();
465            } else {
466                showSidebar();
467            }
468        }
469    });
470
471    sidebarResizeHandle.addEventListener('mousedown', initResize, false);
472
473    function initResize(e) {
474        window.addEventListener('mousemove', resize, false);
475        window.addEventListener('mouseup', stopResize, false);
476        html.classList.add('sidebar-resizing');
477    }
478    function resize(e) {
479        document.documentElement.style.setProperty('--sidebar-width', (e.clientX - sidebar.offsetLeft) + 'px');
480    }
481    //on mouseup remove windows functions mousemove & mouseup
482    function stopResize(e) {
483        html.classList.remove('sidebar-resizing');
484        window.removeEventListener('mousemove', resize, false);
485        window.removeEventListener('mouseup', stopResize, false);
486    }
487
488    document.addEventListener('touchstart', function (e) {
489        firstContact = {
490            x: e.touches[0].clientX,
491            time: Date.now()
492        };
493    }, { passive: true });
494
495    document.addEventListener('touchmove', function (e) {
496        if (!firstContact)
497            return;
498
499        var curX = e.touches[0].clientX;
500        var xDiff = curX - firstContact.x,
501            tDiff = Date.now() - firstContact.time;
502
503        if (tDiff < 250 && Math.abs(xDiff) >= 150) {
504            if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300))
505                showSidebar();
506            else if (xDiff < 0 && curX < 300)
507                hideSidebar();
508
509            firstContact = null;
510        }
511    }, { passive: true });
512
513    // Scroll sidebar to current active section
514    var activeSection = document.getElementById("sidebar").querySelector(".active");
515    if (activeSection) {
516        // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
517        activeSection.scrollIntoView({ block: 'center' });
518    }
519})();
520
521(function chapterNavigation() {
522    document.addEventListener('keydown', function (e) {
523        if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
524        if (window.search && window.search.hasFocus()) { return; }
525
526        switch (e.key) {
527            case 'ArrowRight':
528                e.preventDefault();
529                var nextButton = document.querySelector('.nav-chapters.next');
530                if (nextButton) {
531                    window.location.href = nextButton.href;
532                }
533                break;
534            case 'ArrowLeft':
535                e.preventDefault();
536                var previousButton = document.querySelector('.nav-chapters.previous');
537                if (previousButton) {
538                    window.location.href = previousButton.href;
539                }
540                break;
541        }
542    });
543})();
544
545(function clipboard() {
546    var clipButtons = document.querySelectorAll('.clip-button');
547
548    function hideTooltip(elem) {
549        elem.firstChild.innerText = "";
550        elem.className = 'fa fa-copy clip-button';
551    }
552
553    function showTooltip(elem, msg) {
554        elem.firstChild.innerText = msg;
555        elem.className = 'fa fa-copy tooltipped';
556    }
557
558    var clipboardSnippets = new ClipboardJS('.clip-button', {
559        text: function (trigger) {
560            hideTooltip(trigger);
561            let playpen = trigger.closest("pre");
562            return playpen_text(playpen);
563        }
564    });
565
566    Array.from(clipButtons).forEach(function (clipButton) {
567        clipButton.addEventListener('mouseout', function (e) {
568            hideTooltip(e.currentTarget);
569        });
570    });
571
572    clipboardSnippets.on('success', function (e) {
573        e.clearSelection();
574        showTooltip(e.trigger, "Copied!");
575    });
576
577    clipboardSnippets.on('error', function (e) {
578        showTooltip(e.trigger, "Clipboard error!");
579    });
580})();
581
582(function scrollToTop () {
583    var menuTitle = document.querySelector('.menu-title');
584
585    menuTitle.addEventListener('click', function () {
586        document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' });
587    });
588})();
589
590(function controllMenu() {
591    var menu = document.getElementById('menu-bar');
592
593    (function controllPosition() {
594        var scrollTop = document.scrollingElement.scrollTop;
595        var prevScrollTop = scrollTop;
596        var minMenuY = -menu.clientHeight - 50;
597        // When the script loads, the page can be at any scroll (e.g. if you reforesh it).
598        menu.style.top = scrollTop + 'px';
599        // Same as parseInt(menu.style.top.slice(0, -2), but faster
600        var topCache = menu.style.top.slice(0, -2);
601        menu.classList.remove('sticky');
602        var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
603        document.addEventListener('scroll', function () {
604            scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
605            // `null` means that it doesn't need to be updated
606            var nextSticky = null;
607            var nextTop = null;
608            var scrollDown = scrollTop > prevScrollTop;
609            var menuPosAbsoluteY = topCache - scrollTop;
610            if (scrollDown) {
611                nextSticky = false;
612                if (menuPosAbsoluteY > 0) {
613                    nextTop = prevScrollTop;
614                }
615            } else {
616                if (menuPosAbsoluteY > 0) {
617                    nextSticky = true;
618                } else if (menuPosAbsoluteY < minMenuY) {
619                    nextTop = prevScrollTop + minMenuY;
620                }
621            }
622            if (nextSticky === true && stickyCache === false) {
623                menu.classList.add('sticky');
624                stickyCache = true;
625            } else if (nextSticky === false && stickyCache === true) {
626                menu.classList.remove('sticky');
627                stickyCache = false;
628            }
629            if (nextTop !== null) {
630                menu.style.top = nextTop + 'px';
631                topCache = nextTop;
632            }
633            prevScrollTop = scrollTop;
634        }, { passive: true });
635    })();
636    (function controllBorder() {
637        menu.classList.remove('bordered');
638        document.addEventListener('scroll', function () {
639            if (menu.offsetTop === 0) {
640                menu.classList.remove('bordered');
641            } else {
642                menu.classList.add('bordered');
643            }
644        }, { passive: true });
645    })();
646})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.