I think I've gotten my changes to the js-info reader to a state where it
can be checked in.  See attachment.

In addition to the a "Hide sidebar"/"Show sidebar" button (lower left),
there is also magic to handle narrows screen better, including auto-hide
of the sidebar.

        * js/info.js: Add button to show/hide sidebar.  Other polishing.
        (Sidebar): Create show/hide button.
        (on_click): Handle clicks on show/hide button.
        Also automatically hide sidebar on click when narrow.
        (Sidebar): Copy _href property when copying ToC.
        * js/info.css: Various adjustments and tricks to make it work.

This is the DomTerm manual with some extra DomTerm css style tweaks.
https://per.bothner.com/tmp/DomTerm-txjs/

This is the same manual with just the default styling from info.css:
https://per.bothner.com/tmp/DomTerm-txjs-plain

Please try with different window sizes.
Suggestions/comments about either style appreciated.
--
        --Per Bothner
[email protected]   http://per.bothner.com/
diff --git a/js/info.css b/js/info.css
index b36a1a0bde..dd93097f9f 100644
--- a/js/info.css
+++ b/js/info.css
@@ -6,16 +6,23 @@ body.in-iframe, div[node]#index {
     padding: 0px 0.5em 0px 1em;
 }
 
-div[node] {
-    left: 25%;
-    width: 75%;
+#sub-pages {
     box-sizing: border-box;
+    left: 25%;     width: 75%;
     height: auto;
     top: 0pt;
     bottom: 0pt;
     position: absolute;
+}
+
+div[node] {
+    height: 100%;
     overflow: auto;
 }
+body[show-sidebar="no"] div#sub-pages {
+    left: 0px;
+    width: 100%;
+}
 
 div[node][hidden] {
     display: none;
@@ -26,6 +33,17 @@ body.in-iframe {
     margin: 0px;
 }
 
+div.toc-sidebar {
+    bottom: 2.8ex;
+}
+
+.sidebar-hider {
+    bottom: 0px;
+    height: 2.8ex;
+    position: absolute;
+    text-align: start;
+}
+
 /* Iframed sub pages */
 iframe.node {
     width: 100%;
@@ -50,17 +68,37 @@ iframe.node {
 #slider {
     position: fixed;
     top: 0em;
-    right: 25%;
     bottom: 0em;
-    left: 0em;
     height: 100%;
     width: 25%;
-    overflow: auto;
-    border: none;
     margin: 0px;
     padding: 0px;
 }
 
+#slider, body[show-sidebar="yes"] .sidebar-hider {
+    box-sizing: border-box;
+    left: 0em;
+}
+body[show-sidebar="yes"] .sidebar-hider {
+    width: 100%;
+}
+body[show-sidebar="no"] #slider {
+    width: 0px; /* so mouse events don't get captured */
+}
+body[show-sidebar="no"] .sidebar-hider {
+    width: auto;
+    position: fixed;
+    padding: 3px 1.2em 1px 0.8em;
+}
+
+body[show-sidebar="no"] div.toc-sidebar { display: none }
+
+div.toc-sidebar {
+    position: absolute;
+    top: 0px;
+    overflow: auto;
+}
+
 div.toc-sidebar header {
     font-size: xx-large;
 }
@@ -175,3 +213,20 @@ table#keyboard-shortcuts th {
 .echo-area {
     bottom: 0;
 }
+#slider {
+    background: #f0f0f0c0;
+}
+div.toc-sidebar nav, div.toc-sidebar header, .sidebar-hider {
+    background: #f0f0f0d0;
+}
+body[show-sidebar="yes"] .sidebar-hider {
+    border-width: thin 0px 0px 0px;
+}
+body[show-sidebar="no"] .sidebar-hider {
+    border-width: thin;
+}
+@media (max-width: 60em) {
+    div#sub-pages { left: 0px; width: 100% }
+    body[show-sidebar="yes"] div#slider {width: 20em }
+    div.logo img { max-width: 80%; width: 2em; }
+}
diff --git a/js/info.js b/js/info.js
index 75f6e0c774..9fc7cfc891 100644
--- a/js/info.js
+++ b/js/info.js
@@ -33,6 +33,8 @@
     MAIN_ANCHORS: ["Top"],
     WARNING_TIMEOUT: 3000,
     SCREEN_MIN_WIDTH: 700,
+    SHOW_SIDEBAR_HTML: "<span>Show sidebar</span>",
+    HIDE_SIDEBAR_HTML: "<span>Hide sidebar</span>",
 
     // hooks:
     /** Define a function called after 'DOMContentLoaded' event in
@@ -55,6 +57,7 @@
       @typedef {function (Action): void} Action_consumer
       @type {{dispatch: Action_consumer, state?: any, listeners?: any[]}}.  */
   var store;
+  var show_sidebar_button;
 
   /** Create a Store that calls its listeners at each state change.
       @arg {function (Object, Action): Object} reducer
@@ -683,14 +686,28 @@
     function
     Sidebar (contents_node)
     {
-      this.element = document.createElement ("div");
+      this.element = document.createElement ("div"); // FIXME unneeded?
       this.element.setAttribute ("id", "slider");
       var div = document.createElement ("div");
       div.classList.add ("toc-sidebar");
       var toc = document.querySelector ("#SEC_Contents");
       toc.remove ();
 
-      contents_node.appendChild(toc.cloneNode(true));
+      // Like n.cloneNode, but also copy _href
+      function cloneNode(n)
+      {
+        let r = n.cloneNode(false);
+        for (let c = n.firstChild; c; c = c.nextSibling)
+          {
+            let d = cloneNode(c);
+            let h = c._href;
+            if (h)
+              d._href = h;
+            r.appendChild(d);
+          }
+        return r;
+      }
+      contents_node.appendChild(cloneNode(toc));
 
       /* Remove table of contents header.  */
       toc = toc.querySelector(".contents"); // skip ToC header
@@ -707,6 +724,13 @@
       div$.appendChild (nav);
       div.appendChild (div$);
       this.element.appendChild (div);
+
+      let hider = document.createElement ("button");
+      //let hider = document.createElement ("div");
+      hider.classList.add ("sidebar-hider");
+      hider.innerHTML = config.HIDE_SIDEBAR_HTML;
+      show_sidebar_button = hider;
+      this.element.appendChild(hider);
     }
 
     /* Render 'sidebar' according to STATE which is a new state. */
@@ -995,6 +1019,7 @@
       fix_links (document.links);
       add_icons ();
       document.body.classList.add ("mainbar");
+      document.body.setAttribute("show-sidebar", "yes");
 
       /* Move contents of <body> into a a fresh <div> to let the components
          treat the index page like other iframe page.  */
@@ -1375,7 +1400,9 @@
   {
     for (var target = event.target; target !== null; target = target.parentNode)
       {
-        if ((target instanceof Element) && target.matches ("a"))
+        if (! (target instanceof Element))
+          continue;
+        if (target.matches ("a"))
           {
             var href = link_href(target);
             if (href && !absolute_url_p (href)
@@ -1387,12 +1414,34 @@
                 store.dispatch (actions.set_current_url (linkid));
                 event.preventDefault ();
                 event.stopPropagation ();
+                let body = document.body;
+                if (body.getAttribute("show-sidebar") == "yes"
+                    && is_narrow_window ())
+                   show_sidebar (false)
                 return;
               }
           }
+        if (target.matches (".sidebar-hider"))
+          {
+              let body = document.body;
+              let show = body.getAttribute("show-sidebar");
+              show_sidebar(show==="no");
+          }
       }
   }
 
+  // Only valid when showing sidebar.
+  function is_narrow_window ()
+  {
+        return document.body.firstChild.offsetLeft == 0;
+  }
+
+  function show_sidebar (show)
+  {
+    document.body.setAttribute("show-sidebar", show ? "yes" : "no");
+    show_sidebar_button.innerHTML = show ? config.HIDE_SIDEBAR_HTML : config.SHOW_SIDEBAR_HTML;
+  }
+
   /** Handle unload events.  */
   function
   on_unload ()
@@ -1971,12 +2020,14 @@
 
   /* Until we have a responsive design implemented, fallback to basic
      HTML navigation for small screen.  */
+    /*
   if (window.screen.availWidth < config.SCREEN_MIN_WIDTH)
     {
       window.onload =
         error ("screen width is too small to display the table of content");
       return;
     }
+*/
 
   register_polyfills ();
   /* Let the config provided by the user mask the default one.  */

Reply via email to