Auto merge of #55707 - GuillaumeGomez:file-sidebar, r=QuietMisdreavus
Add source file sidebar This is just a start currently but that gives a good overview of what it'll look like: <img width="1440" alt="screenshot 2018-11-06 at 01 39 15" src="https://user-images.githubusercontent.com/3050060/48035592-05336180-e165-11e8-82e1-5ead0c345eb9.png"> r? @QuietMisdreavus
This commit is contained in:
commit
596e10fd32
10 changed files with 425 additions and 63 deletions
|
@ -33,7 +33,7 @@ pub struct Page<'a> {
|
||||||
|
|
||||||
pub fn render<T: fmt::Display, S: fmt::Display>(
|
pub fn render<T: fmt::Display, S: fmt::Display>(
|
||||||
dst: &mut dyn io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T,
|
dst: &mut dyn io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T,
|
||||||
css_file_extension: bool, themes: &[PathBuf])
|
css_file_extension: bool, themes: &[PathBuf], extra_scripts: &[&str])
|
||||||
-> io::Result<()>
|
-> io::Result<()>
|
||||||
{
|
{
|
||||||
write!(dst,
|
write!(dst,
|
||||||
|
@ -149,6 +149,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
|
||||||
</script>\
|
</script>\
|
||||||
<script src=\"{root_path}aliases.js\"></script>\
|
<script src=\"{root_path}aliases.js\"></script>\
|
||||||
<script src=\"{root_path}main{suffix}.js\"></script>\
|
<script src=\"{root_path}main{suffix}.js\"></script>\
|
||||||
|
{extra_scripts}\
|
||||||
<script defer src=\"{root_path}search-index.js\"></script>\
|
<script defer src=\"{root_path}search-index.js\"></script>\
|
||||||
</body>\
|
</body>\
|
||||||
</html>",
|
</html>",
|
||||||
|
@ -192,6 +193,11 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
|
||||||
page.resource_suffix))
|
page.resource_suffix))
|
||||||
.collect::<String>(),
|
.collect::<String>(),
|
||||||
suffix=page.resource_suffix,
|
suffix=page.resource_suffix,
|
||||||
|
extra_scripts=extra_scripts.iter().map(|e| {
|
||||||
|
format!("<script src=\"{root_path}{extra_script}.js\"></script>",
|
||||||
|
root_path=page.root_path,
|
||||||
|
extra_script=e)
|
||||||
|
}).collect::<String>(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -859,6 +859,11 @@ themePicker.onblur = handleThemeButtonsBlur;
|
||||||
write_minify(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
|
write_minify(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
|
||||||
static_files::SETTINGS_JS,
|
static_files::SETTINGS_JS,
|
||||||
options.enable_minification)?;
|
options.enable_minification)?;
|
||||||
|
if cx.shared.include_sources {
|
||||||
|
write_minify(cx.dst.join(&format!("source-script{}.js", cx.shared.resource_suffix)),
|
||||||
|
static_files::sidebar::SOURCE_SCRIPT,
|
||||||
|
options.enable_minification)?;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut data = format!("var resourcesSuffix = \"{}\";\n",
|
let mut data = format!("var resourcesSuffix = \"{}\";\n",
|
||||||
|
@ -969,10 +974,88 @@ themePicker.onblur = handleThemeButtonsBlur;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::ffi::OsString;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Hierarchy {
|
||||||
|
elem: OsString,
|
||||||
|
children: FxHashMap<OsString, Hierarchy>,
|
||||||
|
elems: FxHashSet<OsString>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hierarchy {
|
||||||
|
fn new(elem: OsString) -> Hierarchy {
|
||||||
|
Hierarchy {
|
||||||
|
elem,
|
||||||
|
children: FxHashMap::default(),
|
||||||
|
elems: FxHashSet::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_json_string(&self) -> String {
|
||||||
|
let mut subs: Vec<&Hierarchy> = self.children.values().collect();
|
||||||
|
subs.sort_unstable_by(|a, b| a.elem.cmp(&b.elem));
|
||||||
|
let mut files = self.elems.iter()
|
||||||
|
.map(|s| format!("\"{}\"",
|
||||||
|
s.to_str()
|
||||||
|
.expect("invalid osstring conversion")))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
files.sort_unstable_by(|a, b| a.cmp(b));
|
||||||
|
// FIXME(imperio): we could avoid to generate "dirs" and "files" if they're empty.
|
||||||
|
format!("{{\"name\":\"{name}\",\"dirs\":[{subs}],\"files\":[{files}]}}",
|
||||||
|
name=self.elem.to_str().expect("invalid osstring conversion"),
|
||||||
|
subs=subs.iter().map(|s| s.to_json_string()).collect::<Vec<_>>().join(","),
|
||||||
|
files=files.join(","))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cx.shared.include_sources {
|
||||||
|
use std::path::Component;
|
||||||
|
|
||||||
|
let mut hierarchy = Hierarchy::new(OsString::new());
|
||||||
|
for source in cx.shared.local_sources.iter()
|
||||||
|
.filter_map(|p| p.0.strip_prefix(&cx.shared.src_root)
|
||||||
|
.ok()) {
|
||||||
|
let mut h = &mut hierarchy;
|
||||||
|
let mut elems = source.components()
|
||||||
|
.filter_map(|s| {
|
||||||
|
match s {
|
||||||
|
Component::Normal(s) => Some(s.to_owned()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.peekable();
|
||||||
|
loop {
|
||||||
|
let cur_elem = elems.next().expect("empty file path");
|
||||||
|
if elems.peek().is_none() {
|
||||||
|
h.elems.insert(cur_elem);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
let e = cur_elem.clone();
|
||||||
|
h.children.entry(cur_elem.clone()).or_insert_with(|| Hierarchy::new(e));
|
||||||
|
h = h.children.get_mut(&cur_elem).expect("not found child");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dst = cx.dst.join("source-files.js");
|
||||||
|
let (mut all_sources, _krates) = try_err!(collect(&dst, &krate.name, "sourcesIndex"), &dst);
|
||||||
|
all_sources.push(format!("sourcesIndex['{}'] = {};",
|
||||||
|
&krate.name,
|
||||||
|
hierarchy.to_json_string()));
|
||||||
|
all_sources.sort();
|
||||||
|
let mut w = try_err!(File::create(&dst), &dst);
|
||||||
|
try_err!(writeln!(&mut w,
|
||||||
|
"var N = null;var sourcesIndex = {{}};\n{}",
|
||||||
|
all_sources.join("\n")),
|
||||||
|
&dst);
|
||||||
|
}
|
||||||
|
|
||||||
// Update the search index
|
// Update the search index
|
||||||
let dst = cx.dst.join("search-index.js");
|
let dst = cx.dst.join("search-index.js");
|
||||||
let (mut all_indexes, mut krates) = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst);
|
let (mut all_indexes, mut krates) = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst);
|
||||||
all_indexes.push(search_index);
|
all_indexes.push(search_index);
|
||||||
|
|
||||||
// Sort the indexes by crate so the file will be generated identically even
|
// Sort the indexes by crate so the file will be generated identically even
|
||||||
// with rustdoc running in parallel.
|
// with rustdoc running in parallel.
|
||||||
all_indexes.sort();
|
all_indexes.sort();
|
||||||
|
@ -1020,7 +1103,7 @@ themePicker.onblur = handleThemeButtonsBlur;
|
||||||
try_err!(layout::render(&mut w, &cx.shared.layout,
|
try_err!(layout::render(&mut w, &cx.shared.layout,
|
||||||
&page, &(""), &content,
|
&page, &(""), &content,
|
||||||
cx.shared.css_file_extension.is_some(),
|
cx.shared.css_file_extension.is_some(),
|
||||||
&cx.shared.themes), &dst);
|
&cx.shared.themes, &[]), &dst);
|
||||||
try_err!(w.flush(), &dst);
|
try_err!(w.flush(), &dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1292,7 +1375,8 @@ impl<'a> SourceCollector<'a> {
|
||||||
layout::render(&mut w, &self.scx.layout,
|
layout::render(&mut w, &self.scx.layout,
|
||||||
&page, &(""), &Source(contents),
|
&page, &(""), &Source(contents),
|
||||||
self.scx.css_file_extension.is_some(),
|
self.scx.css_file_extension.is_some(),
|
||||||
&self.scx.themes)?;
|
&self.scx.themes, &["source-files",
|
||||||
|
&format!("source-script{}", page.resource_suffix)])?;
|
||||||
w.flush()?;
|
w.flush()?;
|
||||||
self.scx.local_sources.insert(p.clone(), href);
|
self.scx.local_sources.insert(p.clone(), href);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1890,7 +1974,7 @@ impl Context {
|
||||||
try_err!(layout::render(&mut w, &self.shared.layout,
|
try_err!(layout::render(&mut w, &self.shared.layout,
|
||||||
&page, &sidebar, &all,
|
&page, &sidebar, &all,
|
||||||
self.shared.css_file_extension.is_some(),
|
self.shared.css_file_extension.is_some(),
|
||||||
&self.shared.themes),
|
&self.shared.themes, &[]),
|
||||||
&final_file);
|
&final_file);
|
||||||
|
|
||||||
// Generating settings page.
|
// Generating settings page.
|
||||||
|
@ -1910,7 +1994,7 @@ impl Context {
|
||||||
try_err!(layout::render(&mut w, &layout,
|
try_err!(layout::render(&mut w, &layout,
|
||||||
&page, &sidebar, &settings,
|
&page, &sidebar, &settings,
|
||||||
self.shared.css_file_extension.is_some(),
|
self.shared.css_file_extension.is_some(),
|
||||||
&themes),
|
&themes, &[]),
|
||||||
&settings_file);
|
&settings_file);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1968,7 +2052,7 @@ impl Context {
|
||||||
&Sidebar{ cx: self, item: it },
|
&Sidebar{ cx: self, item: it },
|
||||||
&Item{ cx: self, item: it },
|
&Item{ cx: self, item: it },
|
||||||
self.shared.css_file_extension.is_some(),
|
self.shared.css_file_extension.is_some(),
|
||||||
&self.shared.themes)?;
|
&self.shared.themes, &[])?;
|
||||||
} else {
|
} else {
|
||||||
let mut url = self.root_path();
|
let mut url = self.root_path();
|
||||||
if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) {
|
if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) {
|
||||||
|
|
|
@ -13,6 +13,19 @@
|
||||||
/*jslint browser: true, es5: true */
|
/*jslint browser: true, es5: true */
|
||||||
/*globals $: true, rootPath: true */
|
/*globals $: true, rootPath: true */
|
||||||
|
|
||||||
|
if (!String.prototype.startsWith) {
|
||||||
|
String.prototype.startsWith = function(searchString, position) {
|
||||||
|
position = position || 0;
|
||||||
|
return this.indexOf(searchString, position) === position;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!String.prototype.endsWith) {
|
||||||
|
String.prototype.endsWith = function(suffix, length) {
|
||||||
|
var l = length || this.length;
|
||||||
|
return this.indexOf(suffix, l - suffix.length) !== -1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
@ -57,19 +70,6 @@
|
||||||
|
|
||||||
var titleBeforeSearch = document.title;
|
var titleBeforeSearch = document.title;
|
||||||
|
|
||||||
if (!String.prototype.startsWith) {
|
|
||||||
String.prototype.startsWith = function(searchString, position) {
|
|
||||||
position = position || 0;
|
|
||||||
return this.indexOf(searchString, position) === position;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!String.prototype.endsWith) {
|
|
||||||
String.prototype.endsWith = function(suffix, length) {
|
|
||||||
var l = length || this.length;
|
|
||||||
return this.indexOf(suffix, l - suffix.length) !== -1;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPageId() {
|
function getPageId() {
|
||||||
var id = document.location.href.split('#')[1];
|
var id = document.location.href.split('#')[1];
|
||||||
if (id) {
|
if (id) {
|
||||||
|
@ -78,46 +78,6 @@
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasClass(elem, className) {
|
|
||||||
if (elem && className && elem.className) {
|
|
||||||
var elemClass = elem.className;
|
|
||||||
var start = elemClass.indexOf(className);
|
|
||||||
if (start === -1) {
|
|
||||||
return false;
|
|
||||||
} else if (elemClass.length === className.length) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
if (start > 0 && elemClass[start - 1] !== ' ') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var end = start + className.length;
|
|
||||||
return !(end < elemClass.length && elemClass[end] !== ' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addClass(elem, className) {
|
|
||||||
if (elem && className && !hasClass(elem, className)) {
|
|
||||||
if (elem.className && elem.className.length > 0) {
|
|
||||||
elem.className += ' ' + className;
|
|
||||||
} else {
|
|
||||||
elem.className = className;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeClass(elem, className) {
|
|
||||||
if (elem && className && elem.className) {
|
|
||||||
elem.className = (" " + elem.className + " ").replace(" " + className + " ", " ")
|
|
||||||
.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isHidden(elem) {
|
|
||||||
return (elem.offsetParent === null)
|
|
||||||
}
|
|
||||||
|
|
||||||
function showSidebar() {
|
function showSidebar() {
|
||||||
var elems = document.getElementsByClassName("sidebar-elems")[0];
|
var elems = document.getElementsByClassName("sidebar-elems")[0];
|
||||||
if (elems) {
|
if (elems) {
|
||||||
|
|
|
@ -113,7 +113,8 @@ h3.impl, h3.method, h3.type {
|
||||||
|
|
||||||
h1, h2, h3, h4,
|
h1, h2, h3, h4,
|
||||||
.sidebar, a.source, .search-input, .content table :not(code)>a,
|
.sidebar, a.source, .search-input, .content table :not(code)>a,
|
||||||
.collapse-toggle, div.item-list .out-of-band {
|
.collapse-toggle, div.item-list .out-of-band,
|
||||||
|
#source-sidebar, #sidebar-toggle {
|
||||||
font-family: "Fira Sans", sans-serif;
|
font-family: "Fira Sans", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,9 +669,9 @@ a {
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
.content .search-results td:first-child a:after {
|
.content .search-results td:first-child a:after {
|
||||||
clear: both;
|
clear: both;
|
||||||
content: "";
|
content: "";
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.content .search-results td:first-child a span {
|
.content .search-results td:first-child a span {
|
||||||
float: left;
|
float: left;
|
||||||
|
@ -1459,3 +1460,68 @@ kbd {
|
||||||
.non-exhaustive {
|
.non-exhaustive {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#sidebar-toggle {
|
||||||
|
position: fixed;
|
||||||
|
top: 30px;
|
||||||
|
left: 300px;
|
||||||
|
z-index: 10;
|
||||||
|
padding: 3px;
|
||||||
|
border-top-right-radius: 3px;
|
||||||
|
border-bottom-right-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: left .5s;
|
||||||
|
font-size: 1.2em;
|
||||||
|
border: 1px solid;
|
||||||
|
border-left: 0;
|
||||||
|
}
|
||||||
|
#source-sidebar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 300px;
|
||||||
|
z-index: 1;
|
||||||
|
overflow: auto;
|
||||||
|
transition: left .5s;
|
||||||
|
border-right: 1px solid;
|
||||||
|
}
|
||||||
|
#source-sidebar > .title {
|
||||||
|
font-size: 1.5em;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.children {
|
||||||
|
padding-left: 27px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
div.name {
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
div.files > a {
|
||||||
|
display: block;
|
||||||
|
padding: 0 3px;
|
||||||
|
}
|
||||||
|
div.files > a:hover, div.name:hover {
|
||||||
|
background-color: #a14b4b;
|
||||||
|
}
|
||||||
|
div.name.expand + .children {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
div.name::before {
|
||||||
|
content: "\25B6";
|
||||||
|
padding-left: 4px;
|
||||||
|
font-size: 0.7em;
|
||||||
|
position: absolute;
|
||||||
|
left: -16px;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
|
div.name.expand::before {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
left: -14px;
|
||||||
|
}
|
||||||
|
|
147
src/librustdoc/html/static/source-script.js
Normal file
147
src/librustdoc/html/static/source-script.js
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/*!
|
||||||
|
* Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
* file at the top-level directory of this distribution and at
|
||||||
|
* http://rust-lang.org/COPYRIGHT.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
* <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
* option. This file may not be copied, modified, or distributed
|
||||||
|
* except according to those terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getCurrentFilePath() {
|
||||||
|
var parts = window.location.pathname.split("/");
|
||||||
|
var rootPathParts = window.rootPath.split("/");
|
||||||
|
|
||||||
|
for (var i = 0; i < rootPathParts.length; ++i) {
|
||||||
|
if (rootPathParts[i] === "..") {
|
||||||
|
parts.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var file = window.location.pathname.substring(parts.join("/").length);
|
||||||
|
if (file.startsWith("/")) {
|
||||||
|
file = file.substring(1);
|
||||||
|
}
|
||||||
|
return file.substring(0, file.length - 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDirEntry(elem, parent, fullPath, currentFile, hasFoundFile) {
|
||||||
|
var name = document.createElement("div");
|
||||||
|
name.className = "name";
|
||||||
|
|
||||||
|
fullPath += elem["name"] + "/";
|
||||||
|
|
||||||
|
name.onclick = function() {
|
||||||
|
if (hasClass(this, "expand")) {
|
||||||
|
removeClass(this, "expand");
|
||||||
|
} else {
|
||||||
|
addClass(this, "expand");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
name.innerText = elem["name"];
|
||||||
|
|
||||||
|
var children = document.createElement("div");
|
||||||
|
children.className = "children";
|
||||||
|
var folders = document.createElement("div");
|
||||||
|
folders.className = "folders";
|
||||||
|
for (var i = 0; i < elem.dirs.length; ++i) {
|
||||||
|
if (createDirEntry(elem.dirs[i], folders, fullPath, currentFile,
|
||||||
|
hasFoundFile) === true) {
|
||||||
|
addClass(name, "expand");
|
||||||
|
hasFoundFile = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
children.appendChild(folders);
|
||||||
|
|
||||||
|
var files = document.createElement("div");
|
||||||
|
files.className = "files";
|
||||||
|
for (i = 0; i < elem.files.length; ++i) {
|
||||||
|
var file = document.createElement("a");
|
||||||
|
file.innerText = elem.files[i];
|
||||||
|
file.href = window.rootPath + "src/" + fullPath + elem.files[i] + ".html";
|
||||||
|
if (hasFoundFile === false &&
|
||||||
|
currentFile === fullPath + elem.files[i]) {
|
||||||
|
file.className = "selected";
|
||||||
|
addClass(name, "expand");
|
||||||
|
hasFoundFile = true;
|
||||||
|
}
|
||||||
|
files.appendChild(file);
|
||||||
|
}
|
||||||
|
search.fullPath = fullPath;
|
||||||
|
children.appendChild(files);
|
||||||
|
parent.appendChild(name);
|
||||||
|
parent.appendChild(children);
|
||||||
|
return hasFoundFile === true && currentFile.startsWith(fullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSidebar() {
|
||||||
|
var sidebar = document.getElementById("source-sidebar");
|
||||||
|
var child = this.children[0].children[0];
|
||||||
|
if (child.innerText === ">") {
|
||||||
|
sidebar.style.left = "";
|
||||||
|
this.style.left = "";
|
||||||
|
child.innerText = "<";
|
||||||
|
updateLocalStorage("rustdoc-source-sidebar-show", "true");
|
||||||
|
} else {
|
||||||
|
sidebar.style.left = "-300px";
|
||||||
|
this.style.left = "0";
|
||||||
|
child.innerText = ">";
|
||||||
|
updateLocalStorage("rustdoc-source-sidebar-show", "false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSidebarToggle() {
|
||||||
|
var sidebarToggle = document.createElement("div");
|
||||||
|
sidebarToggle.id = "sidebar-toggle";
|
||||||
|
sidebarToggle.onclick = toggleSidebar;
|
||||||
|
|
||||||
|
var inner1 = document.createElement("div");
|
||||||
|
inner1.style.position = "relative";
|
||||||
|
|
||||||
|
var inner2 = document.createElement("div");
|
||||||
|
inner2.style.marginTop = "-2px";
|
||||||
|
if (getCurrentValue("rustdoc-source-sidebar-show") === "true") {
|
||||||
|
inner2.innerText = "<";
|
||||||
|
} else {
|
||||||
|
inner2.innerText = ">";
|
||||||
|
sidebarToggle.style.left = "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
inner1.appendChild(inner2);
|
||||||
|
sidebarToggle.appendChild(inner1);
|
||||||
|
return sidebarToggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSourceSidebar() {
|
||||||
|
if (window.rootPath.endsWith("/") === false) {
|
||||||
|
window.rootPath += "/";
|
||||||
|
}
|
||||||
|
var main = document.getElementById("main");
|
||||||
|
|
||||||
|
var sidebarToggle = createSidebarToggle();
|
||||||
|
main.insertBefore(sidebarToggle, main.firstChild);
|
||||||
|
|
||||||
|
var sidebar = document.createElement("div");
|
||||||
|
sidebar.id = "source-sidebar";
|
||||||
|
if (getCurrentValue("rustdoc-source-sidebar-show") !== "true") {
|
||||||
|
sidebar.style.left = "-300px";
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentFile = getCurrentFilePath();
|
||||||
|
var hasFoundFile = false;
|
||||||
|
|
||||||
|
var title = document.createElement("div");
|
||||||
|
title.className = "title";
|
||||||
|
title.innerText = "Files";
|
||||||
|
sidebar.appendChild(title);
|
||||||
|
Object.keys(sourcesIndex).forEach(function(key) {
|
||||||
|
sourcesIndex[key].name = key;
|
||||||
|
hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "",
|
||||||
|
currentFile, hasFoundFile);
|
||||||
|
});
|
||||||
|
|
||||||
|
main.insertBefore(sidebar, main.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
createSourceSidebar();
|
|
@ -15,6 +15,46 @@ var mainTheme = document.getElementById("mainThemeStyle");
|
||||||
|
|
||||||
var savedHref = [];
|
var savedHref = [];
|
||||||
|
|
||||||
|
function hasClass(elem, className) {
|
||||||
|
if (elem && className && elem.className) {
|
||||||
|
var elemClass = elem.className;
|
||||||
|
var start = elemClass.indexOf(className);
|
||||||
|
if (start === -1) {
|
||||||
|
return false;
|
||||||
|
} else if (elemClass.length === className.length) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (start > 0 && elemClass[start - 1] !== ' ') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var end = start + className.length;
|
||||||
|
return !(end < elemClass.length && elemClass[end] !== ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addClass(elem, className) {
|
||||||
|
if (elem && className && !hasClass(elem, className)) {
|
||||||
|
if (elem.className && elem.className.length > 0) {
|
||||||
|
elem.className += ' ' + className;
|
||||||
|
} else {
|
||||||
|
elem.className = className;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeClass(elem, className) {
|
||||||
|
if (elem && className && elem.className) {
|
||||||
|
elem.className = (" " + elem.className + " ").replace(" " + className + " ", " ")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isHidden(elem) {
|
||||||
|
return (elem.offsetParent === null)
|
||||||
|
}
|
||||||
|
|
||||||
function onEach(arr, func, reversed) {
|
function onEach(arr, func, reversed) {
|
||||||
if (arr && arr.length > 0 && func) {
|
if (arr && arr.length > 0 && func) {
|
||||||
if (reversed !== true) {
|
if (reversed !== true) {
|
||||||
|
|
|
@ -416,3 +416,22 @@ kbd {
|
||||||
.impl-items code {
|
.impl-items code {
|
||||||
background-color: rgba(0, 0, 0, 0);
|
background-color: rgba(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#sidebar-toggle {
|
||||||
|
background-color: #565656;
|
||||||
|
}
|
||||||
|
#sidebar-toggle:hover {
|
||||||
|
background-color: #676767;
|
||||||
|
}
|
||||||
|
#source-sidebar {
|
||||||
|
background-color: #565656;
|
||||||
|
}
|
||||||
|
#source-sidebar > .title {
|
||||||
|
border-bottom-color: #ccc;
|
||||||
|
}
|
||||||
|
div.files > a:hover, div.name:hover {
|
||||||
|
background-color: #444;
|
||||||
|
}
|
||||||
|
div.files > .selected {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
|
@ -410,3 +410,22 @@ kbd {
|
||||||
.impl-items code {
|
.impl-items code {
|
||||||
background-color: rgba(0, 0, 0, 0);
|
background-color: rgba(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#sidebar-toggle {
|
||||||
|
background-color: #F1F1F1;
|
||||||
|
}
|
||||||
|
#sidebar-toggle:hover {
|
||||||
|
background-color: #E0E0E0;
|
||||||
|
}
|
||||||
|
#source-sidebar {
|
||||||
|
background-color: #F1F1F1;
|
||||||
|
}
|
||||||
|
#source-sidebar > .title {
|
||||||
|
border-bottom-color: #ccc;
|
||||||
|
}
|
||||||
|
div.files > a:hover, div.name:hover {
|
||||||
|
background-color: #E0E0E0;
|
||||||
|
}
|
||||||
|
div.files > .selected {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
|
@ -109,3 +109,9 @@ pub mod source_code_pro {
|
||||||
/// The file `SourceCodePro-LICENSE.txt`, the license text of the Source Code Pro font.
|
/// The file `SourceCodePro-LICENSE.txt`, the license text of the Source Code Pro font.
|
||||||
pub static LICENSE: &'static [u8] = include_bytes!("static/SourceCodePro-LICENSE.txt");
|
pub static LICENSE: &'static [u8] = include_bytes!("static/SourceCodePro-LICENSE.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Files related to the sidebar in rustdoc sources.
|
||||||
|
pub mod sidebar {
|
||||||
|
/// File script to handle sidebar.
|
||||||
|
pub static SOURCE_SCRIPT: &'static str = include_str!("static/source-script.js");
|
||||||
|
}
|
||||||
|
|
15
src/test/rustdoc/source-file.rs
Normal file
15
src/test/rustdoc/source-file.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![crate_name = "foo"]
|
||||||
|
|
||||||
|
// @has source-files.js source-file.rs
|
||||||
|
|
||||||
|
pub struct Foo;
|
Loading…
Add table
Add a link
Reference in a new issue