← back to Dw Theme Hamburger

assets/dw-pdp-size-pills.js

119 lines

/*
 * dw-pdp-size-pills.js  (Designer Wallcoverings PDP restyle, 2026-06-22)
 *
 * Progressive enhancement ONLY. We do NOT remove or replace the native
 * <select class="single-option-selector"> that the theme's variant /
 * cart / cowlendar / MOQ JS reads. We:
 *   1. keep the <select> in the DOM (visually hidden via dw-pdp-restyle.css),
 *   2. render one clickable pill <button> per <option>,
 *   3. on click -> set select.value + dispatch a native 'change' event so
 *      the existing jQuery `.on('change', '.single-option-selector', ...)'
 *      handler in custom.js.liquid (and everything downstream) fires exactly
 *      as if the user had used the dropdown.
 *
 * Safe to load globally; it no-ops on any page without a size selector.
 */
(function () {
  'use strict';
  if (window.__dwPdpSizePillsLoaded) return;
  window.__dwPdpSizePillsLoaded = true;

  var SELECTOR = 'select.single-option-selector';

  function buildPills(select) {
    if (!select || select.dataset.dwPilled === '1') return;
    // Only enhance real size/option selectors with 2+ choices.
    var opts = Array.prototype.slice.call(select.options);
    if (opts.length < 1) return;

    select.dataset.dwPilled = '1';

    // Hide the theme's styled dropdown shell (.select-wrapper / .selector-wrapper
    // with its .selected-text span) so the pills are the ONLY visible size control.
    var styledShell = select.closest('.select-wrapper') || select.closest('.selector-wrapper');
    if (styledShell) { styledShell.style.display = 'none'; }

    var wrap = document.createElement('div');
    wrap.className = 'dw-size-pills';
    wrap.setAttribute('role', 'radiogroup');
    var lbl = select.getAttribute('data-option-name') ||
              (select.options[0] && select.options[0].closest ? '' : '');
    wrap.setAttribute('aria-label', lbl || 'Size');

    opts.forEach(function (opt) {
      var btn = document.createElement('button');
      btn.type = 'button';
      btn.className = 'dw-size-pill';
      btn.setAttribute('role', 'radio');
      btn.textContent = (opt.textContent || opt.value || '').trim();
      btn.dataset.value = opt.value;
      if (opt.disabled) {
        btn.disabled = true;
        btn.classList.add('is-unavailable');
      }
      if (opt.selected) {
        btn.classList.add('is-active');
        btn.setAttribute('aria-checked', 'true');
      } else {
        btn.setAttribute('aria-checked', 'false');
      }
      btn.addEventListener('click', function () {
        if (btn.disabled) return;
        if (select.value === opt.value && opt.selected) {
          // already selected — still re-sync visual state
          syncActive(wrap, select);
          return;
        }
        select.value = opt.value;
        // Native change so jQuery delegated handlers + theme JS all fire.
        var evt;
        try {
          evt = new Event('change', { bubbles: true });
        } catch (e) {
          evt = document.createEvent('HTMLEvents');
          evt.initEvent('change', true, false);
        }
        select.dispatchEvent(evt);
        syncActive(wrap, select);
      });
      wrap.appendChild(btn);
    });

    // Insert the pills right before the (now hidden) select wrapper.
    var anchor = select.closest('.selector-wrapper') || select.parentNode;
    if (anchor && anchor.parentNode) {
      anchor.parentNode.insertBefore(wrap, anchor);
    }

    // DW 2026-06-25: pull the Download-PDF control into the size-pill row, next to Sample.
    var dlp = document.querySelector('.spec-sheet-controls'); if (dlp && !dlp.closest('.dw-size-pills')) wrap.appendChild(dlp);

    // Keep pills in sync if the select changes from any other source.
    select.addEventListener('change', function () {
      syncActive(wrap, select);
    });
  }

  function syncActive(wrap, select) {
    var val = select.value;
    Array.prototype.forEach.call(wrap.querySelectorAll('.dw-size-pill'), function (b) {
      var on = b.dataset.value === val;
      b.classList.toggle('is-active', on);
      b.setAttribute('aria-checked', on ? 'true' : 'false');
    });
  }

  function init() {
    var selects = document.querySelectorAll(SELECTOR);
    Array.prototype.forEach.call(selects, buildPills);
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
  // Re-run shortly after load in case theme JS injects/reorders selectors.
  window.addEventListener('load', function () { setTimeout(init, 600); });
})();