From 93520d2ad145b791b1b1a6c71cdea65b1943ffb6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Nov 2018 01:40:12 +0100 Subject: Add source file sidebar --- src/librustdoc/html/static/source-script.js | 147 ++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 src/librustdoc/html/static/source-script.js (limited to 'src/librustdoc/html/static/source-script.js') diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js new file mode 100644 index 00000000000..59b82361c09 --- /dev/null +++ b/src/librustdoc/html/static/source-script.js @@ -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 or the MIT license + * , 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 && search.currentFile !== null; +} + +function toggleSidebar() { + var sidebar = document.getElementById("source-sidebar"); + var child = this.children[0].children[0]; + if (child.innerText === "<") { + sidebar.style.right = ""; + this.style.right = ""; + child.innerText = ">"; + updateLocalStorage("rustdoc-source-sidebar-hidden", "false"); + } else { + sidebar.style.right = "-300px"; + this.style.right = "0"; + child.innerText = "<"; + updateLocalStorage("rustdoc-source-sidebar-hidden", "true"); + } +} + +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-hidden") === "true") { + inner2.innerText = "<"; + sidebarToggle.style.right = "0"; + } else { + inner2.innerText = ">"; + } + + 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-hidden") === "true") { + sidebar.style.right = "-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(); -- cgit 1.4.1-3-g733a5 From e87f8cc49b56ea2b8f01281a0b2baf20e12a319d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 16 Nov 2018 11:36:40 +0100 Subject: Source sidebar improvements --- src/librustdoc/html/layout.rs | 5 +- src/librustdoc/html/render.rs | 84 ++++++++++++++++------------- src/librustdoc/html/static/rustdoc.css | 27 +++++++--- src/librustdoc/html/static/source-script.js | 24 ++++----- src/librustdoc/html/static_files.rs | 6 +++ 5 files changed, 86 insertions(+), 60 deletions(-) (limited to 'src/librustdoc/html/static/source-script.js') diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index fd6bd83e29f..287e5a31888 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -194,9 +194,10 @@ pub fn render( .collect::(), suffix=page.resource_suffix, extra_scripts=extra_scripts.iter().map(|e| { - format!("", + format!("", root_path=page.root_path, - extra_script=e) + extra_script=e, + suffix=page.resource_suffix) }).collect::(), ) } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index a106a773571..7b020415af1 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -859,9 +859,11 @@ themePicker.onblur = handleThemeButtonsBlur; write_minify(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)), static_files::SETTINGS_JS, options.enable_minification)?; - write_minify(cx.dst.join(&format!("source-script{}.js", cx.shared.resource_suffix)), - include_str!("static/source-script.js"), - 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", @@ -990,8 +992,8 @@ themePicker.onblur = handleThemeButtonsBlur; } } - fn to_string(&self) -> String { - let mut subs: Vec<&Hierarchy> = self.children.iter().map(|(_, v)| v).collect(); + 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!("\"{}\"", @@ -1002,46 +1004,52 @@ themePicker.onblur = handleThemeButtonsBlur; // 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_string()).collect::>().join(","), + subs=subs.iter().map(|s| s.to_json_string()).collect::>().join(","), files=files.join(",")) } } - use std::path::Component; + 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 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_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); + 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 let dst = cx.dst.join("search-index.js"); @@ -1367,7 +1375,7 @@ impl<'a> SourceCollector<'a> { layout::render(&mut w, &self.scx.layout, &page, &(""), &Source(contents), self.scx.css_file_extension.is_some(), - &self.scx.themes, &["source-files.js", "source-script.js"])?; + &self.scx.themes, &["source-files", "source-script"])?; w.flush()?; self.scx.local_sources.insert(p.clone(), href); Ok(()) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 5dbba3ebab5..902c492105f 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1464,25 +1464,28 @@ kbd { #sidebar-toggle { position: fixed; top: 30px; - right: 300px; + left: 300px; z-index: 10; padding: 3px; - border-top-left-radius: 3px; - border-bottom-left-radius: 3px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; cursor: pointer; font-weight: bold; - transition: right 1s; + transition: left .5s; font-size: 1.2em; + border: 1px solid; + border-left: 0; } #source-sidebar { position: fixed; top: 0; bottom: 0; - right: 0; + left: 0; width: 300px; z-index: 1; overflow: auto; - transition: right 1s; + transition: left .5s; + border-right: 1px solid; } #source-sidebar > .title { font-size: 1.5em; @@ -1495,6 +1498,11 @@ div.children { padding-left: 27px; display: none; } +div.name { + cursor: pointer; + position: relative; + margin-left: 16px; +} div.files > a { display: block; padding: 0 3px; @@ -1507,10 +1515,13 @@ div.name.expand + .children { } div.name::before { content: "\25B6"; - display: inline-block; - padding-right: 4px; + padding-left: 4px; font-size: 0.7em; + position: absolute; + left: -16px; + top: 4px; } div.name.expand::before { transform: rotate(90deg); + left: -14px; } diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index 59b82361c09..f8e0cf196fb 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -72,21 +72,21 @@ function createDirEntry(elem, parent, fullPath, currentFile, hasFoundFile) { children.appendChild(files); parent.appendChild(name); parent.appendChild(children); - return hasFoundFile === true && search.currentFile !== null; + 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.right = ""; - this.style.right = ""; - child.innerText = ">"; + if (child.innerText === ">") { + sidebar.style.left = ""; + this.style.left = ""; + child.innerText = "<"; updateLocalStorage("rustdoc-source-sidebar-hidden", "false"); } else { - sidebar.style.right = "-300px"; - this.style.right = "0"; - child.innerText = "<"; + sidebar.style.left = "-300px"; + this.style.left = "0"; + child.innerText = ">"; updateLocalStorage("rustdoc-source-sidebar-hidden", "true"); } } @@ -102,10 +102,10 @@ function createSidebarToggle() { var inner2 = document.createElement("div"); inner2.style.marginTop = "-2px"; if (getCurrentValue("rustdoc-source-sidebar-hidden") === "true") { - inner2.innerText = "<"; - sidebarToggle.style.right = "0"; - } else { inner2.innerText = ">"; + sidebarToggle.style.left = "0"; + } else { + inner2.innerText = "<"; } inner1.appendChild(inner2); @@ -125,7 +125,7 @@ function createSourceSidebar() { var sidebar = document.createElement("div"); sidebar.id = "source-sidebar"; if (getCurrentValue("rustdoc-source-sidebar-hidden") === "true") { - sidebar.style.right = "-300px"; + sidebar.style.left = "-300px"; } var currentFile = getCurrentFilePath(); diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 3baa082bd0e..ee29f15d686 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -109,3 +109,9 @@ pub mod source_code_pro { /// 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"); } + +/// 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"); +} -- cgit 1.4.1-3-g733a5 From 8d67de4e9165a643b74dae822be325a983beb10b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 24 Nov 2018 11:43:52 +0100 Subject: Don't show file sidebar by default --- src/librustdoc/html/static/source-script.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/librustdoc/html/static/source-script.js') diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index f8e0cf196fb..1db8218dae6 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -82,12 +82,12 @@ function toggleSidebar() { sidebar.style.left = ""; this.style.left = ""; child.innerText = "<"; - updateLocalStorage("rustdoc-source-sidebar-hidden", "false"); + updateLocalStorage("rustdoc-source-sidebar-show", "true"); } else { sidebar.style.left = "-300px"; this.style.left = "0"; child.innerText = ">"; - updateLocalStorage("rustdoc-source-sidebar-hidden", "true"); + updateLocalStorage("rustdoc-source-sidebar-show", "false"); } } @@ -101,11 +101,11 @@ function createSidebarToggle() { var inner2 = document.createElement("div"); inner2.style.marginTop = "-2px"; - if (getCurrentValue("rustdoc-source-sidebar-hidden") === "true") { + if (getCurrentValue("rustdoc-source-sidebar-show") === "true") { + inner2.innerText = "<"; + } else { inner2.innerText = ">"; sidebarToggle.style.left = "0"; - } else { - inner2.innerText = "<"; } inner1.appendChild(inner2); @@ -124,7 +124,7 @@ function createSourceSidebar() { var sidebar = document.createElement("div"); sidebar.id = "source-sidebar"; - if (getCurrentValue("rustdoc-source-sidebar-hidden") === "true") { + if (getCurrentValue("rustdoc-source-sidebar-show") !== "true") { sidebar.style.left = "-300px"; } -- cgit 1.4.1-3-g733a5