mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-24 16:02:59 +01:00
229 lines
6.5 KiB
JavaScript
229 lines
6.5 KiB
JavaScript
|
// From rust:
|
||
|
/* global sourcesIndex */
|
||
|
|
||
|
// Local js definitions:
|
||
|
/* global addClass, getCurrentValue, onEachLazy, removeClass, browserSupportsHistoryApi */
|
||
|
/* global updateLocalStorage */
|
||
|
|
||
|
"use strict";
|
||
|
|
||
|
(function() {
|
||
|
|
||
|
const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
|
||
|
|
||
|
const NAME_OFFSET = 0;
|
||
|
const DIRS_OFFSET = 1;
|
||
|
const FILES_OFFSET = 2;
|
||
|
|
||
|
function closeSidebarIfMobile() {
|
||
|
if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
|
||
|
updateLocalStorage("source-sidebar-show", "false");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function createDirEntry(elem, parent, fullPath, hasFoundFile) {
|
||
|
const dirEntry = document.createElement("details");
|
||
|
const summary = document.createElement("summary");
|
||
|
|
||
|
dirEntry.className = "dir-entry";
|
||
|
|
||
|
fullPath += elem[NAME_OFFSET] + "/";
|
||
|
|
||
|
summary.innerText = elem[NAME_OFFSET];
|
||
|
dirEntry.appendChild(summary);
|
||
|
|
||
|
const folders = document.createElement("div");
|
||
|
folders.className = "folders";
|
||
|
if (elem[DIRS_OFFSET]) {
|
||
|
for (const dir of elem[DIRS_OFFSET]) {
|
||
|
if (createDirEntry(dir, folders, fullPath, false)) {
|
||
|
dirEntry.open = true;
|
||
|
hasFoundFile = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
dirEntry.appendChild(folders);
|
||
|
|
||
|
const files = document.createElement("div");
|
||
|
files.className = "files";
|
||
|
if (elem[FILES_OFFSET]) {
|
||
|
for (const file_text of elem[FILES_OFFSET]) {
|
||
|
const file = document.createElement("a");
|
||
|
file.innerText = file_text;
|
||
|
file.href = rootPath + "src/" + fullPath + file_text + ".html";
|
||
|
file.addEventListener("click", closeSidebarIfMobile);
|
||
|
const w = window.location.href.split("#")[0];
|
||
|
if (!hasFoundFile && w === file.href) {
|
||
|
file.className = "selected";
|
||
|
dirEntry.open = true;
|
||
|
hasFoundFile = true;
|
||
|
}
|
||
|
files.appendChild(file);
|
||
|
}
|
||
|
}
|
||
|
dirEntry.appendChild(files);
|
||
|
parent.appendChild(dirEntry);
|
||
|
return hasFoundFile;
|
||
|
}
|
||
|
|
||
|
function toggleSidebar() {
|
||
|
const child = this.parentNode.children[0];
|
||
|
if (child.innerText === ">") {
|
||
|
window.rustdocMobileScrollLock();
|
||
|
addClass(document.documentElement, "source-sidebar-expanded");
|
||
|
child.innerText = "<";
|
||
|
updateLocalStorage("source-sidebar-show", "true");
|
||
|
} else {
|
||
|
window.rustdocMobileScrollUnlock();
|
||
|
removeClass(document.documentElement, "source-sidebar-expanded");
|
||
|
child.innerText = ">";
|
||
|
updateLocalStorage("source-sidebar-show", "false");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function createSidebarToggle() {
|
||
|
const sidebarToggle = document.createElement("div");
|
||
|
sidebarToggle.id = "sidebar-toggle";
|
||
|
|
||
|
const inner = document.createElement("button");
|
||
|
|
||
|
if (getCurrentValue("source-sidebar-show") === "true") {
|
||
|
inner.innerText = "<";
|
||
|
} else {
|
||
|
inner.innerText = ">";
|
||
|
}
|
||
|
inner.onclick = toggleSidebar;
|
||
|
|
||
|
sidebarToggle.appendChild(inner);
|
||
|
return sidebarToggle;
|
||
|
}
|
||
|
|
||
|
// This function is called from "source-files.js", generated in `html/render/write_shared.rs`.
|
||
|
// eslint-disable-next-line no-unused-vars
|
||
|
function createSourceSidebar() {
|
||
|
const container = document.querySelector("nav.sidebar");
|
||
|
|
||
|
const sidebarToggle = createSidebarToggle();
|
||
|
container.insertBefore(sidebarToggle, container.firstChild);
|
||
|
|
||
|
const sidebar = document.createElement("div");
|
||
|
sidebar.id = "source-sidebar";
|
||
|
|
||
|
let hasFoundFile = false;
|
||
|
|
||
|
const title = document.createElement("div");
|
||
|
title.className = "title";
|
||
|
title.innerText = "Files";
|
||
|
sidebar.appendChild(title);
|
||
|
Object.keys(sourcesIndex).forEach(key => {
|
||
|
sourcesIndex[key][NAME_OFFSET] = key;
|
||
|
hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "",
|
||
|
hasFoundFile);
|
||
|
});
|
||
|
|
||
|
container.appendChild(sidebar);
|
||
|
// Focus on the current file in the source files sidebar.
|
||
|
const selected_elem = sidebar.getElementsByClassName("selected")[0];
|
||
|
if (typeof selected_elem !== "undefined") {
|
||
|
selected_elem.focus();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const lineNumbersRegex = /^#?(\d+)(?:-(\d+))?$/;
|
||
|
|
||
|
function highlightSourceLines(match) {
|
||
|
if (typeof match === "undefined") {
|
||
|
match = window.location.hash.match(lineNumbersRegex);
|
||
|
}
|
||
|
if (!match) {
|
||
|
return;
|
||
|
}
|
||
|
let from = parseInt(match[1], 10);
|
||
|
let to = from;
|
||
|
if (typeof match[2] !== "undefined") {
|
||
|
to = parseInt(match[2], 10);
|
||
|
}
|
||
|
if (to < from) {
|
||
|
const tmp = to;
|
||
|
to = from;
|
||
|
from = tmp;
|
||
|
}
|
||
|
let elem = document.getElementById(from);
|
||
|
if (!elem) {
|
||
|
return;
|
||
|
}
|
||
|
const x = document.getElementById(from);
|
||
|
if (x) {
|
||
|
x.scrollIntoView();
|
||
|
}
|
||
|
onEachLazy(document.getElementsByClassName("src-line-numbers"), e => {
|
||
|
onEachLazy(e.getElementsByTagName("span"), i_e => {
|
||
|
removeClass(i_e, "line-highlighted");
|
||
|
});
|
||
|
});
|
||
|
for (let i = from; i <= to; ++i) {
|
||
|
elem = document.getElementById(i);
|
||
|
if (!elem) {
|
||
|
break;
|
||
|
}
|
||
|
addClass(elem, "line-highlighted");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const handleSourceHighlight = (function() {
|
||
|
let prev_line_id = 0;
|
||
|
|
||
|
const set_fragment = name => {
|
||
|
const x = window.scrollX,
|
||
|
y = window.scrollY;
|
||
|
if (browserSupportsHistoryApi()) {
|
||
|
history.replaceState(null, null, "#" + name);
|
||
|
highlightSourceLines();
|
||
|
} else {
|
||
|
location.replace("#" + name);
|
||
|
}
|
||
|
// Prevent jumps when selecting one or many lines
|
||
|
window.scrollTo(x, y);
|
||
|
};
|
||
|
|
||
|
return ev => {
|
||
|
let cur_line_id = parseInt(ev.target.id, 10);
|
||
|
// It can happen when clicking not on a line number span.
|
||
|
if (isNaN(cur_line_id)) {
|
||
|
return;
|
||
|
}
|
||
|
ev.preventDefault();
|
||
|
|
||
|
if (ev.shiftKey && prev_line_id) {
|
||
|
// Swap selection if needed
|
||
|
if (prev_line_id > cur_line_id) {
|
||
|
const tmp = prev_line_id;
|
||
|
prev_line_id = cur_line_id;
|
||
|
cur_line_id = tmp;
|
||
|
}
|
||
|
|
||
|
set_fragment(prev_line_id + "-" + cur_line_id);
|
||
|
} else {
|
||
|
prev_line_id = cur_line_id;
|
||
|
|
||
|
set_fragment(cur_line_id);
|
||
|
}
|
||
|
};
|
||
|
}());
|
||
|
|
||
|
window.addEventListener("hashchange", () => {
|
||
|
const match = window.location.hash.match(lineNumbersRegex);
|
||
|
if (match) {
|
||
|
return highlightSourceLines(match);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
onEachLazy(document.getElementsByClassName("src-line-numbers"), el => {
|
||
|
el.addEventListener("click", handleSourceHighlight);
|
||
|
});
|
||
|
|
||
|
highlightSourceLines();
|
||
|
|
||
|
window.createSourceSidebar = createSourceSidebar;
|
||
|
})();
|