autocompleter-typescript-gcba
Version:
Autocompleter para direcciones y lugares de la Ciudad de Buenos Aires
335 lines (334 loc) • 13.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Autocompleter = void 0;
const config_1 = require("./config");
const types_1 = require("./types");
const SuggesterLugares_1 = require("./suggesters/SuggesterLugares");
const SuggesterDirecciones_1 = require("./suggesters/SuggesterDirecciones");
const SuggesterDireccionesAMBA_1 = require("./suggesters/SuggesterDireccionesAMBA");
const SuggesterDeficitHabitacional_1 = require("./suggesters/SuggesterDeficitHabitacional");
const SuggesterCatastro_1 = require("./suggesters/SuggesterCatastro");
const defaultOptions = {
inputPause: 200,
maxSuggestions: 10,
serverTimeout: 30000,
minTextLength: 3,
maxRetries: 1,
flushTimeout: 0,
suggesters: [
{
name: 'Direcciones',
options: { inputPause: 300, minTextLength: 3 },
class: SuggesterDirecciones_1.SuggesterDirecciones,
},
{
name: 'Lugares',
options: { inputPause: 500, minTextLength: 3 },
class: SuggesterLugares_1.SuggesterLugares,
},
{
name: 'DireccionesAMBA',
options: { inputPause: 500, minTextLength: 3 },
class: SuggesterDireccionesAMBA_1.SuggesterDireccionesAMBA,
},
{
name: 'DeficitHabitacional',
options: { inputPause: 500, minTextLength: 3 },
class: SuggesterDeficitHabitacional_1.SuggesterDeficitHabitacional,
},
{
name: 'Catastro',
options: { inputPause: 500, minTextLength: 3 },
class: SuggesterCatastro_1.SuggesterCatastro,
},
],
debug: false,
texts: {
nothingFound: 'No se hallaron resultados coincidentes con su búsqueda.',
},
};
const emptyCallback = () => {
console.debug('Callback not implemented');
};
class Autocompleter {
constructor(callbacks, options) {
this.suggesters = [];
this.registeredSuggesters = [];
this.suggestions = [];
this.suggestersByName = {};
this.pendingRequests = {};
this.currentText = '';
this.numPendingRequests = 0;
this.appendResults = false;
this.bufferedResults = [];
this.flushTimer = null;
this.appendBufferedResults = false;
this.options = { ...defaultOptions, ...options };
this.initializeCallbacks(callbacks);
this.initializeState();
this.initializeRegisteredSuggesters();
}
initializeCallbacks(callbacks) {
this.onSuggestions = (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onSuggestions) || emptyCallback;
this.onCompleteSuggestions = (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onCompleteSuggestions) || emptyCallback;
this.onUpdate = (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onUpdate) || emptyCallback;
this.onError = (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onError) || emptyCallback;
this.onMessage = (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onMessage) || emptyCallback;
this.onBufferResults = (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onBufferResults) || emptyCallback;
}
initializeState() {
this.globalState = {
currentText: this.currentText,
suggesters: [],
suggestions: [],
pendingRequests: 0,
waitingSuggesters: 0,
};
}
initializeRegisteredSuggesters() {
this.options.suggesters.forEach((suggester) => {
this.registeredSuggesters.push(suggester);
});
}
setCallbacks(callbacks) {
this.initializeCallbacks(callbacks);
}
getSuggesters() {
return this.suggesters;
}
addSuggester(suggester, options = {}) {
const name = typeof suggester === 'string' ? suggester : suggester.name;
if (this.suggestersByName[name]) {
if (this.options.debug) {
console.debug('Se intentó agregar dos suggesters con el mismo nombre.');
}
return false;
}
try {
const sgObj = this.createSuggester(suggester, options);
this.suggestersByName[name] = sgObj;
this.pendingRequests[name] = 0;
this.suggesters.push(sgObj);
return true;
}
catch (error) {
if (this.options.debug) {
console.debug(`ERROR: Suggester: ${name} creation failed.`);
}
return false;
}
}
createSuggester(suggester, options = {}) {
if (typeof suggester === 'string') {
const suggesterConfig = this.registeredSuggesters.find((s) => s.name === suggester);
if (!suggesterConfig) {
throw new Error('Suggester no encontrado');
}
const mergedOptions = {
...this.options,
...options,
onReady: this.options.onReady,
debug: this.options.debug,
maxRetries: this.options.maxRetries,
afterServerRequest: this.handleServerRequest.bind(this),
afterServerResponse: this.handleServerResponse.bind(this),
afterAbort: this.handleAbort.bind(this),
};
return new suggesterConfig.class(suggester, mergedOptions);
}
suggester.setOptions({
debug: this.options.debug,
maxRetries: this.options.maxRetries,
afterServerRequest: this.handleServerRequest.bind(this),
afterServerResponse: this.handleServerResponse.bind(this),
afterAbort: this.handleAbort.bind(this),
});
return suggester;
}
removeSuggester(suggester) {
const name = typeof suggester === 'string' ? suggester : suggester.name;
this.suggesters = this.suggesters.filter((s) => s.name !== name);
delete this.suggestersByName[name];
}
async updateCoordenadas(suggestion) {
if (suggestion.suggesterName === 'Direcciones') {
return this.fetchCoordenadas(`${suggestion.data.nombre},${suggestion.data.descripcion}`);
}
else if (suggestion.suggesterName === 'DireccionesAMBA') {
return this.fetchCoordenadas(`${suggestion.data.nombre}, ${suggestion.data.descripcion.split(',', 2)[0]}`);
}
return null;
}
async fetchCoordenadas(direccion) {
var _a, _b;
try {
const response = await fetch(`${config_1.usig_webservice_url}/normalizar/?direccion=${direccion}&geocodificar=true&srid=4326`);
const data = await response.json();
if ((_b = (_a = data.direccionesNormalizadas) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.coordenadas) {
return data.direccionesNormalizadas[0].coordenadas;
}
return null;
}
catch (error) {
if (this.options.debug) {
console.error('Error fetching coordenadas:', error);
}
return null;
}
}
updateSuggestions(newValue) {
this.currentText = newValue;
this.suggestions = [];
this.abortPendingRequests();
this.appendResults = false;
this.suggesters.forEach((suggester) => {
if (newValue.length >= suggester.options.minTextLength) {
suggester.status = types_1.SuggesterStatus.INPUT_WAIT;
suggester.inputTimer = setTimeout(() => this.suggest(suggester, newValue), suggester.options.inputPause);
}
});
this.onUpdate(this.getGlobalState());
}
abortPendingRequests() {
this.suggesters.forEach((suggester) => {
if (suggester.inputTimer) {
if (this.options.debug) {
console.debug(`Aborting suggester ${suggester.name}`);
}
clearTimeout(suggester.inputTimer);
suggester.status = types_1.SuggesterStatus.DONE;
}
});
}
suggest(suggester, text) {
this.handleServerRequest(suggester.name);
if (this.options.debug) {
console.debug(`Starting suggestions fetch. Suggesters ready?: ${this.isInitialized()}`);
}
suggester.getSuggestions(text, (results, inputStr, suggesterName) => this.handleSuggestions(results, inputStr, suggesterName), suggester.options.maxSuggestions);
}
handleSuggestions(results, inputStr, suggesterName) {
var _a;
if (this.currentText !== inputStr) {
return; // Respuesta a destiempo
}
if ('getError' in results) {
// @ts-ignore
this.onError(((_a = results.getError) === null || _a === void 0 ? void 0 : _a.call(results)) || results.message);
return;
}
if (results.length === 0) {
this.onMessage({
message: 'No results found',
suggester: suggesterName,
});
return;
}
if (Array.isArray(results)) {
this.suggestions = this.suggestions.concat(results).slice(0, this.options.maxSuggestions);
if (this.options.flushTimeout > 0) {
this.bufferResults(results, this.appendResults);
}
else {
this.onSuggestions(this.suggestions, this.appendResults);
}
this.appendResults = true;
}
this.handleServerResponse(suggesterName);
this.checkForCompleteSuggestions();
}
checkForCompleteSuggestions() {
if (this.suggesters.every((s) => s.status === types_1.SuggesterStatus.DONE)) {
this.onCompleteSuggestions(this.suggestions, this.appendResults);
}
}
handleAbort(suggesterName) {
if (this.pendingRequests[suggesterName] > 0) {
this.pendingRequests[suggesterName]--;
this.numPendingRequests--;
}
this.logDebug(`ServerResponse ${suggesterName}`);
}
handleServerRequest(suggesterName) {
var _a, _b;
this.pendingRequests[suggesterName]++;
this.numPendingRequests++;
const suggester = this.suggesters.find((s) => s.name === suggesterName);
if (suggester) {
suggester.status = types_1.SuggesterStatus.PENDING;
}
this.logDebug(`ServerResponse ${suggesterName}`);
(_b = (_a = this.options).afterServerRequest) === null || _b === void 0 ? void 0 : _b.call(_a);
this.onUpdate(this.getGlobalState());
}
handleServerResponse(suggesterName) {
const suggester = this.suggesters.find((s) => s.name === suggesterName);
if (!suggester) {
return;
}
if (this.pendingRequests[suggesterName] > 0) {
this.pendingRequests[suggesterName]--;
this.numPendingRequests--;
if (this.pendingRequests[suggesterName] === 0) {
suggester.status = types_1.SuggesterStatus.DONE;
}
}
this.logDebug(`ServerResponse ${suggesterName}`);
if (this.options.afterServerResponse && this.numPendingRequests === 0) {
this.options.afterServerResponse();
}
this.onUpdate(this.getGlobalState());
}
logDebug(action) {
if (this.options.debug) {
console.debug(`usig.AutoCompleter.${action}. Num Pending Requests: ${this.numPendingRequests}`);
console.debug(this.pendingRequests);
}
}
bufferResults(results, appendResults) {
if (!appendResults) {
if (this.options.debug) {
console.debug('Resetting buffered results...');
}
this.bufferedResults = [];
this.appendBufferedResults = false;
}
if (this.options.debug) {
console.debug('Appending to buffered results...');
}
this.bufferedResults.push(...results);
if (!this.flushTimer) {
if (this.options.debug) {
console.debug('Setting flush timer...');
}
this.appendBufferedResults = appendResults;
this.suggestions = this.bufferedResults;
this.flushTimer = setTimeout(() => this.handleBufferCallback(), this.options.flushTimeout);
}
}
handleBufferCallback() {
if (this.bufferedResults.length > 0) {
this.onBufferResults(this.suggestions);
this.bufferedResults = [];
this.flushTimer = null;
}
}
getGlobalState() {
return {
currentText: this.currentText,
suggesters: this.suggesters.map((s) => ({
name: s.name,
status: s.status,
})),
suggestions: this.suggestions,
pendingRequests: this.numPendingRequests,
waitingSuggesters: this.suggesters.filter((s) => s.status === types_1.SuggesterStatus.INPUT_WAIT)
.length,
};
}
isInitialized() {
return this.suggesters.every((s) => s.ready());
}
}
exports.Autocompleter = Autocompleter;
exports.default = Autocompleter;