mirror of https://github.com/nocodb/nocodb
89 lines
1.8 KiB
89 lines
1.8 KiB
// ref : https://medium.com/weekly-webtips/js-implementing-auto-complete-f4c5a5d5c009 |
|
|
|
interface Node { |
|
value: [] |
|
isLeaf: boolean |
|
children: Record<string, Node> |
|
} |
|
|
|
export class NcAutocompleteTree { |
|
trie: Record<string, any> |
|
suggestions: Record<string, any>[] |
|
|
|
constructor() { |
|
this.trie = {} |
|
this.suggestions = [] |
|
} |
|
|
|
newNode(): Node { |
|
return { |
|
value: [], |
|
isLeaf: false, |
|
children: {}, |
|
} |
|
} |
|
|
|
add(word: Record<string, any>) { |
|
if (Object.keys(this.trie).length === 0) { |
|
this.trie = this.newNode() |
|
} |
|
|
|
let root = this.trie |
|
for (const letter of word.text.toLowerCase()) { |
|
if (!(letter in root.children)) { |
|
root.children[letter] = this.newNode() |
|
} |
|
root = root.children[letter] |
|
} |
|
root.value = root.value || [] |
|
root.value.push(word) |
|
root.isLeaf = true |
|
} |
|
|
|
find(word: string) { |
|
let root = this.trie |
|
for (const letter of word) { |
|
if (letter in root.children) { |
|
root = root.children[letter] |
|
} else { |
|
return null // if not found return null |
|
} |
|
} |
|
return root // return the root where it ends search |
|
} |
|
|
|
traverse(root: Node) { |
|
if (root.isLeaf) { |
|
this.suggestions.push(...root.value) |
|
} |
|
|
|
for (const letter in root.children) { |
|
this.traverse(root.children[letter]) |
|
} |
|
} |
|
|
|
complete(word: string, CHILDREN = null) { |
|
this.suggestions = [] |
|
const root = this.find(word.toLowerCase()) |
|
|
|
if (!root) { |
|
return this.suggestions |
|
} // cannot suggest anything |
|
|
|
this.suggestions.push(...root.value) |
|
|
|
const children = root.children |
|
|
|
let spread = 0 |
|
for (const letter in children) { |
|
this.traverse(children[letter]) |
|
spread++ |
|
|
|
if (CHILDREN && spread === CHILDREN) { |
|
break |
|
} |
|
} |
|
|
|
return this.suggestions |
|
} |
|
}
|
|
|