2 Commits 160485341d ... 4ec77747d8

Author SHA1 Message Date
  Mathieu Lirzin 4ec77747d8 text_input: Warn the user when there is no menu in current node 6 years ago
  Mathieu Lirzin c752f44e1c utils: Let 'navigation_links' callers check menu presence easily 6 years ago
3 changed files with 92 additions and 33 deletions
  1. 3 1
      js/src/config.js
  2. 84 30
      js/src/text_input.js
  3. 5 2
      js/src/utils.js

+ 3 - 1
js/src/config.js

@@ -27,5 +27,7 @@ export default {
 
   INDEX_ID: "index",
 
-  PACKAGE_LOGO: "kawa-logo.png"
+  PACKAGE_LOGO: "kawa-logo.png",
+
+  WARNING_TIMEOUT: 3000
 };

+ 84 - 30
js/src/text_input.js

@@ -17,6 +17,7 @@
    along with GNU Texinfo.  If not, see <http://www.gnu.org/licenses/>.  */
 
 import * as actions from "./actions";
+import config from "./config";
 import { iframe_dispatch } from "./store";
 
 export class
@@ -24,17 +25,21 @@ Text_input
 {
   constructor (id)
   {
+    /* Create global container.  */
+    let elem = document.createElement ("div");
+    elem.setAttribute ("style", "background:pink;z-index:100;position:fixed");
+
+    /* Create container for menu search.  */
     let div = document.createElement ("div");
-    div.setAttribute ("id", "menu-input");
-    div.setAttribute ("style", "background:pink;z-index:100;position:fixed");
     div.setAttribute ("hidden", "true");
     div.appendChild (document.createTextNode ("menu:"));
-
     let input = document.createElement ("input");
     input.setAttribute ("type", "search");
     input.setAttribute ("list", "menu");
     div.appendChild (input);
+    elem.appendChild (div);
 
+    /* Define a special key handler when INPUT is focused and visible.  */
     input.addEventListener ("keypress", event => {
       if (event.key === "Escape")
         iframe_dispatch (actions.hide_component (id));
@@ -49,43 +54,92 @@ Text_input
       event.stopPropagation ();
     });
 
-    this.element = div;
+    /* Create a container for warning when no menu in current page.  */
+    let warn = document.createElement ("div");
+    warn.setAttribute ("hidden", "true");
+    warn.appendChild (document.createTextNode ("No menu in this node"));
+    elem.appendChild (warn);
+
+    this.element = elem;
+    this.input_container = div;
     this.input = input;
+    this.warn = warn;
     this.id = id;
+    this.toid = null;
+    this.current_menu = null;
   }
 
   render (state)
   {
-    if (state.text_input_visible)
+    if (!state.text_input_visible)
+      this.hide_elements ();
+    else
       {
-        /* Create a datalist for the menu completions.  */
-        let datalist = document.createElement ("datalist");
-        datalist.setAttribute ("id", "menu");
-
-        let current_menu = state.loaded_nodes[state.current].menu;
-        if (current_menu)
-          {
-            this.current_menu = current_menu;
-            Object.keys (current_menu)
-                  .forEach (title => {
-                    let opt = document.createElement ("option");
-                    opt.setAttribute ("value", title);
-                    datalist.appendChild (opt);
-                  });
-          }
-
-        this.element.appendChild (datalist);
-        this.element.removeAttribute ("hidden");
-        this.input.focus ();
+        let menu = state.loaded_nodes[state.current].menu;
+        if (menu)
+          this.show_menu_input (menu);
+        else
+          this.show_menu_warning ();
       }
+  }
+
+  /* Display a text input for searching through the current menu.  */
+  show_menu_input (menu)
+  {
+    let datalist = create_datalist (menu);
+    datalist.setAttribute ("id", "menu");
+    this.current_menu = menu;
+    this.input_container.appendChild (datalist);
+    this.input_container.removeAttribute ("hidden");
+    this.input.focus ();
+  }
+
+  /* Display a warning indicating that there is no menu in current node.  */
+  show_menu_warning ()
+  {
+    /* Check if a menu warning is already displayed.  */
+    if (this.toid)
+      window.clearTimeout (this.toid);
     else
+      this.warn.removeAttribute ("hidden");
+
+    this.toid = window.setTimeout (() => {
+      iframe_dispatch (actions.hide_component ("menu"));
+      this.toid = null;
+    }, config.WARNING_TIMEOUT);
+  }
+
+  /* Hide both menu input and menu warning.  */
+  hide_elements ()
+  {
+    this.input_container.setAttribute ("hidden", "true");
+    this.warn.setAttribute ("hidden", "true");
+    this.input.value = "";
+
+    /* Check if a menu warning is already displayed.  */
+    if (this.toid)
       {
-        this.element.setAttribute ("hidden", "true");
-        this.input.value = "";
-        /* Remove the datalist if found.  */
-        let datalist = this.element.querySelector ("datalist");
-        if (datalist)
-          datalist.parentNode.removeChild (datalist);
+        window.clearTimeout (this.toid);
+        this.toid = null;
       }
+
+    /* Remove the datalist if found.  */
+    this.input_container.querySelectorAll ("datalist")
+                        .forEach (el => el.parentNode.removeChild (el));
   }
 }
+
+/* Create a datalist element containing option elements corresponding
+   to the keys in MENU.  */
+function
+create_datalist (menu)
+{
+  let datalist = document.createElement ("datalist");
+  Object.keys (menu)
+        .forEach (title => {
+          let opt = document.createElement ("option");
+          opt.setAttribute ("value", title);
+          datalist.appendChild (opt);
+        });
+  return datalist;
+}

+ 5 - 2
js/src/utils.js

@@ -76,7 +76,7 @@ export function
 navigation_links (content)
 {
   let links = content.querySelectorAll ("footer a");
-  let res = { menu: {} };
+  let res = {};
   /* links have the form MAIN_FILE.html#FRAME-ID.  For convenience
      only store FRAME-ID.  */
   for (let i = 0; i < links.length; i += 1)
@@ -86,7 +86,10 @@ navigation_links (content)
       if (nav_id)
         res[nav_id] = href_hash (link.getAttribute ("href"));
       else                  /* this link is part of local table of content. */
-        res.menu[link.text] = href_hash (link.getAttribute ("href"));
+        {
+          res.menu = res.menu || {};
+          res.menu[link.text] = href_hash (link.getAttribute ("href"));
+        }
     }
 
   return res;