@ideal-postcodes/address-finder
Version:
Address Finder JS library backed by the Ideal Postcodes UK address search API
68 lines (67 loc) • 2.75 kB
JavaScript
import { Client, checkKeyUsability } from "@ideal-postcodes/core-axios";
import { NOOP, defaults } from "./controller";
import { toContextMap } from "./contexts";
import { loaded, toArray, getParent, generateTimer, markLoaded, getScope, } from "@ideal-postcodes/jsutil";
import { setup } from "./setup";
const isTrue = () => true;
const getAnchors = (config, marker) => {
const scope = getScope(config.scope || null);
const matches = scope.querySelectorAll(config.anchor ||
config.inputField ||
(config.outputFields || {}).line_1);
return toArray(matches).filter((e) => !loaded(e, marker));
};
const DEFAULT_INTERVAL = 1000;
const formScope = (anchor) => getParent(anchor, "FORM");
/**
* Dynamically apply AddressFinder when relevant fields appear
* - Exits if page test is fails
* - Check if key usable
* - Creates a bind method
* - Retrives parent scope
* - Marks anchor if completed
* - Creates timer tools
*/
export const watch = (config, options = {}) => {
const client = new Client({ ...defaults, ...config, api_key: config.apiKey });
const { pageTest = isTrue } = options;
if (!pageTest())
return Promise.resolve(null);
return checkKeyUsability({ client })
.then((key) => {
if (!key.available)
return null;
const { getScope = formScope, interval = DEFAULT_INTERVAL, anchor, onBind = NOOP, onAnchorFound = NOOP, onBindAttempt = NOOP, immediate = true, marker = "idpc", } = options;
const bind = () => {
onBindAttempt({ config, options });
getAnchors({ anchor, ...config }, marker).forEach((anchor) => {
const scope = getScope(anchor);
if (!scope)
return;
const contexts = toContextMap(key.contexts);
const newConfig = { scope, ...config, checkKey: false, contexts };
onAnchorFound({ anchor, scope, config: newConfig });
const c = setup(newConfig);
const details = c.options.contexts[key.context];
if (c.options.detectCountry && details) {
c.applyContext(details, false);
}
else {
c.applyContext(c.currentContext(), false);
}
markLoaded(anchor, marker);
onBind(c);
});
};
const { start, stop } = generateTimer({ bind, pageTest, interval });
if (immediate)
start();
return { start, stop, bind };
})
.catch((e) => {
// Swallow promise errors and raise via optionall onError callback
if (options.onError)
options.onError(e);
return null;
});
};