<commit_before>'use strict';
var _ = require('lodash'),
  dom = require('../services/dom');

/**
 * Find the first child that is a text input.
 * @param {object} el
 * @returns {object|undefined}
 */
function findFirstTextInput(el) {
  
  var inputs = el.querySelectorAll('input'),
    l = inputs.length,
    i = 0,
    type,
    textInput;
  
  while (i < l) {
    type = inputs[i].getAttribute('type');
    if (!type || type === 'text') {
      textInput = inputs[i];
      break;
    }
    i += 1;
  }
  
  return textInput;
}

/**
 * Temporary, until the endpoint is hooked up.
 * @param q
 * @returns {*}
 */
function mockEndpoint(q) {
  if (q.toLowerCase().indexOf('m') === 0) {
    // Names with M
    return JSON.stringify({results:['Morgan', 'Mindy', 'Miguel']});
  } else {
    // Random names
    return JSON.stringify({results:['<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>', '<NAME>']});
  }
}


module.exports = function (result, args) {
  
  var existingInput = findFirstTextInput(result.el);
  
  if (existingInput) {
    
    // Add element.
    var datalist = document.createElement('datalist');

    // Set attributes.
    var listName = args.listName || 'list-needs-an-id';
    existingInput.setAttribute('list', listName);
    datalist.id = listName;

    // Add options.
    var options = dom.create(`
      <label>
        or select from the list:
        <select name="${ existingInput.getAttribute('name') }">
          <option value="">
          <option>Bip
          <option>Bop
          <option>Boop
        </select>
      </label>
    `);
    datalist.appendChild(options);
    
    var optionsParent = options.querySelector('select');

    existingInput.addEventListener('input', (function(optionsParent) { 
      return function(e) {
        
        var options = JSON.parse(mockEndpoint(e.target.value)).results.reduce(function(prev, curr) { 
          return prev + '<option>' + curr; 
        }, '<option value="">');
        
        options = dom.create(`${ options }`);

        dom.clearChildren(optionsParent);
        optionsParent.appendChild(options);
      };
    })(optionsParent));

    // Add it back to the result element.
    result.el.appendChild(datalist);
  }
  
  return result;
  
};<commit_msg>Basic autocomplete working with API.<commit_after>'use strict';
var _ = require('lodash'),
  dom = require('../services/dom'),
  db = require('../services/db'),
  lists = {};

/**
 * Find the first child that is a text input.
 * @param {object} el
 * @returns {object|undefined}
 */
function findFirstTextInput(el) {
  
  var inputs, l, i, type, textInput;

  inputs = el.querySelectorAll('input');
  
  for (i = 0, l = inputs.length; i < l; i++) {
    type = inputs[i].getAttribute('type');
    if (!type || type === 'text') {
      textInput = inputs[i];
      break;
    }
  }
  
  return textInput;
}

/**
 * Get the list values from the API and store in memory.
 * @param {string} apiUrl   The endpoint for the list, e.g. '/lists/authors'
 * @returns {promise}
 */
function getListValues(apiUrl) {
  if (lists[apiUrl]) {
    return Promise.resolve(lists[apiUrl]);
  } else {
    return db.getComponentJSONFromReference(apiUrl);
  }
}

/**
 * Create a unique name for the list. Does not need to be too unique because specific to one form.
 * @returns {string}      Name to be used for the list
 */
function createListName() {
  var somewhatUnique = '' + Math.floor(Math.random() * 100) + (new Date()).getTime();
  return 'autocomplete-' + somewhatUnique;
}


module.exports = function (result, args) {
  
  var api = args.api,
    existingInput = findFirstTextInput(result.el), 
    listName = createListName(),
    optionsParent;
  
  // Requirements.
  if (!api) {
    console.warn('Autocomplete requires an API.');
    return result;
  }
  if (!existingInput) {
    console.warn('Autocomplete requires a text input.');
    return result;
  }
  
  getListValues(api);

  // Add elements.
  var datalist = document.createElement('datalist');
  var options = dom.create(`
    <label>
      <select>
        <option value="">
      </select>
    </label>
  `);
  datalist.appendChild(options);
  optionsParent = options.querySelector('select');
  
  // Set attributes.
  existingInput.setAttribute('list', listName);
  datalist.id = listName;

  // Listen.
  existingInput.addEventListener('input', (function(optionsParent) { 
    return function(e) {

      getListValues(api).then(function (results) {  
        var options = results.reduce(function (prev, curr) {
            return prev + '<option>' + curr;
          }, '<option value="">');

        options = dom.create(`${ options }`);
        dom.clearChildren(optionsParent);
        optionsParent.appendChild(options);
        
        existingInput.focus();
      });
      
    };
  })(optionsParent));

  // Add it back to the result element.
  result.el.appendChild(datalist);
  
  return result;
  
};
{'fraction_non_alphanumeric': 0.1636327661258409, 'fraction_numerical': 0.0013850415512465374, 'mean_word_length': 2.8036117381489842, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2233586', 'n_tokens_mistral': 1567, 'n_tokens_neox': 1560, 'n_words': 387}