mirror of
https://github.com/nextapps-de/flexsearch.git
synced 2025-09-25 12:58:59 +02:00
269 lines
8.1 KiB
HTML
269 lines
8.1 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{
|
|
pointer-events: none
|
|
}
|
|
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;
|
|
}
|
|
input[type="text"]{
|
|
/*width: 98%;*/
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="header">
|
|
<div 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">
|
|
</div>
|
|
<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, Charset } from "https://cdn.jsdelivr.net/gh/nextapps-de/flexsearch@master/dist/flexsearch.bundle.module.min.js";
|
|
import { Document, Charset } from "../src/bundle.js";
|
|
//import EnglishPreset from "../src/lang/en.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_autocomplete, true);
|
|
suggest.addEventListener("change", toggle_suggest, true);
|
|
suggestions.addEventListener("click", accept_suggestion, true);
|
|
|
|
trigger_prev.addEventListener("focus", function(){
|
|
if(iterate > 0) {
|
|
iterate_autocomplete({ key: "ArrowUp"});
|
|
}
|
|
userinput.focus();
|
|
}, true);
|
|
trigger_next.addEventListener("focus", function(){
|
|
if(iterate < results.length){
|
|
iterate_autocomplete({ 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(){
|
|
|
|
let value = userinput.value;
|
|
results = index.searchCache({
|
|
query: value,
|
|
limit: 25,
|
|
suggest: suggest.checked,
|
|
enrich: true,
|
|
highlight: "<b>$1</b>"
|
|
});
|
|
results = results[0] || results;
|
|
results = results.result || results;
|
|
iterate = 0;
|
|
|
|
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]);
|
|
}
|
|
|
|
iterate_autocomplete()
|
|
}
|
|
|
|
function iterate_autocomplete(event){
|
|
|
|
suggestions.childNodes[iterate] &&
|
|
(suggestions.childNodes[iterate].style.backgroundColor = "");
|
|
|
|
if(event){
|
|
const key = event.key;
|
|
if(key === "ArrowUp"){
|
|
if(iterate > 0){
|
|
iterate--;
|
|
}
|
|
event.preventDefault &&
|
|
event.preventDefault();
|
|
}
|
|
else if(key === "ArrowDown"){
|
|
if(iterate < results.length){
|
|
iterate++;
|
|
}
|
|
event.preventDefault &&
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
|
|
let value = userinput.value;
|
|
let first_result = results && results[iterate] && data[results[iterate].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;
|
|
suggestions.childNodes[iterate] &&
|
|
(suggestions.childNodes[iterate].style.backgroundColor = "rgb(0 0 255 / 10%)");
|
|
}
|
|
else{
|
|
|
|
autocomplete.value = autocomplete.current = value;
|
|
}
|
|
}
|
|
|
|
function accept_autocomplete(event){
|
|
|
|
if((event || window.event).keyCode === 13) {
|
|
this.value = autocomplete.value = autocomplete.current;
|
|
suggestions.textContent = "";
|
|
}
|
|
}
|
|
|
|
function accept_suggestion(event){
|
|
|
|
let target = (event || window.event).target;
|
|
userinput.value = autocomplete.value = target.textContent;
|
|
suggestions.textContent = "";
|
|
|
|
return false;
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|