← 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); });
})();