summaryrefslogtreecommitdiffstats
path: root/assets/js/cepis-woocommerce-classic.js
diff options
context:
space:
mode:
Diffstat (limited to 'assets/js/cepis-woocommerce-classic.js')
-rw-r--r--assets/js/cepis-woocommerce-classic.js92
1 files changed, 92 insertions, 0 deletions
diff --git a/assets/js/cepis-woocommerce-classic.js b/assets/js/cepis-woocommerce-classic.js
index 69d8068..481104c 100644
--- a/assets/js/cepis-woocommerce-classic.js
+++ b/assets/js/cepis-woocommerce-classic.js
@@ -23,6 +23,9 @@
var DIACRITIC = /[\u0300-\u036f]/g;
+ /** Class the widget gives the region it announces through. */
+ var STATUS = "cepis-autofill-status";
+
/**
* Compare labels the way a person would: accents and case do not count.
*
@@ -123,6 +126,90 @@
}
/**
+ * The `aria-live` region the widget announces through.
+ *
+ * The widget inserts it immediately after the CEP field and points the
+ * field's `aria-describedby` at it, but only once, when it attaches.
+ * WooCommerce re-renders the address fields afterwards — that is what
+ * `country_to_state_changed` does — and the attribute does not survive it
+ * while the region itself does. So the sibling is what is actually reliable
+ * here, and the surrounding form row is the fallback for a theme that wraps
+ * the input in something of its own.
+ *
+ * Never widened to a document-wide search: billing and shipping each have a
+ * region, and picking the wrong one would tell a shopper about the address
+ * they are not editing.
+ *
+ * @param {string} selector CSS selector for the CEP field.
+ * @returns {HTMLElement|null}
+ */
+ function statusRegion(selector) {
+ var field = document.querySelector(selector);
+
+ if (!field) {
+ return null;
+ }
+
+ var sibling = field.nextElementSibling;
+
+ if (sibling && sibling.classList && sibling.classList.contains(STATUS)) {
+ return sibling;
+ }
+
+ var node = field.parentElement;
+
+ for (var depth = 0; node && depth < 2; depth += 1) {
+ var region = node.querySelector("." + STATUS);
+
+ if (region) {
+ return region;
+ }
+
+ node = node.parentElement;
+ }
+
+ return null;
+ }
+
+ /**
+ * Say which municipality a CEP that does not exist would have been in.
+ *
+ * Rewrites the line the widget just wrote, and nothing else — no field is
+ * touched here, on this path, ever. The CEP was not found; there is no
+ * address to fill anything with, and inventing one from the municipality
+ * would send the parcel to the wrong town.
+ *
+ * Both guards before the write matter, because the answer arrives one round
+ * trip late: the shopper may have typed on, and the widget may have replaced
+ * the line with a "found" of its own in the meantime.
+ *
+ * @param {string} selector CSS selector for the CEP field.
+ * @param {string} cep The CEP that was not found.
+ */
+ function explain(selector, cep) {
+ var helper = window.cepisWooCommerceFaixa;
+ var region = statusRegion(selector);
+
+ if (!helper || !region) {
+ return;
+ }
+
+ var shown = region.textContent;
+
+ helper.message(cep, shown, function (message) {
+ var current = statusRegion(selector);
+ var field = document.querySelector(selector);
+ var typed = field ? String(field.value == null ? "" : field.value).replace(/\D+/g, "") : "";
+
+ if (message === shown || !current || current.textContent !== shown || typed !== cep) {
+ return;
+ }
+
+ current.textContent = message;
+ });
+ }
+
+ /**
* Attach one address section — billing or shipping.
*
* @param {Record<string, string>} map Selectors, keyed by the API's field names.
@@ -143,6 +230,11 @@
onResult: function (address) {
fillState(map.uf, address.uf, address.estado);
},
+ onError: function (error, context) {
+ if (error && "not_found" === error.code) {
+ explain(map.cep, context.cep);
+ }
+ },
};
Object.keys(map).forEach(function (field) {