public/src/js/widgets/autocomplete.js (113 lines of code) (raw):
import ko from 'knockout';
import _ from 'underscore';
import BaseWidget from 'widgets/base-widget';
import autocomplete from 'modules/auto-complete';
import debounce from 'utils/debounce';
import {CONST} from 'modules/vars';
var typeBounceSym = Symbol();
var setFilter = Symbol();
var preventUpdate = Symbol();
export default class AutoComplete extends BaseWidget {
constructor(opts) {
super();
this.suggestions = ko.observableArray();
this.filterType = ko.observable();
this.filterTypes = ko.observableArray(_.values(CONST.filterTypes) || []);
this.alertMessage = ko.observable(false);
this.filter = ko.observable('');
this.subscribeOn(this.filter, () => {
if (!this[preventUpdate]) {
this.type();
}
});
this[setFilter] = (suggestion) => {
// Prevent types update
this[preventUpdate] = true;
this.filter(suggestion && suggestion.id ? suggestion.id : suggestion);
this[preventUpdate] = false;
};
this.placeholder = ko.pureComputed(() => {
return (this.filterType() || {}).placeholder;
});
this.open = ko.pureComputed(() => {
return this.alertMessage() || this.suggestions().length;
});
this.paginationInProgress = ko.observable(false);
this.currentPage = ko.observable(1);
this.totalPages = ko.observable(1);
this.hasMoreSuggestions = ko.pureComputed(() => {
return this.suggestions().length > 0 && (this.currentPage() < this.totalPages());
});
this[typeBounceSym] = debounce(() => {
return autocomplete(this.state());
}, CONST.searchDebounceMs);
if (opts.parent && opts.parent.registerChild) {
opts.parent.registerChild(this);
this.listenOn(opts.parent, 'clear', () => {
this.clear();
this.emit('change', this.state());
});
}
}
select(suggestion) {
this[setFilter](suggestion);
this.suggestions.removeAll();
this.emit('change', this.state());
}
state() {
return {
query: this.filter(),
path: this.getPath(),
param: (this.filterType() || {}).param
};
}
getPath() {
return (this.filterType() || {}).path;
}
clear() {
this.suggestions.removeAll();
this.alertMessage(false);
this[setFilter]('');
}
type() {
if (this.filter()) {
this.alertMessage('searching for ' + this.filter() + '...');
this[typeBounceSym]().then(res => {
this.alertMessage(false);
if (res && res.results && res.results.length) {
this.currentPage(res.currentPage || 1);
this.totalPages(res.pages || 1);
this.suggestions(res.results);
} else {
this.alertMessage('...sorry, no ' + this.getPath() + ' found.');
}
})
.catch(ex => {
this.alertMessage(ex.message);
})
.then(() => this.emit('update'));
} else {
this.select('');
}
}
nextPage() {
var state = this.state();
state.page = this.currentPage() + 1;
this.paginationInProgress(true);
autocomplete(state).then(res => {
if (res && res.results && res.results.length) {
this.currentPage(res.currentPage || 1);
this.totalPages(res.pages || 1);
this.suggestions(this.suggestions().concat(res.results));
} else {
this.alertMessage('...sorry, no ' + this.getPath() + ' found.');
}
})
.catch(ex => {
this.alertMessage(ex.message);
})
.then(() => {
this.paginationInProgress(false);
this.emit('update');
});
}
}