Как изменить элемент списка данных или альтернативу - PullRequest
1 голос
/ 08 мая 2019

Я работаю над автозаполнением ввода текста, проверяя сходство строк, а не проверяя совпадения символов. Таким образом, dropdown, как datalists, все равно будет предлагать пользователю предложения, даже если они случайно добавят дополнительный символ или произнесут неправильный ввод желаемого ввода.

У меня есть рабочий файл Javascript, который может сравнивать ввод строки из ввода текста HTML со всеми строками в файле JSON, который содержит около 700 названий школ в виде строк. Затем файл Javascript форматирует HTML и передает 10 наиболее похожих строк в неупорядоченный список (для отладки) и в список данных (где пользователь сможет выбрать свой правильный ответ).

Однако, datalists, похоже, имеет встроенное автозаполнение, которое проверяет идентичные группы символов, а datalists будет разумно удалять предложения, если введенная строка не существует в предложении.

<input 
    type ="text" 
    id="search" 
    list="hsDropdown" 
    class ="form-control form-control-lg"
    placeholder="High School Name"
    autocomplete="off"
    autofocus = "false"
/>

<hr/>

<p id="word"></p>
<datalist id ="hsDropdown"></datalist>
<ul id ="list"></ul>

</main>

<script src="js/script.js" type ="text/javascript"></script>
<script src="js/ukkonen/index.js" type ="text/javascript"></script>

Параметры в datalist в моем HTML правильно заполнены моим script.js наиболее похожими строками, но мне нужно найти способ переопределить свойство тега datalist, которое приводит к результатам с несовершенными совпадениями не появляться или

Мне нужно найти альтернативный способ отображения списка dropdown из textbox, который не ограничен жестким автокоррекцией.

1 Ответ

0 голосов
/ 08 мая 2019

Вы можете посмотреть на select2 jQuery плагин и проблема поиска Fuzzy открыта там

По запросу он реализовал функцию fuzzy_match и встроил ее в плагин следующим образом:

У меня также есть функция matcher, которая выглядит примерно так:

function matcher(term, text){
    if(term.term === undefined){
        return {text: text, score: 1};
    }
    var match = fuzzy_match(term.term, text.text);
    return (match[0])?{text: text, score: match[1]}:false;
}

У меня также есть сортировщик, который сортирует совпадающие элементы (таким образом, совпадающие элементы идут сверху)

function sorter(data) {
    return data.filter(function(item) {
        return !!item;
    }).sort((a, b) => b.score - a.score)
          .map(item => item.text);
}

И всякий раз, когда мы вызываемselect2 для элемента, мы передаем этот сопоставитель как параметр сопоставления и сортировщик как параметр сортировки, который выглядит примерно так:

$("#element").select2({
  placeholder: 'select a name',
  matcher,
  sorter
})

Здесь - это fuzzy_match код функции:

/**
 *
 * @param pattern
 * @param str
 * @returns {[boolean,score,formatted]}
 */
function fuzzy_match(pattern, str) {

	// Score consts
	var adjacency_bonus = 55;                // bonus for adjacent matches
	var separator_bonus = 10;               // bonus if match occurs after a separator
	var camel_bonus = 10;                   // bonus if match is uppercase and prev is lower
	var leading_letter_penalty = -3;        // penalty applied for every letter in str before the first match
	var max_leading_letter_penalty = -9;    // maximum penalty for leading letters
	var unmatched_letter_penalty = -1;      // penalty for every letter that doesn't matter

	// Loop variables
	var score = 0;
	var patternIdx = 0;
	var patternLength = pattern.length;
	var strIdx = 0;
	var strLength = str.length;
	var prevMatched = false;
	var prevLower = false;
	var prevSeparator = true;       // true so if first letter match gets separator bonus

	// Use "best" matched letter if multiple string letters match the pattern
	var bestLetter = null;
	var bestLower = null;
	var bestLetterIdx = null;
	var bestLetterScore = 0;

	var matchedIndices = [];

	// Loop over strings
	while (strIdx != strLength) {
		var patternChar = patternIdx != patternLength ? pattern.charAt(patternIdx) : null;
		var strChar = str.charAt(strIdx);

		var patternLower = patternChar != null ? patternChar.toLowerCase() : null;
		var strLower = strChar.toLowerCase();
		var strUpper = strChar.toUpperCase();

		var nextMatch = patternChar && patternLower == strLower;
		var rematch = bestLetter && bestLower == strLower;

		var advanced = nextMatch && bestLetter;
		var patternRepeat = bestLetter && patternChar && bestLower == patternLower;
		if (advanced || patternRepeat) {
			score += bestLetterScore;
			matchedIndices.push(bestLetterIdx);
			bestLetter = null;
			bestLower = null;
			bestLetterIdx = null;
			bestLetterScore = 0;
		}

		if (nextMatch || rematch) {
			var newScore = 0;

			// Apply penalty for each letter before the first pattern match
			// Note: std::max because penalties are negative values. So max is smallest penalty.
			if (patternIdx == 0) {
				var penalty = Math.max(strIdx * leading_letter_penalty, max_leading_letter_penalty);
				score += penalty;
			}

			// Apply bonus for consecutive bonuses
			if (prevMatched)
				newScore += adjacency_bonus;

			// Apply bonus for matches after a separator
			if (prevSeparator)
				newScore += separator_bonus;

			// Apply bonus across camel case boundaries. Includes "clever" isLetter check.
			if (prevLower && strChar == strUpper && strLower != strUpper)
				newScore += camel_bonus;

			// Update patter index IFF the next pattern letter was matched
			if (nextMatch)
				++patternIdx;

			// Update best letter in str which may be for a "next" letter or a "rematch"
			if (newScore >= bestLetterScore) {

				// Apply penalty for now skipped letter
				if (bestLetter != null)
					score += unmatched_letter_penalty;

				bestLetter = strChar;
				bestLower = bestLetter.toLowerCase();
				bestLetterIdx = strIdx;
				bestLetterScore = newScore;
			}

			prevMatched = true;
		}
		else {
			// Append unmatch characters
			formattedStr += strChar;

			score += unmatched_letter_penalty;
			prevMatched = false;
		}

		// Includes "clever" isLetter check.
		prevLower = strChar == strLower && strLower != strUpper;
		prevSeparator = strChar == '_' || strChar == ' ';

		++strIdx;
	}

	// Apply score for last match
	if (bestLetter) {
		score += bestLetterScore;
		matchedIndices.push(bestLetterIdx);
	}

	// Finish out formatted string after last pattern matched
	// Build formated string based on matched letters
	var formattedStr = "";
	var lastIdx = 0;
	for (var i = 0; i < matchedIndices.length; ++i) {
		var idx = matchedIndices[i];
		formattedStr += str.substr(lastIdx, idx - lastIdx) + "<b>" + str.charAt(idx) + "</b>";
		lastIdx = idx + 1;
	}
	formattedStr += str.substr(lastIdx, str.length - lastIdx);

	var matched = patternIdx == patternLength;
	return [matched, score, formattedStr];
}
...