1
0
mirror of https://github.com/nextapps-de/flexsearch.git synced 2025-09-30 23:26:42 +02:00
Files
flexsearch/demo/autocomplete.html
2025-04-17 13:43:59 +02:00

267 lines
7.9 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1, maximum-scale=1.0, user-scalable=no, viewport-fit=cover, shrink-to-fit=no, minimal-ui">
<title>Demo: Auto-Complete</title>
<style>
body{
padding: 0;
margin: 0 10px;
font-family: Helvetica, Arial, sans-serif;
font-size: 14px;
}
#header{
position: fixed;
top: 10px;
left: 10px;
width: 100%;
display: flex;
justify-content: flex-start;
flex-direction: row;
max-width: 500px;
table-layout: fixed;
background-color: #fff;
z-index: 1;
}
input[type="text"]{
width: 100%;
border: 1px solid #ddd;
border-radius: 4px;
outline: none;
background-color: transparent;
position: absolute;
-webkit-appearance: none;
}
#autocomplete{
color: #999;
background-color: #f5f5f5;
pointer-events: none;
}
#trigger-prev,
#trigger-next{
z-index: -1;
}
input{
padding:7px 5px;
box-sizing: border-box;
}
#suggestions{
position: relative;
top: 50px;
}
#suggestions div{
padding: 10px 8px;
border-bottom: 1px solid #ddd;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: calc(100% - 16px);
}
#suggestions b{
color: blue;
}
#suggestions:empty:before{
content: "No resuls found";
font-size: 12px;
color: #999;
margin-left: 7px;
}
#info{
position: absolute;
bottom: 7px;
left: 12px;
color: #888;
}
label{
width: 100px;
height: 32px;
display: flex;
align-items: center;
margin: 0 10px;
}
@media only screen and (max-width: 600px) {
body{
font-size: 12px;
}
}
</style>
</head>
<body>
<div id="header">
<form style="position: relative; width: 100%;">
<input type="text" id="trigger-prev">
<input type="text" id="autocomplete" disabled>
<input type="text" id="userinput" placeholder="Search by movie title ..." autocorrect="off" spellcheck="false" autocomplete="off" autofocus>
<input type="text" id="trigger-next">
</form>
<label>
<input type="checkbox" id="suggest" checked> Suggest
</label>
</div>
<div id="suggestions"></div>
<!--<div id="info">iterate results by arrow keys</div>-->
<script type="module">
import { Document } from "https://cdn.jsdelivr.net/gh/nextapps-de/flexsearch@master/dist/flexsearch.compact.module.min.js";
import data from "https://cdn.jsdelivr.net/gh/nextapps-de/flexsearch@master/demo/data/movies.js";
// for "Result Highlighting" it requires the usage of a Document Index
// also when just adding id-content-pairs to a single index
const index = new Document({
// the cache is a perfect addition
// for an instant search on keypress
cache: true,
document: {
// it requires storing the documents
store: true,
index: [{
field: "title",
// a forward tokenizer is minimum
// required by an instant search
tokenize: "forward"
}]
}
});
for(let i = 0; i < data.length; i++){
// pass a flat pseudo document when using
// result highlighting on plain string inputs
index.add(i, {
"title": data[i]
});
}
const suggestions = document.getElementById("suggestions");
const autocomplete = document.getElementById("autocomplete");
const userinput = document.getElementById("userinput");
const suggest = document.getElementById("suggest");
const trigger_prev = document.getElementById("trigger-prev");
const trigger_next = document.getElementById("trigger-next");
let results = [];
let iterate = 0;
userinput.addEventListener("input", show_results, true);
userinput.addEventListener("keyup", accept_autocomplete, true);
userinput.addEventListener("keydown", iterate_selected, true);
suggest.addEventListener("change", toggle_suggest, true);
suggestions.addEventListener("click", accept_suggestion, true);
trigger_prev.addEventListener("focus", function(){
iterate_selected({ key: "ArrowUp"});
userinput.focus();
}, true);
trigger_next.addEventListener("focus", function(){
iterate_selected({ key: "ArrowDown"});
userinput.focus();
}, true);
function toggle_suggest(){
// changing any of the search options requires
// deletion of cached results (when using cache)
index.cache.clear();
show_results();
}
function show_results(){
results = index.searchCache({
query: userinput.value,
suggest: suggest.checked,
limit: 25,
pluck: "title",
enrich: true,
highlight: "<b>$1</b>"
});
let entry, childs = suggestions.childNodes;
let i = 0, len = results.length;
for(; i < len; i++){
entry = childs[i];
if(!entry){
entry = document.createElement("div");
suggestions.appendChild(entry);
}
entry.innerHTML = results[i].highlight; //data[results[i]];
}
while(childs.length > len){
suggestions.removeChild(childs[i]);
}
select_result(0);
iterate_selected();
}
function iterate_selected(event){
let index = iterate;
if(event){
const key = event.key;
if(key === "ArrowUp"){
if(iterate > 0){
select_result(--index);
}
event.preventDefault &&
event.preventDefault();
}
else if(key === "ArrowDown"){
if(iterate < results.length){
select_result(++index);
}
event.preventDefault &&
event.preventDefault();
}
}
let value = userinput.value;
let first_result = results && results[index] && data[results[index].id];
let match = first_result && first_result.toLowerCase().indexOf(value.toLowerCase());
if(first_result && (match > -1)){
autocomplete.value = value + first_result.substring(match + value.length);
autocomplete.current = first_result;
}
else{
autocomplete.value = autocomplete.current = value;
}
}
function select_result(index){
let node = suggestions.childNodes[iterate];
node && (node.style.backgroundColor = "");
iterate = index;
node = suggestions.childNodes[iterate];
node && (node.style.backgroundColor = "rgba(0, 0, 255, 0.1)");
}
function accept_autocomplete(event){
const key = (event || window.event).keyCode;
if(key === 13 || key === 39) {
userinput.value = autocomplete.value = autocomplete.current;
suggestions.textContent = "";
}
}
function accept_suggestion(event){
const target = (event || window.event).target;
userinput.value = autocomplete.value = target.textContent;
suggestions.textContent = "";
return false;
}
</script>
</body>
</html>