added async search capability
This commit is contained in:
parent
50d3631bc4
commit
c81628a66e
1 changed files with 124 additions and 0 deletions
124
src/util/AsyncSearch.js
Normal file
124
src/util/AsyncSearch.js
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
|
class AsyncSearch extends EventEmitter {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._reset();
|
||||||
|
|
||||||
|
this.RESULT_SENT = 'RESULT_SENT';
|
||||||
|
}
|
||||||
|
|
||||||
|
_reset() {
|
||||||
|
this.dataList = null;
|
||||||
|
this.term = null;
|
||||||
|
this.searchKeys = null;
|
||||||
|
this.isContain = false;
|
||||||
|
this.isCaseSensitive = false;
|
||||||
|
this.ignoreWhitespace = true;
|
||||||
|
this.limit = null;
|
||||||
|
this.findingList = [];
|
||||||
|
|
||||||
|
this.searchUptoIndex = 0;
|
||||||
|
this.sessionStartTimestamp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_softReset() {
|
||||||
|
this.term = null;
|
||||||
|
this.findingList = [];
|
||||||
|
this.searchUptoIndex = 0;
|
||||||
|
this.sessionStartTimestamp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the search.
|
||||||
|
* opts.keys are required when dataList items are object.
|
||||||
|
*
|
||||||
|
* @param {[string | object]} dataList - A list to search in
|
||||||
|
* @param {object} opts - Options
|
||||||
|
* @param {string | [string]} [opts.keys=null]
|
||||||
|
* @param {boolean} [opts.isContain=false] - Add finding to result if it contain search term
|
||||||
|
* @param {boolean} [opts.isCaseSensitive=false]
|
||||||
|
* @param {boolean} [opts.ignoreWhitespace=true]
|
||||||
|
* @param {number} [opts.limit=null] - Stop search after limit
|
||||||
|
*/
|
||||||
|
setup(dataList, opts) {
|
||||||
|
this._reset();
|
||||||
|
this.dataList = dataList;
|
||||||
|
this.searchKeys = opts?.keys || null;
|
||||||
|
this.isContain = opts?.isContain || false;
|
||||||
|
this.isCaseSensitive = opts?.isCaseSensitive || false;
|
||||||
|
this.ignoreWhitespace = opts?.ignoreWhitespace || true;
|
||||||
|
this.limit = opts?.limit || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
search(term) {
|
||||||
|
this._softReset();
|
||||||
|
|
||||||
|
this.term = (this.isCaseSensitive) ? term : term.toLocaleLowerCase();
|
||||||
|
if (this.ignoreWhitespace) this.term = this.term.replace(' ', '');
|
||||||
|
|
||||||
|
this._find(this.sessionStartTimestamp, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_find(sessionTimestamp, lastFindingCount) {
|
||||||
|
if (sessionTimestamp !== this.sessionStartTimestamp) return;
|
||||||
|
this.sessionStartTimestamp = window.performance.now();
|
||||||
|
|
||||||
|
for (
|
||||||
|
let searchIndex = this.searchUptoIndex;
|
||||||
|
searchIndex < this.dataList.length;
|
||||||
|
searchIndex += 1
|
||||||
|
) {
|
||||||
|
if (this._match(this.dataList[searchIndex])) {
|
||||||
|
this.findingList.push(this.dataList[searchIndex]);
|
||||||
|
if (typeof this.limit === 'number' && this.findingList.length >= this.limit) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const calcFinishTime = window.performance.now();
|
||||||
|
if (calcFinishTime - this.sessionStartTimestamp > 8) {
|
||||||
|
const thisFindingCount = this.findingList.length;
|
||||||
|
const thisSessionTimestamp = this.sessionStartTimestamp;
|
||||||
|
if (lastFindingCount !== thisFindingCount) this._sendFindings();
|
||||||
|
|
||||||
|
this.searchUptoIndex = searchIndex + 1;
|
||||||
|
queueMicrotask(() => this._find(thisSessionTimestamp, thisFindingCount));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastFindingCount !== this.findingList.length
|
||||||
|
|| lastFindingCount === 0) this._sendFindings();
|
||||||
|
this._softReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
_match(item) {
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
return this._compare(item);
|
||||||
|
}
|
||||||
|
if (typeof item === 'object') {
|
||||||
|
if (Array.isArray(this.searchKeys)) {
|
||||||
|
return !!this.searchKeys.find((key) => this._compare(item[key]));
|
||||||
|
}
|
||||||
|
if (typeof this.searchKeys === 'string') {
|
||||||
|
return this._compare(item[this.searchKeys]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_compare(item) {
|
||||||
|
if (typeof item !== 'string') return false;
|
||||||
|
let myItem = (this.isCaseSensitive) ? item : item.toLocaleLowerCase();
|
||||||
|
if (this.ignoreWhitespace) myItem = myItem.replace(' ', '');
|
||||||
|
|
||||||
|
if (this.isContain) return myItem.indexOf(this.term) !== -1;
|
||||||
|
return myItem.startsWith(this.term);
|
||||||
|
}
|
||||||
|
|
||||||
|
_sendFindings() {
|
||||||
|
this.emit(this.RESULT_SENT, this.findingList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AsyncSearch;
|
Loading…
Reference in a new issue