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