d7237d1a3cd101ac490a921984a2ce95629161c397a976802ff7aed9d5f1b1c4

Source Code:

var NaviApiI3 = function () {};

/**
 * send Suggest information to i3
 *
 * @param {Object} set
 *   {
 *     rank: index(number of service or word)
 *     uid: uid
 *     word: word
 *     type: 'service_suggest' or 'word_suggest'
 *     category(option): Service Suggest only.
 *   }
 * @param {Array} suggests
 *   [
 *    {
 *      suggest_rank: index(number of service or word)
 *      suggest_uid: uid
 *      suggest_word: word
 *      suggest_type: 'service_suggest' or 'word_suggest'
 *     },...
 *   ]
 * @param {string} event 'click'...etc
 * @param {function} callback
 */
NaviApiI3.send = function (set, suggests, event, callback) {
  var type = 'suggest';
  var tracker = [event, '_', type].join('');
  // i3 Check
  if (typeof i3 !== 'function') {
    return;
  }

  /* eslint-disable */
  // 1.Create Tracker
  i3('create', tracker);

  // 2.Set Search Word
  i3(tracker + '.set', type, set);

  // 3.Add Display Suggest List
  suggests.forEach(function (value) {
    i3(tracker + '.add', type, value);
  });

  // 4.Send to i3
  if (typeof callback === 'function') {
    i3(tracker + '.send', event, type, callback);
  } else {
    i3(tracker + '.send', event, type);
  }
};

/**
 * return object to send i3 (for suggest view)
 *
 * @param {string} uid selected uid
 * @param {Array} suggestList Response of SuggestAPI
 * @return {object} set(i3 Send object)
 */
NaviApiI3.getSet = function (uid, suggestList) {
  var services = suggestList.services;
  var words = suggestList.words;
  var result = {};
  var isService = false;
  // service suggest (requires category)
  isService = services.some(function (value, index) {
    if (value.uid === uid) {
      result.rank = (index + 1);
      result.uid = uid;
      result.word = value.suggest_word;
      result.type = 'service_suggest';
      result.category = value.service_ja;
      return true;
    }
    return false;
  });
  if (isService) {
    return result;
  }

  // word suggest
  words.some(function (value, index) {
    if (value.uid === uid) {
      result.rank = (index + 1);
      result.uid = uid;
      result.word = value.suggest_word;
      result.type = 'word_suggest';
      return true;
    }
    return false;
  });
  return result;
};

/**
 * return list to send i3 (for suggest view)
 *
 * [info] Currently, service suggest information will be contained if `all` is selected.
 * Since it is difficult for the caller to do such operation,
 * we will do it in this function instead.
 *
 * @param {string} uid selected uid
 * @param {Array} suggestList Response of SuggestAPI
 * @param {number} index select box index
 * @param {string} word search word
 * @return {Array} suggests(i3 Send List Objects)
 */
NaviApiI3.getSuggests = function (uid, suggestList, index, word) {
  var services = suggestList.services;
  var words = suggestList.words;
  var result = [];
  // service suggest and word suggest
  if (index === 0 && word && word.length > 1) {
    services.forEach(function (value, idx) {
      var object = {};
      object.suggest_rank = (idx + 1);
      object.suggest_uid = value.uid;
      object.suggest_word = value.suggest_word;
      object.suggest_type = 'service_suggest';
      object.suggest_category = value.service_ja;
      result.push(object);
    });
    words.forEach(function (value, idx) {
      var object = {};
      object.suggest_rank = (idx + 1);
      object.suggest_uid = value.uid;
      object.suggest_word = value.suggest_word;
      object.suggest_type = 'word_suggest';
      result.push(object);
    });
    return result;
  }

  // word suggest only
  words.forEach(function (value, idx) {
    var object = {};
    object.suggest_rank = (idx + 1);
    object.suggest_uid = value.uid;
    object.suggest_word = value.suggest_word;
    object.suggest_type = 'word_suggest';
    result.push(object);
  });
  return result;
};

/**
 * return object to send i3 (for search button)
 *
 * [specification(AND condition)]
 *   1.`all` is selected in pulldown
 *   2.there is at least 1 service suggest for search query
 *
 * [return value]
 *   null if parameter is invalid
 *   otherwise, will return correct value
 *
 * @param {string} text input data
 * @return {object} set(i3 Send object)
 */
NaviApiI3.getSetForSubmit = function (text) {
  if (!text) {
    return null;
  }
  var result = {};
  result.word = text;
  return result;
};

/**
 * return list to send i3 (for search button)
 *
 * [specification(AND condition)]
 *   1.`all` is selected in pulldown
 *   2.there is at least 1 service suggest for search query
 *
 * [return value]
 *   empty list if parameter is invalid
 *   otherwise, will return correct value
 *
 * @param {Array} suggestList Response of SuggestAPI
 * @param {number} index select box index
 * @return {Array} suggests(i3 Send List Objects)
 */
NaviApiI3.getSuggestsForSubmit = function (suggestList, index) {
  var services = suggestList.services;
  var result = [];
  if (index !== 0) {
    return result;
  }
  if (!services) {
    return result;
  }
  if (services.length === 0) {
    return result;
  }
  services.forEach(function (value, idx) {
    var object = {};
    object.suggest_rank = (idx + 1);
    object.suggest_uid = value.uid;
    object.suggest_word = value.suggest_word;
    object.suggest_type = 'service_assist_suggest';
    object.suggest_category = value.service_ja;
    result.push(object);
  });
  return result;
};


var NaviApiSearchSuggest = function () {};

/**
 * callback for keyup event in search form
 *
 * @param {object} event
 */
NaviApiSearchSuggest.changedText = function (event) {
  var text = NaviApiSearchSuggest.text.value;
  if (text.length === 0) {
    NaviApiSearchSuggest.clear();
    return;
  }
  if (NaviApiSearchSuggest.previousInput === text) {
    return;
  }
  // Call Suggest API
  NaviApiSearchSuggest.httpRequest(event, text);

  // Set word suggest data
  NaviApiSearchSuggest.changedArrowKey(event);

  NaviApiSearchSuggest.previousInput = text;
};

/**
 * set word suggest data using arrow keys (up/down)
 *
 * @param {object} event
 */
NaviApiSearchSuggest.changedArrowKey = function (event) {
  // KEY_UP=-1, KEY_DOWN=1
  var keyIndex = (event.keyCode === NaviApiSearchSuggest.ARROW_KEYS_UP) ? -1 : 1;
  var lastIndex = NaviApiSearchSuggest.SUGGEST_WORDS_INDEX;
  var index = lastIndex + keyIndex;
  var word = '';
  var lastSelected;

  // validate
  if (NaviApiSearchSuggest.ARROW_KEYS.indexOf(event.keyCode) < 0) {
    return;
  }
  if (NaviApiSearchSuggest.SUGGEST_WORDS.length === 0) {
    return;
  }

  if (index < 0) {
    index = NaviApiSearchSuggest.SUGGEST_WORDS.length - 1;
  }
  if (index >= NaviApiSearchSuggest.SUGGEST_WORDS.length) {
    index = 0;
  }

  word = NaviApiSearchSuggest.SUGGEST_WORDS[index];
  NaviApiSearchSuggest.text.value = word.suggest_word;
  NaviApiSearchSuggest.SUGGEST_WORDS_INDEX = index;
  if (lastIndex !== NaviApiSearchSuggest.SUGGEST_WORDS_NOT_EXIST) {
    lastSelected = NaviApiSearchSuggest.suggestWindow.querySelector('._n4v1-search-suggest-word li:nth-of-type(' + (lastIndex + 1) + ')');
    lastSelected.classList.remove('_n4v1-search-suggest-word-selected');
  }
  NaviApiSearchSuggest.suggestWindow.querySelector('._n4v1-search-suggest-word li:nth-of-type(' + (index + 1) + ')').classList.add('_n4v1-search-suggest-word-selected');
};

/**
 * make http request
 *
 * @param {object} event
 * @param {string} text text value in search box
 */
NaviApiSearchSuggest.httpRequest = function (event, text) {
  var sc = '';
  var element = '';
  if (NaviApiSearchSuggest.ARROW_KEYS.indexOf(event.keyCode) >= 0) {
    return;
  }
  sc = document.createElement('script');
  sc.id = 'naviapi-suggest-script';
  sc.type = 'text/javascript';
  sc.src = NaviApiSearchSuggest.getEndpoint(text);
  sc.async = 'true';
  element = document.getElementById('naviapi-suggest-script');
  element.parentNode.insertBefore(sc, element);
  element.parentNode.removeChild(element);
};

/**
 * return API endpoint URL
 *
 * @param {string} text text value in search box
 * @return {string} SuggestAPI Endpoint
 */
NaviApiSearchSuggest.getEndpoint = function (text) {
  var domain = NaviApiSearchSuggest.getDomain();
  return 'https://' + domain + '/search/-/assist/ajax-suggest/=/q=' + encodeURIComponent(text) + '?jsoncallback=NaviApiSearchSuggest.callback';
};

/**
 * return domain for API endpoint
 *
 * @return {string} domain
 */
NaviApiSearchSuggest.getDomain = function () {
  return NaviApiSearchSuggest.isR18() ? 'www.dmm.co.jp' : 'www.dmm.com';
};

/**
 * judge if the page is r18 site
 *
 * @return {bool} true if the page is r18 site, false otherwise
 */
NaviApiSearchSuggest.isR18 = function () {
  var hostname = window.location.hostname;
  return /dmm\.co\.jp$/.test(hostname);
};

/**
 * callback for suggest API
 *
 * @param {object} data response body
 */
NaviApiSearchSuggest.callback = function (data) {
  if (!data) {
    NaviApiSearchSuggest.clear();
    return;
  }
  NaviApiSearchSuggest.SUGGESTS = data;
  NaviApiSearchSuggest.htmlBuilder(data);
  NaviApiSearchSuggest.sendSuggestShowEvent();
};

/**
 * build HTML
 *
 * @param {object} data response body
 */
NaviApiSearchSuggest.htmlBuilder = function (data) {
  var result = [];
  var services = data.services;
  var words = data.words;
  var serviceList = NaviApiSearchSuggest.buildService(services);
  var wordList = NaviApiSearchSuggest.buildWord(words);
  if ((services.length === 0) && (words.length === 0)) {
    NaviApiSearchSuggest.clear();
    return;
  }
  result.push(serviceList.join(''));
  result.push(wordList.join(''));
  NaviApiSearchSuggest.suggestWindow.innerHTML = result.join('');
  // set service suggest
  NaviApiSearchSuggest.SUGGEST_SERVICES = services;
  // set word suggest
  NaviApiSearchSuggest.SUGGEST_WORDS = words;
  // show
  NaviApiSearchSuggest.display();
};

/**
 * build HTML for service suggest
 *
 * @param {Array} services Service Objects
 * @return {Array} Service Suggest HTML
 */
NaviApiSearchSuggest.buildService = function (services) {
  var result = [];
  var inputText = NaviApiSearchSuggest.text.value;
  var index = 0;
  var colorClass = '';
  if (services.length === 0) {
    return result;
  }

  // if `all` is not selected, terminate these steps
  index = NaviApiSearchSuggest.selectBox.selectedIndex;
  if (index !== 0) {
    return result;
  }

  // if word length is less than 2, terminate these steps
  // (due to existing specification)
  if (inputText.length <= 1) {
    return result;
  }

  if (NaviApiSearchSuggest.isR18()) {
    colorClass = '_n4v1-search-r18-color';
  } else {
    colorClass = '_n4v1-search-com-color';
  }

  result.push('<ul class="_n4v1-search-suggest-service">');
  services.forEach(function (value) {
    result.push('<li>');
    result.push('<a class="' + colorClass + '" id="' + value.uid + '" href="' + value.detail.url + '" data-uid="' + value.uid + '">');
    result.push(value.suggest_word);
    result.push('<span>' + value.service_ja + '</span>');
    result.push('</a>');
    result.push('</li>');
  });
  result.push('</ul>');
  return result;
};

/**
 * build HTML for word suggest
 *
 * @param {Array} words word objects
 * @return {Array} Words Suggest HTML
 */
NaviApiSearchSuggest.buildWord = function (words) {
  var result = [];
  if (words.length === 0) {
    return result;
  }
  result.push('<ul class="_n4v1-search-suggest-word">');
  words.forEach(function (value) {
    result.push('<li id="' + value.uid + '">');
    result.push(value.suggest_word);
    result.push('</li>');
  });
  result.push('</ul>');
  return result;
};

/**
 * show suggest result
 */
NaviApiSearchSuggest.display = function () {
  NaviApiSearchSuggest.SUGGEST_WORDS_INDEX = NaviApiSearchSuggest.SUGGEST_WORDS_NOT_EXIST;
  NaviApiSearchSuggest.suggestWindow.classList.remove('_n4v1-search-suggest-hide');
};

/**
 * callback for selecting suggest window
 *
 * @param {Object} event
 */
NaviApiSearchSuggest.selectedSuggestWindow = function (event) {
  /* eslint-disable */
  var id = event.target.id;
  // update the input value if word suggest data exist
  var text = NaviApiSearchSuggest.text.value;
  var isWord = NaviApiSearchSuggest.SUGGEST_WORDS.some(function (value) {
    if (value.uid === id) {
      NaviApiSearchSuggest.text.value = value.suggest_word;
      return true;
    }
    return false;
  });
  // 1.Get set
  var i3Set = NaviApiI3.getSet(id, NaviApiSearchSuggest.SUGGESTS);
  // 2.Get suggests
  var i3SuggestLit = NaviApiI3.getSuggests(
    id,
    NaviApiSearchSuggest.SUGGESTS,
    NaviApiSearchSuggest.selectBox.selectedIndex,
    text
  );
  // 3.send
  NaviApiI3.send(i3Set, i3SuggestLit, 'click');

  // for word suggest
  if (isWord) {
    document.search_form.submit();
  } else {
    // update location for service suggest
    NaviApiSearchSuggest.SUGGEST_SERVICES.some(function (value) {
      if (value.uid === id) {
        window.location.href = value.detail.url;
        return true;
      }
      return false;
    });
  }
};

/**
 * send `show suggest` event
 */
NaviApiSearchSuggest.sendSuggestShowEvent = function () {
  /* eslint-disable */
  var text = NaviApiSearchSuggest.text.value;
  var selectedIndex = NaviApiSearchSuggest.selectBox.selectedIndex;
  var i3Set = NaviApiI3.getSetForSubmit(text);
  var i3SuggestLit = NaviApiI3.getSuggests(
    null,
    NaviApiSearchSuggest.SUGGESTS,
    selectedIndex,
    text
  );

  // Check
  if (!i3Set) {
    return;
  }
  if (i3SuggestLit.length === 0) {
    return;
  }
  NaviApiI3.send(i3Set, i3SuggestLit, 'show');
};


/**
 * callback for clicking search button
 *
 * @param {Object} event
 */
NaviApiSearchSuggest.submitSuggest = function (event) {
  document.search_form.submit();
};

/**
 * clear suggest result
 */
NaviApiSearchSuggest.clear = function () {
  NaviApiSearchSuggest.SUGGEST_WORDS_INDEX = NaviApiSearchSuggest.SUGGEST_WORDS_NOT_EXIST;
  NaviApiSearchSuggest.SUGGEST_SERVICES = [];
  NaviApiSearchSuggest.SUGGEST_WORDS = [];
  NaviApiSearchSuggest.previousInput = null;
  NaviApiSearchSuggest.suggestWindow.innerHTML = '';
  NaviApiSearchSuggest.suggestWindow.classList.add('_n4v1-search-suggest-hide');
};

// ----------------------- //
// Define
// ----------------------- //
// arrorw keys
NaviApiSearchSuggest.ARROW_KEYS = [38, 40];
NaviApiSearchSuggest.ARROW_KEYS_UP = 38;
// API response
NaviApiSearchSuggest.SUGGESTS = [];
NaviApiSearchSuggest.SUGGEST_SERVICES = [];
NaviApiSearchSuggest.SUGGEST_WORDS = [];
NaviApiSearchSuggest.SUGGEST_WORDS_NOT_EXIST = -1;
NaviApiSearchSuggest.SUGGEST_WORDS_INDEX = NaviApiSearchSuggest.SUGGEST_WORDS_NOT_EXIST;
// search query text
NaviApiSearchSuggest.previousInput = null;
// select box
NaviApiSearchSuggest.selectBox = document.getElementById('select-box');
// search box (for inputing text)
NaviApiSearchSuggest.text = document.getElementById('naviapi-search-text');
NaviApiSearchSuggest.suggestWindow = document.getElementById('naviapi-suggest-display');
// search button
NaviApiSearchSuggest.submit = document.getElementById('naviapi-search-submit');

// ---------------- /
// EventListeners
// ---------------- /
// for text input event
NaviApiSearchSuggest.text.addEventListener('keyup', NaviApiSearchSuggest.changedText);
// for clicking suggest window
NaviApiSearchSuggest.suggestWindow.addEventListener('mousedown', NaviApiSearchSuggest.selectedSuggestWindow);
// for clearing suggest display
NaviApiSearchSuggest.text.addEventListener('blur', NaviApiSearchSuggest.clear);
// for form submit
NaviApiSearchSuggest.submit.addEventListener('click', NaviApiSearchSuggest.submitSuggest);