(function () {
'use strict';
const LIST_SELECTORS = [
'.woocommerce ul.products',
'.related.products ul.products',
'.upsells.products ul.products',
'.cross-sells ul.products'
];
function $all(root, sel) {
try { return Array.from((root || document).querySelectorAll(sel)); }
catch(e){ return []; }
}
// Espera todas as imagens de um container decodificarem (medição correta)
function waitImages(container) {
const imgs = $all(container, 'img');
const ps = imgs.map(img => {
if (img.complete && img.naturalWidth > 0) return Promise.resolve();
if (img.decode) return img.decode().catch(()=>{});
return new Promise(res => {
img.addEventListener('load', res, {once:true});
img.addEventListener('error', res, {once:true});
});
});
return Promise.all(ps);
}
function findLists(root) {
if (root && root.matches && root.matches('ul.products')) return [root];
const lists = [];
LIST_SELECTORS.forEach(sel => {
$all(document, sel).forEach(ul => lists.push(ul));
});
return lists;
}
function resetItem(li) {
li.style.display = '';
li.style.flexDirection = '';
const wrap = li.querySelector('.woocommerce-LoopProduct-link');
if (wrap) {
wrap.style.display = '';
wrap.style.flexDirection = '';
wrap.style.flex = '';
}
const title = li.querySelector('.woocommerce-loop-product__title');
const price = li.querySelector('.price');
if (title) title.style.minHeight = '';
if (price) price.style.minHeight = '';
const btn = li.querySelector('a.button, .added_to_cart');
if (btn) btn.style.marginTop = '';
}
// Define variáveis CSS por lista e usa min-height via CSS nos cards
async function equalizeList(ul) {
const items = $all(ul, 'li.product');
if (!items.length) return;
// Aguarda imagens para medir de forma confiável
await waitImages(ul);
items.forEach(li => {
resetItem(li);
li.style.display = 'flex';
li.style.flexDirection = 'column';
const wrap = li.querySelector('.woocommerce-LoopProduct-link');
if (wrap) {
wrap.style.display = 'flex';
wrap.style.flexDirection = 'column';
wrap.style.flex = '1 1 auto';
}
const btn = li.querySelector('a.button, .added_to_cart');
if (btn) btn.style.marginTop = 'auto';
});
let titleMax = 0;
let priceMax = 0;
items.forEach(li => {
const title = li.querySelector('.woocommerce-loop-product__title');
const price = li.querySelector('.price');
if (title) {
const h = title.getBoundingClientRect().height;
if (h > titleMax) titleMax = h;
}
if (price) {
const h = price.getBoundingClientRect().height;
if (h > priceMax) priceMax = h;
}
});
// Variáveis por UL – cada grade pode ter alturas próprias
ul.style.setProperty('--sv-title-min', titleMax ? `${titleMax}px` : 'auto');
ul.style.setProperty('--sv-price-min', priceMax ? `${priceMax}px` : 'auto');
}
function equalizeAll(root) {
const lists = findLists(root);
if (!lists.length) return;
lists.forEach(equalizeList);
}
// Agenda com RAF (evita rodar 100x durante mudanças)
let rafId;
function schedule(root) {
if (rafId) cancelAnimationFrame(rafId);
rafId = requestAnimationFrame(() => equalizeAll(root));
}
// Observa novas entradas no DOM (Carregar mais, Ajax, Relacionados, etc.)
const mo = new MutationObserver(muts => {
let touch = false;
for (const m of muts) {
if (touch) break;
m.addedNodes.forEach(n => {
if (n.nodeType !== 1) return;
if (n.matches && (n.matches('li.product') || n.matches('ul.products'))) touch = true;
else if (n.querySelector && n.querySelector('li.product, ul.products')) touch = true;
});
}
if (touch) schedule();
});
mo.observe(document.body, { childList: true, subtree: true });
// Gancho em frameworks comuns (YITH, Jet, etc.)
document.addEventListener('yith_infs_adding_elem', () => schedule());
document.addEventListener('yith_infs_loaded', () => schedule());
document.addEventListener('jet-filter-content-rendered', () => schedule());
document.addEventListener('jet-plugins/frontend/elementor/ajaxloaded', () => schedule());
document.addEventListener('woo_loadmore_success', () => schedule());
// Patch fetch / XHR pra agendar após qualquer Ajax
const _fetch = window.fetch;
window.fetch = function(){
return _fetch.apply(this, arguments).then(res=>{
try { res.clone().text().finally(schedule); } catch(e){}
schedule();
return res;
});
};
const _send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function(){
this.addEventListener('loadend', () => schedule(), {once:true});
_send.apply(this, arguments);
};
// ResizeObserver: se as alturas mudarem depois (ex: fontes web), recalcula
const ro = new ResizeObserver(() => schedule());
window.addEventListener('load', () => {
findLists().forEach(ul => ro.observe(ul));
schedule();
});
window.addEventListener('resize', schedule);
document.addEventListener('DOMContentLoaded', schedule);
})();
Gloss Labial 3D Payot Esta é uma loja de demonstração para fins de teste - As compras realizadas não são válidas. Dispensar