From c7a72481e6ee8fabb7a736cd252279dfa708bc5d Mon Sep 17 00:00:00 2001
From: kwcantrell <kcantrel@ucsd.edu>
Date: Thu, 19 Nov 2020 21:41:26 -0800
Subject: [PATCH] Fix 364 (#433)

* limited autofill to 10 words

* fixed substring issue

* fixed style issue

* addressed @fedarko comments

* fix style issue

* Apply suggestions from code review

added @fedarko suggestions

Co-authored-by: Marcus Fedarko <marcus.fedarko@gmail.com>

* only show elipse when more suggestions are possible

* sort array ignore case

* style fix

* addressed @fedarko's comments

Co-authored-by: Marcus Fedarko <marcus.fedarko@gmail.com>
---
 empress/support_files/js/canvas-events.js | 49 +++++++++++++++++++----
 empress/support_files/js/empress.js       |  7 +++-
 2 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/empress/support_files/js/canvas-events.js b/empress/support_files/js/canvas-events.js
index 16c63bf2f..b2faab8cb 100644
--- a/empress/support_files/js/canvas-events.js
+++ b/empress/support_files/js/canvas-events.js
@@ -1,4 +1,8 @@
-define(["glMatrix", "SelectedNodeMenu"], function (gl, SelectedNodeMenu) {
+define(["underscore", "glMatrix", "SelectedNodeMenu"], function (
+    _,
+    gl,
+    SelectedNodeMenu
+) {
     /**
      * @class CanvasEvents
      *
@@ -282,18 +286,36 @@ define(["glMatrix", "SelectedNodeMenu"], function (gl, SelectedNodeMenu) {
             );
             autocompleteContainer.appendChild(suggestionMenu);
 
+            // helper function to compare query to node name
+            // returns true if the first (query.length) characters of nodeName
+            // are equal to query, ignoring case (if query.length >
+            // nodeName.length this should be false, since .substr()
+            // will just not modify the nodeName)
+            var compareQuery = function (nodeName) {
+                return (
+                    nodeName.substr(0, query.length).toUpperCase() ===
+                    query.toUpperCase()
+                );
+            };
+
             // search ids array for all possible words
-            for (var i = 0; i < ids.length; i++) {
+            var suggestId,
+                suggestionsAdded = 0,
+                i = _.findIndex(ids, compareQuery, true);
+
+            // no match was found
+            if (i === -1) {
+                return;
+            }
+
+            for (i; i < ids.length && suggestionsAdded < 10; i++) {
                 var word = ids[i];
 
                 // if node id begins with user query, add it to suggestionMenu
-                if (
-                    word.substr(0, query.length).toUpperCase() ===
-                    query.toUpperCase()
-                ) {
+                if (compareQuery(word)) {
                     // create a container to hold the text/click event for the
                     // suggested id
-                    var suggestId = document.createElement("DIV");
+                    suggestId = document.createElement("DIV");
                     suggestId.id = word;
 
                     suggestId.innerHTML =
@@ -305,8 +327,21 @@ define(["glMatrix", "SelectedNodeMenu"], function (gl, SelectedNodeMenu) {
 
                     // add suggested id to the suggstions menu
                     suggestionMenu.appendChild(suggestId);
+                    suggestionsAdded += 1;
+                } else {
+                    break;
                 }
             }
+
+            // not all node ids were listed in the autofill box
+            // create an ellipse autofill (...) to let users know there are
+            // more possible options
+            if (i < ids.length && compareQuery(ids[i])) {
+                suggestId = document.createElement("DIV");
+
+                suggestId.innerHTML = "<strong>...</strong>";
+                suggestionMenu.appendChild(suggestId);
+            }
         };
 
         /**
diff --git a/empress/support_files/js/empress.js b/empress/support_files/js/empress.js
index dbbbd436e..4cb13cab5 100644
--- a/empress/support_files/js/empress.js
+++ b/empress/support_files/js/empress.js
@@ -442,7 +442,12 @@ define([
         // Don't include nodes with the name null (i.e. nodes without a
         // specified name in the Newick file) in the auto-complete.
         nodeNames = nodeNames.filter((n) => n !== null);
-        nodeNames.sort();
+
+        // Sort node names case insensitively
+        nodeNames.sort(function (a, b) {
+            return a.localeCompare(b, "en", { sensitivity: "base" });
+        });
+        nodeNames = _.uniq(nodeNames);
         this._events.autocomplete(nodeNames);
 
         this.getLayoutInfo();