add autocompletion to package list
authorMoritz Warning <moritzwarning@web.de>
Fri, 22 May 2020 23:43:18 +0000 (01:43 +0200)
committerMoritz Warning <moritzwarning@web.de>
Wed, 3 Jun 2020 10:28:46 +0000 (12:28 +0200)
the package list will autocomplete packages and only allow known
packages

index.css
index.html
index.js

index 7569ada9156c0031fbba42d60ed5293f68a5ce7f..a7203375a25548766cfbb93aca6cab343b0ab56d 100644 (file)
--- a/index.css
+++ b/index.css
@@ -4,10 +4,13 @@ body {
   margin: 0px;
 }
 
-/*the container must be positioned relative:*/
+#models-autocomplete {
+  width: 20em;
+  display: inline-block;
+}
+
 .autocomplete {
   position: relative;
-  display: inline-block;
 }
 
 .autocomplete > input {
@@ -18,10 +21,6 @@ body {
   border-radius: 4px;
 }
 
-.autocomplete {
-  width: 20em;
-}
-
 .autocomplete-items {
   position: absolute;
   border: 1px solid #d4d4d4;
index 6feaa677ad7d3f4dd0cdde83c1f7816827e189c2..8ad054d31493118bde428610694b6762f89e6a61 100644 (file)
@@ -40,7 +40,7 @@
                <br>
 
                <select id="versions" size="1"></select>
-               <div class="autocomplete">
+               <div id="models-autocomplete" class="autocomplete">
                        <input id="models" type="text" placeholder="Model" spellcheck="false" autocapitalize="off" autocorrect="off">
                </div>
 
@@ -55,7 +55,9 @@
                <div id="images">
                        <div id="custom">
                                <h3 class="tr-customize">Customize</h3>
-                               <textarea id="packages" spellcheck="false" autocapitalize="off" autocorrect="off">luci</textarea>
+                               <div class="autocomplete">
+                                       <textarea id="packages" spellcheck="false" autocapitalize="off" autocorrect="off"></textarea>
+                               </div>
                                <a href="javascript:build_asa_request()" class="custom-link">
                                        <span>&#9881;</span><span class="tr-request-build">Request Build</span>
                                </a>
index 894f1a12ea562e14d35a531db68022682dd043cc..ce5f4b41f14dbd63980786d050e5551ac5997ad0 100644 (file)
--- a/index.js
+++ b/index.js
@@ -13,16 +13,16 @@ function hide(id) {
   $(id).style.display = 'none';
 }
 
+function split(str) {
+  return str.match(/[^\s,]+/g) || [];
+}
+
 function build_asa_request() {
   if (!current_model || !current_model.id) {
     alert('bad profile');
     return;
   }
 
-  function split(str) {
-    return str.match(/[^\s,]+/g) || [];
-  }
-
   function get_model_titles(titles) {
     return titles.map(e => {
       if (e.title) {
@@ -132,9 +132,7 @@ function translate() {
   }
 }
 
-function setupAutocompleteList(input, items, onselection) {
-  // the setupAutocompleteList function takes two arguments,
-  // the text field element and an array of possible autocompleted values:
+function setupAutocompleteList(input, items, as_list, onbegin, onend) {
   var currentFocus = -1;
 
   // sort numbers and other characters separately
@@ -142,12 +140,20 @@ function setupAutocompleteList(input, items, onselection) {
 
   items.sort(collator.compare);
 
-  // execute a function when someone writes in the text field:
   input.oninput = function(e) {
-    // clear images
-    updateImages();
+    onbegin();
 
+    var offset = 0;
     var value = this.value;
+    var value_list = [];
+
+    if (as_list) {
+      // automcomplete last text item
+      offset = this.value.lastIndexOf(' ') + 1;
+      value = this.value.substr(offset);
+      value_list = split(this.value.substr(0, offset));
+    }
+
     // close any already open lists of autocompleted values
     closeAllLists();
 
@@ -162,7 +168,6 @@ function setupAutocompleteList(input, items, onselection) {
     // append the DIV element as a child of the autocomplete container:
     this.parentNode.appendChild(list);
 
-    // for each item in the array...
     var c = 0;
     for (var i = 0; i < items.length; i += 1) {
       var item = items[i];
@@ -173,6 +178,11 @@ function setupAutocompleteList(input, items, onselection) {
         continue;
       }
 
+      // do not offer a duplicate item
+      if (as_list && value_list.indexOf(item) != -1) {
+        continue;
+      }
+
       c += 1;
       if (c >= 15) {
         var div = document.createElement('DIV');
@@ -188,13 +198,16 @@ function setupAutocompleteList(input, items, onselection) {
           + '<input type="hidden" value="' + item + '">';
 
         div.addEventListener('click', function(e) {
-          // set text field to selected value
-          input.value = this.getElementsByTagName('input')[0].value;
+          // include selected value
+          var selected = this.getElementsByTagName('input')[0].value;
+          if (as_list) {
+            input.value = value_list.join(' ') + ' ' + selected;
+          } else {
+            input.value = selected;
+          }
           // close the list of autocompleted values,
-          // (or any other open lists of autocompleted values:
           closeAllLists();
-          // callback
-          onselection(input.value);
+          onend(input);
         });
 
         list.appendChild(div);
@@ -226,7 +239,12 @@ function setupAutocompleteList(input, items, onselection) {
   };
 
   input.onfocus = function() {
-    onselection(input.value);
+    onend(input);
+  }
+
+  // focus lost
+  input.onblur = function() {
+    onend(input);
   }
 
   function setActive(x) {
@@ -259,6 +277,21 @@ function setupAutocompleteList(input, items, onselection) {
   });
 }
 
+// for attended sysupgrade
+function updatePackageList(target) {
+  // set available packages
+  fetch(config.asu_url + '/' + target + '/packages.json')
+  .then(response => response.json())
+  .then(all_packages => {
+    setupAutocompleteList($('packages'), all_packages, true, _ => {}, textarea => {
+      textarea.value = split(textarea.value)
+        .filter((value, index, self) => self.indexOf(value) === index) // make list unique
+        //.filter((value, index) => all_packages.indexOf(value) !== -1) // limit to available packages
+        .join(' ');
+    });
+  });
+}
+
 function updateImages(version, code, date, model, url, mobj, is_custom) {
   // add download button for image
   function addLink(type, file) {
@@ -341,6 +374,10 @@ function updateImages(version, code, date, model, url, mobj, is_custom) {
       addLink(images[i].type, images[i].name);
     }
 
+    if (config.asu_url) {
+      updatePackageList(target);
+    }
+
     show('images');
   } else {
     hide('images');
@@ -351,7 +388,8 @@ function init() {
   setupSelectList($('versions'), Object.keys(config.versions), version => {
     fetch(config.versions[version]).then(data => {
       data.json().then(obj => {
-        setupAutocompleteList($('models'), Object.keys(obj['models']), model => {
+        setupAutocompleteList($('models'), Object.keys(obj['models']), false, updateImages, models => {
+          var model = models.value;
           if (model in obj['models']) {
             var url = obj.url || 'unknown';
             var code = obj.version_code || 'unknown';