From 09454513d196613e3e60ab52b7479f9d65d6270a Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Sun, 9 May 2021 11:21:38 -0700 Subject: [PATCH] Move global click handlers to per-element ones. In rustdoc's main.js, we had an onclick handler for the whole document that would dispatch to handlers for various elements. This change attaches the handlers to the elements that trigger them, instead. This simplfies the code and avoids reimplementing the browser's bubbling functionality. As part of this change, change from a class to an id for help button. Move the handlers and associated code for highlighting source lines into source-script.js (and factor out a shared regex). --- src/librustdoc/html/layout.rs | 2 +- src/librustdoc/html/markdown.rs | 1 + src/librustdoc/html/static/main.js | 146 ++++---------------- src/librustdoc/html/static/rustdoc.css | 8 +- src/librustdoc/html/static/source-script.js | 97 +++++++++++++ src/librustdoc/html/static/themes/ayu.css | 4 +- src/librustdoc/html/static/themes/dark.css | 4 +- src/librustdoc/html/static/themes/light.css | 4 +- 8 files changed, 138 insertions(+), 128 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 99e96fdcf1eb4..ec04c94dc11f9 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -105,7 +105,7 @@ crate fn render( placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \ type=\"search\">\ \ - + \ FxHashMap { map.insert("theme-picker".to_owned(), 1); map.insert("theme-choices".to_owned(), 1); map.insert("settings-menu".to_owned(), 1); + map.insert("help-button".to_owned(), 1); map.insert("main".to_owned(), 1); map.insert("search".to_owned(), 1); map.insert("crate-search".to_owned(), 1); diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index dc65e14ab37b8..65f936819f589 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -381,56 +381,9 @@ function hideThemeButtonState() { } } - function highlightSourceLines(match, ev) { - if (typeof match === "undefined") { - // If we're in mobile mode, we should hide the sidebar in any case. - hideSidebar(); - match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/); - } - if (!match) { - return; - } - var from = parseInt(match[1], 10); - var to = from; - if (typeof match[2] !== "undefined") { - to = parseInt(match[2], 10); - } - if (to < from) { - var tmp = to; - to = from; - from = tmp; - } - var elem = document.getElementById(from); - if (!elem) { - return; - } - if (!ev) { - var x = document.getElementById(from); - if (x) { - x.scrollIntoView(); - } - } - onEachLazy(document.getElementsByClassName("line-numbers"), function(e) { - onEachLazy(e.getElementsByTagName("span"), function(i_e) { - removeClass(i_e, "line-highlighted"); - }); - }); - for (var i = from; i <= to; ++i) { - elem = document.getElementById(i); - if (!elem) { - break; - } - addClass(elem, "line-highlighted"); - } - } - function onHashChange(ev) { // If we're in mobile mode, we should hide the sidebar in any case. hideSidebar(); - var match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/); - if (match) { - return highlightSourceLines(match, ev); - } handleHashes(ev); } @@ -585,78 +538,9 @@ function hideThemeButtonState() { } } - function findParentElement(elem, tagName) { - do { - if (elem && elem.tagName === tagName) { - return elem; - } - elem = elem.parentNode; - } while (elem); - return null; - } - document.addEventListener("keypress", handleShortcut); document.addEventListener("keydown", handleShortcut); - var handleSourceHighlight = (function() { - var prev_line_id = 0; - - var set_fragment = function(name) { - var x = window.scrollX, - y = window.scrollY; - if (searchState.browserSupportsHistoryApi()) { - history.replaceState(null, null, "#" + name); - highlightSourceLines(); - } else { - location.replace("#" + name); - } - // Prevent jumps when selecting one or many lines - window.scrollTo(x, y); - }; - - return function(ev) { - var cur_line_id = parseInt(ev.target.id, 10); - ev.preventDefault(); - - if (ev.shiftKey && prev_line_id) { - // Swap selection if needed - if (prev_line_id > cur_line_id) { - var 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); - } - }; - }()); - - document.addEventListener("click", function(ev) { - var helpElem = getHelpElement(false); - if (hasClass(ev.target, "help-button")) { - displayHelp(true, ev); - } else if (ev.target.tagName === "SPAN" && hasClass(ev.target.parentNode, "line-numbers")) { - handleSourceHighlight(ev); - } else if (helpElem && hasClass(helpElem, "hidden") === false) { - var is_inside_help_popup = ev.target !== helpElem && helpElem.contains(ev.target); - if (is_inside_help_popup === false) { - addClass(helpElem, "hidden"); - removeClass(document.body, "blur"); - } - } else { - // Making a collapsed element visible on onhashchange seems - // too late - var a = findParentElement(ev.target, "A"); - if (a && a.hash) { - expandSection(a.hash.replace(/^#/, "")); - } - } - }); - (function() { var x = document.getElementsByClassName("version-selector"); if (x.length > 0) { @@ -1121,6 +1005,27 @@ function hideThemeButtonState() { }); }()); + function handleClick(id, f) { + var elem = document.getElementById(id); + if (elem) { + elem.addEventListener("click", f); + } + } + handleClick("help-button", function(ev) { + displayHelp(true, ev); + }); + + onEachLazy(document.getElementsByTagName("a"), function(el) { + // For clicks on internal links ( tags with a hash property), we expand the section we're + // jumping to *before* jumping there. We can't do this in onHashChange, because it changes + // the height of the document so we wind up scrolled to the wrong place. + if (el.hash) { + el.addEventListener("click", function() { + expandSection(el.hash.slice(1)); + }); + } + }); + onEachLazy(document.getElementsByClassName("notable-traits"), function(e) { e.onclick = function() { this.getElementsByClassName('notable-traits-tooltiptext')[0] @@ -1165,6 +1070,13 @@ function hideThemeButtonState() { addClass(popup, "hidden"); popup.id = "help"; + popup.addEventListener("click", function(ev) { + if (ev.target === popup) { + // Clicked the blurred zone outside the help popup; dismiss help. + displayHelp(false, ev); + } + }); + var book_info = document.createElement("span"); book_info.innerHTML = "You can find more information in \ the rustdoc book."; @@ -1223,7 +1135,7 @@ function hideThemeButtonState() { } onHashChange(null); - window.onhashchange = onHashChange; + window.addEventListener("hashchange", onHashChange); searchState.setup(); }()); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index aaa2525644f11..6622756bcc36e 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1289,7 +1289,7 @@ h4 > .notable-traits { outline: none; } -#settings-menu, .help-button { +#settings-menu, #help-button { position: absolute; top: 10px; } @@ -1299,7 +1299,7 @@ h4 > .notable-traits { outline: none; } -#theme-picker, #settings-menu, .help-button, #copy-path { +#theme-picker, #settings-menu, #help-button, #copy-path { padding: 4px; width: 27px; height: 29px; @@ -1308,7 +1308,7 @@ h4 > .notable-traits { cursor: pointer; } -.help-button { +#help-button { right: 30px; font-family: "Fira Sans", Arial, sans-serif; text-align: center; @@ -1593,7 +1593,7 @@ h4 > .notable-traits { } /* We don't display the help button on mobile devices. */ - .help-button { + #help-button { display: none; } .search-container > div { diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index 42b54e4cc1e46..a5aa2c5f67819 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -3,6 +3,7 @@ // Local js definitions: /* global addClass, getCurrentValue, hasClass, removeClass, updateLocalStorage */ +(function() { function getCurrentFilePath() { var parts = window.location.pathname.split("/"); @@ -150,3 +151,99 @@ function createSourceSidebar() { selected_elem.focus(); } } + +var lineNumbersRegex = /^#?(\d+)(?:-(\d+))?$/; + +function highlightSourceLines(match, ev) { + if (typeof match === "undefined") { + match = window.location.hash.match(lineNumbersRegex); + } + if (!match) { + return; + } + var from = parseInt(match[1], 10); + var to = from; + if (typeof match[2] !== "undefined") { + to = parseInt(match[2], 10); + } + if (to < from) { + var tmp = to; + to = from; + from = tmp; + } + var elem = document.getElementById(from); + if (!elem) { + return; + } + if (!ev) { + var x = document.getElementById(from); + if (x) { + x.scrollIntoView(); + } + } + onEachLazy(document.getElementsByClassName("line-numbers"), function(e) { + onEachLazy(e.getElementsByTagName("span"), function(i_e) { + removeClass(i_e, "line-highlighted"); + }); + }); + for (var i = from; i <= to; ++i) { + elem = document.getElementById(i); + if (!elem) { + break; + } + addClass(elem, "line-highlighted"); + } +} + +var handleSourceHighlight = (function() { + var prev_line_id = 0; + + var set_fragment = function(name) { + var x = window.scrollX, + y = window.scrollY; + if (searchState.browserSupportsHistoryApi()) { + history.replaceState(null, null, "#" + name); + highlightSourceLines(); + } else { + location.replace("#" + name); + } + // Prevent jumps when selecting one or many lines + window.scrollTo(x, y); + }; + + return function(ev) { + var cur_line_id = parseInt(ev.target.id, 10); + ev.preventDefault(); + + if (ev.shiftKey && prev_line_id) { + // Swap selection if needed + if (prev_line_id > cur_line_id) { + var 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", function() { + var match = window.location.hash.match(lineNumbersRegex); + if (match) { + return highlightSourceLines(match, ev); + } +}); + +onEachLazy(document.getElementsByClassName("line-numbers"), function(el) { + el.addEventListener("click", handleSourceHighlight); +}); + +highlightSourceLines(); + +window.createSourceSidebar = createSourceSidebar; +})(); diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index aafb7f6300ea4..08148fdcf9597 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -503,7 +503,7 @@ kbd { box-shadow-color: #c6cbd1; } -#theme-picker, #settings-menu, .help-button, #copy-path { +#theme-picker, #settings-menu, #help-button, #copy-path { border-color: #5c6773; background-color: #0f1419; color: #fff; @@ -515,7 +515,7 @@ kbd { #theme-picker:hover, #theme-picker:focus, #settings-menu:hover, #settings-menu:focus, -.help-button:hover, .help-button:focus, +#help-button:hover, #help-button:focus, #copy-path:hover, #copy-path:focus { border-color: #e0e0e0; } diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 715605d7b3785..8ee51d39c9214 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -393,7 +393,7 @@ kbd { box-shadow-color: #c6cbd1; } -#theme-picker, #settings-menu, .help-button, #copy-path { +#theme-picker, #settings-menu, #help-button, #copy-path { border-color: #e0e0e0; background: #f0f0f0; color: #000; @@ -401,7 +401,7 @@ kbd { #theme-picker:hover, #theme-picker:focus, #settings-menu:hover, #settings-menu:focus, -.help-button:hover, .help-button:focus, +#help-button:hover, #help-button:focus, #copy-path:hover, #copy-path:focus { border-color: #ffb900; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 60ed889879387..e0efcfe2249af 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -385,14 +385,14 @@ kbd { box-shadow-color: #c6cbd1; } -#theme-picker, #settings-menu, .help-button, #copy-path { +#theme-picker, #settings-menu, #help-button, #copy-path { border-color: #e0e0e0; background-color: #fff; } #theme-picker:hover, #theme-picker:focus, #settings-menu:hover, #settings-menu:focus, -.help-button:hover, .help-button:focus, +#help-button:hover, #help-button:focus, #copy-path:hover, #copy-path:focus { border-color: #717171; }