Skip to content

1.14.2

Choose a tag to compare

@enderecoFlorian enderecoFlorian released this 18 Feb 06:16
· 9 commits to master since this release

Overview

This release improves submit reliability and modal keyboard behavior. The main focus is on resolving edge cases where form submission silently fails due to third-party listener interference, and on preventing keyboard events from escaping the address correction modal.

Key improvements in 1.14.2:

  • Flexible target selector with resolver support and configurable insert position
  • Fixed form submission failing when clicking nested elements inside submit buttons
  • Fixed Enter key escaping the modal focus trap and triggering implicit form submission
  • Fixed third-party click listeners interfering with submit resumption

New Features

Flexible Target Selector Configuration

  • Feature: The targetSelector option now supports dynamic resolution via a resolver function, and a new insertPosition option controls where inside the target element the modal is placed
  • Problem Solved: Static CSS selectors are insufficient when the injection target depends on runtime state (e.g., dynamically created modals, multiple forms on one page)
  • Configuration:
    • insertPosition option on initAMS() , accepts standard insertAdjacentHTML positions: 'beforebegin', 'afterbegin', 'beforeend' (default), 'afterend'
    • resolvers.targetSelectorResolve(selector, addressObject) , a resolver function that receives the configured selector and address object, and returns the actual selector to use. Falsy return values fall back to the original selector
  • Reference: GitHub #23

Using the Resolver

EnderecoIntegrator.resolvers.targetSelectorResolve = function(selector, addressObject) {
    // Dynamically determine the target based on runtime state
    const activeModal = document.querySelector('.modal.show');
    if (activeModal) {
        return '#' + activeModal.id;
    }
    return selector; // fall back to configured selector
};

Using Insert Position

EnderecoIntegrator.initAMS({
    countryCode: '[name="country"]',
    postalCode: '[name="zipcode"]',
    locality: '[name="city"]',
    streetFull: '[name="street"]'
}, {
    targetSelector: '.my-modal-container',
    insertPosition: 'afterbegin'
});

Bug Fixes

Form Submit with Nested Button Elements

  • Bug: Clicking on a nested element inside a submit button (e.g., <span> or <svg> icon) would cause the resumed submission to silently fail
  • Root Cause: After validation, resumeFormSubmission() dispatched the synthetic click event on originalEvent.target, which was the inner element (span, svg), not the submit button itself. The inner element has no submit behavior
  • Solution: Use originalEvent.target.closest('button, input[type="submit"]') to resolve to the actual submit control regardless of where inside the button the click occurred

Enter Key Escaping Modal Focus Trap

  • Bug: Pressing Enter inside the address correction modal could trigger implicit form submission of the underlying page form, or propagate to parent handlers
  • Root Cause: Two issues , (1) Enter keydown events inside the modal were not stopped from propagating, and (2) modal buttons had no explicit type attribute, defaulting to type="submit" inside forms
  • Solution:
    • Added an Enter key handler to the modal that calls stopPropagation() on all Enter presses and preventDefault() on input elements (radio buttons, checkboxes) to block implicit form submission
    • Added explicit type="button" to all modal button templates
  • Behavior: Buttons and links inside the modal still activate normally via Enter; only propagation to the parent form is blocked

Third-Party Listeners Blocking Form Submission

  • Bug: Form submission silently fails when third-party plugins register click listeners on the same submit button
  • Root Cause: blockSubmit() used stopPropagation(), which only prevents bubbling to parent elements. Other listeners registered on the same button still fired during the blocking phase. A third-party multi-click preventer would see the original click, add a loading state, and then call preventDefault() on the resumed synthetic click , silently preventing form submission
  • Solution: Use stopImmediatePropagation() instead, which prevents all subsequent listeners on the same element from firing during the blocking phase. Third-party listeners still participate normally on the resumed event, since the resumed event is a new Event object unaffected by the original stopImmediatePropagation()
  • Behavior: Third-party listeners see exactly one click event , the resumed one after validation , instead of two (one blocked, one resumed)

External Modal Removal Leaves System in Broken State

  • Bug: When the endereco modal is injected inside a dynamically-rendered parent (e.g. a third-party checkout overlay) via targetSelector, closing that parent leaves the page in a broken state — scroll locked, future modals blocked
  • Root Cause: All Promise resolve paths lived exclusively in DOM event handlers attached to elements inside the modal. When an external actor removed the parent (and with it the endereco modal), no events could fire, so the Promise never resolved, endereco-no-scroll stayed on the body, and popupQueue counters remained incremented
  • Solution: A MutationObserver watches for the modal element being disconnected from the document. When triggered, it performs the same cleanup as removePopup() and resolves the Promise. In the normal flow, each handler disconnects the observer before resolving to prevent double cleanup
  • Ref: DEV-331

Update Notes

This is a drop-in replacement for 1.14.1. No configuration changes are required unless you want to use the new insertPosition or targetSelectorResolve features.