.ecom-coleccion_tematica body {
font-family: Arial, sans-serif;
font-size: 14px;
color: #333;
background: #f9f9f9;
}
.ecom-coleccion_tematica .main-container,
.ecom-coleccion_tematica .container {
width: 100%;
margin: 40px auto;
display: flex;
gap: 24px;
}
.ecom-coleccion_tematica .main-container {
max-width: 1200px;
}
.ecom-coleccion_tematica .container {
padding: 1em 5em;
}
.ecom-coleccion_tematica .top-section {
display: flex;
align-items: flex-start;
gap: 24px;
}
.ecom-coleccion_tematica .promo-banner {
display: flex;
align-items: center;
justify-content: center;
background: #111;
color: #fff;
font-size: 14px;
padding: 12px 20px;
gap: 8px;
}
.ecom-coleccion_tematica .promo-banner .discount {
color: #ffd700;
font-weight: bold;
}
.ecom-coleccion_tematica .promo-banner .conditions {
display: flex;
align-items: center;
font-weight: bold;
text-decoration: none;
color: #fff;
}
.ecom-coleccion_tematica .promo-banner .conditions:hover {
text-decoration: underline;
}
.ecom-coleccion_tematica .promo-banner .conditions i {
margin-left: 4px;
font-size: 16px;
}
.ecom-coleccion_tematica .product-detail {
flex: 1;
background: #fff;
padding: 24px;
border-radius: 4px;
}
.ecom-coleccion_tematica .header {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 16px;
}
.ecom-coleccion_tematica .header .logo {
max-width: 200px;
}
.ecom-coleccion_tematica .title {
font-family: 'SohoPro-Regular';
font-size: 24px;
color: #00437a;
font-weight: bold;
}
.ecom-coleccion_tematica .subinfo {
display: inline-block;
margin: 10px 0 0;
padding: 4px 8px;
background: #D8F8FF;
font-size: 12px;
font-weight: bold;
color: #00437A;
}
.ecom-coleccion_tematica .description {
margin: 10px 0 20px;
font-family: 'SohoPro-Regular';
font-size: 1.2em;
font-weight: 600;
line-height: 1.4;
color: #222;
}
.ecom-coleccion_tematica .btn {
display: inline-block;
font-family: 'SohoPro-Regular';
font-weight: bold;
padding: 8px 16px;
text-decoration: none;
}
.ecom-coleccion_tematica .extract-btn {
font-size: 1em !important;
border: 2px solid #00437a;
color: #00437a;
transition: background .2s, color .2s;
text-transform: none !important;
}
.ecom-coleccion_tematica .extract-btn:hover {
background: #00437a;
color: #120e5b;
}
.ecom-coleccion_tematica .purchase-box {
flex: 0 0 300px;
background: #f3f6f9;
padding: 10px 0 15px;
border-radius: 4px;
text-align: center;
}
.ecom-coleccion_tematica .purchase-box .price-header {
padding: 16px;
text-align: left;
}
.ecom-coleccion_tematica .purchase-box .price-header .price {
font-family: 'SohoPro-Regular';
font-size: 28px;
font-weight: bold;
color: #00437a;
}
.ecom-coleccion_tematica .purchase-box .price-header .note {
font-family: sans-serif;
font-size: 12px;
font-weight: 500;
margin-top: 4px;
color: #000;
}
.ecom-coleccion_tematica .purchase-box .selectors {
display: flex;
align-items: center;
gap: 8px;
padding: 0 16px 16px;
}
.ecom-coleccion_tematica .purchase-box .selectors .qty {
flex: 0 0 50px;
}
.ecom-coleccion_tematica .purchase-box .selectors input,
.ecom-coleccion_tematica .purchase-box .selectors select {
width: 100%;
height: 40px;
padding: 0 12px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: #fff;
}
.ecom-coleccion_tematica .purchase-box .selectors select {
background-image: url(/documents/d/global/ico-chevron-down);
background-repeat: no-repeat;
background-size: 18px 10px;
background-position: right 12px center;
}
.ecom-coleccion_tematica .purchase-box .selectors select::-ms-expand {
display: none;
}
.ecom-coleccion_tematica .purchase-box .selectors .selector {
position: relative;
flex: 1;
}
.ecom-coleccion_tematica .purchase-box .selectors .selector .arrow {
position: absolute;
top: 50%;
right: 12px;
transform: translateY(-50%);
pointer-events: none;
font-size: 12px;
color: #666;
}
.ecom-coleccion_tematica .purchase-box .selectors .selector:focus-within {
background-size: 18px 10px;
background-position-x: 95%;
}
.ecom-coleccion_tematica .purchase-box .buy-btn {
width: calc(100% - 32px);
text-transform: uppercase;
}
.ecom-coleccion_tematica .purchase-box .buy-btn:hover,
.ecom-coleccion_tematica .purchase-box .buy-btn:focus,
.ecom-coleccion_tematica .purchase-box .buy-btn:focus-visible {
outline: 2px solid var(--brand-color-2, #6a9bd3);
outline-offset: 2px;
box-shadow: 0 0 0 3px rgba(106, 155, 211, 0.35);
}
.ecom-coleccion_tematica .purchase-box .buy-btn.disabled,
.ecom-coleccion_tematica .purchase-box .buy-btn:disabled,
.ecom-coleccion_tematica .purchase-box .buy-btn[disabled],
.ecom-coleccion_tematica .purchase-box .buy-btn.ecom-btn-loading {
opacity: .6;
pointer-events: none;
}
.ecom-coleccion_tematica .purchase-box .buy-btn.ecom-btn-loading::before,
.ecom-coleccion_tematica .purchase-box .buy-btn.ecom-btn-loading::after {
display: none;
}
.ecom-coleccion_tematica .tabs-section {
max-width: 900px;
//margin: 0 auto 40px;
//padding-top: 3em;
background: #fff;
border-radius: 4px;
overflow: hidden;
}
.ecom-coleccion_tematica .tabs-section .tabs {
display: flex;
border-bottom: 1px solid #ddd;
}
.ecom-coleccion_tematica .tabs-section .tab {
padding: 12px 16px;
margin-right: 8px;
background: transparent;
border: none;
border-radius: 4px 4px 0 0;
cursor: pointer;
font-size: 14px;
color: #222;
transition: background .2s;
}
.ecom-coleccion_tematica .tabs-section .tab:hover {
background: rgba(0, 67, 122, 0.05);
}
.ecom-coleccion_tematica .tabs-section .tab.active {
color: #00437a;
background: #e5f5ff;
border-bottom: 2px solid #00437a;
font-weight: bold;
}
.ecom-coleccion_tematica .tabs-section .tab-content {
margin: 0;
padding: 0;
}
.ecom-coleccion_tematica .tabs-section table {
width: 100%;
border-collapse: collapse;
}
.ecom-coleccion_tematica .tabs-section th,
.ecom-coleccion_tematica .tabs-section td {
padding: 12px 16px;
vertical-align: middle;
}
.ecom-coleccion_tematica .tabs-section th {
width: 180px;
font-weight: 600;
color: #444;
text-align: left;
white-space: nowrap;
}
.ecom-coleccion_tematica .tabs-section td {
font-weight: 400;
color: #222;
line-height: 1.4;
}
.ecom-coleccion_tematica .tabs-section tr:nth-child(even) > * {
background: #f9fafb;
}
.ecom-coleccion_tematica .tabs-section .badge {
display: inline-block;
margin-left: 8px;
padding: 2px 6px;
font-size: 11px;
text-transform: uppercase;
border-radius: 3px;
}
.ecom-coleccion_tematica .tabs-section .alert-label {
vertical-align: top;
text-align: right;
}
.ecom-coleccion_tematica .tabs-section .th-content {
vertical-align: top;
text-align: right;
}
.ecom-coleccion_tematica .tabs-section .alert-content {
vertical-align: bottom;
text-align: left;
}
/* Márgenes para <p> dentro del td */
.ecom-coleccion_tematica .tabs-section .alert-content p {
margin-top: 0;
margin-bottom: 0;
}
/* Márgenes para <p> dentro del td */
.ecom-coleccion_tematica .tabs-section .td-content p {
margin-top: 0;
margin-bottom: 0;
}
/* Márgenes para el <strong> del título */
.ecom-coleccion_tematica .tabs-section .alert-content strong {
display: inline; /* o block si quieres control total del margen */
margin: 0;
}
.ecom-coleccion_tematica .tabs-section .tag-success {
background: #2a7a36;
color: #fff;
}
.ecom-coleccion_tematica .tabs-section .tag-danger {
background: #c00000;
color: #fff;
}
.ecom-coleccion_tematica .tabs-section .tag-blue {
background: #0078c0;
color: #fff;
}
.ecom-coleccion_tematica .info-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 1.5em;
height: 1.5em;
margin-right: 8px;
border: 2px solid #273469;
border-radius: 50%;
font-size: 1em;
font-weight: bold;
}
/* === Media queries === */
@media (max-width: 1024px) {
.ecom-coleccion_tematica .main-container { padding: 20px; margin: 20px auto; }
.ecom-coleccion_tematica .top-section { flex-direction: column; gap: 16px; }
.ecom-coleccion_tematica .purchase-box { flex: none; width: 100%; }
.ecom-coleccion_tematica .product-detail { padding: 16px; }
.ecom-coleccion_tematica .header .logo { max-width: 200px; }
.ecom-coleccion_tematica .title { font-size: 18px; }
.ecom-coleccion_tematica .description { font-size: 1em; }
.ecom-coleccion_tematica .tabs-section { max-width: 100%; padding: 1.5em 1em; }
}
@media (max-width: 768px) {
.ecom-coleccion_tematica body { font-size: 13px; }
.ecom-coleccion_tematica .promo-banner { flex-direction: column; text-align: center; gap: 4px; padding: 8px 10px; }
.ecom-coleccion_tematica .main-container { margin: 16px auto; }
.ecom-coleccion_tematica .top-section { gap: 12px; }
.ecom-coleccion_tematica .header { flex-direction: column; align-items: flex-start; }
.ecom-coleccion_tematica .header .logo { max-width: 200px; }
.ecom-coleccion_tematica .title { font-size: 16px; }
.ecom-coleccion_tematica .subinfo { font-size: 11px; }
.ecom-coleccion_tematica .description { font-size: 0.95em; }
.ecom-coleccion_tematica .extract-btn { padding: 6px 12px; font-size: 13px; }
.ecom-coleccion_tematica .selectors { flex-direction: column; gap: 8px; padding: 12px; }
.ecom-coleccion_tematica .selectors .qty,
.ecom-coleccion_tematica .selectors .selector { width: 100%; }
.ecom-coleccion_tematica .buy-btn { width: 100%; margin-bottom: 16px; }
.ecom-coleccion_tematica .tabs-section .tabs { flex-wrap: wrap; justify-content: center; }
.ecom-coleccion_tematica .tabs-section .tab { flex: 1 1 45%; margin: 4px; padding: 10px 8px; font-size: 13px; text-align: center; }
.ecom-coleccion_tematica .tabs-section th,
.ecom-coleccion_tematica .tabs-section td { padding: 8px 10px; font-size: 12px; }
.ecom-coleccion_tematica .tabs-section th { width: 140px; }
}
.list-thematic-collection-section { margin: 40px auto 35px; }
.list-thematic-collection-section .thematic-collection-container { display: flex; flex-wrap: wrap; gap: 20px 3.5%; padding-right: 0; padding-left: 0; }
.list-thematic-collection-section .item-thematic-collection-adt {
position: relative;
border: 1px solid #e0e0e0;
padding: 28px 14px 16px;
border-radius: 4px;
background: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
justify-content: space-between;
overflow: visible;
min-height: 1px;
box-sizing: border-box;
}
.list-thematic-collection-section .item-thematic-collection-adt .info-standard {
position: static;
display: flex;
flex-direction: column;
flex: 1 1 auto;
}
.list-thematic-collection-section .item-thematic-collection-adt .info-standard a {
display: block;
}
.list-thematic-collection-section .tag-standard {
position: absolute;
background-color: #6a9bd3;
top: -10px;
left: 16px;
padding: 4px 10px;
border-radius: 4px;
color: #fff;
font-weight: bold;
font-size: 12px;
z-index: 5;
}
.list-thematic-collection-section .title-standard {
font-family: SohoGothicPro-Regular;
font-size: 16px;
font-weight: bold;
color: #1a4b94;
margin-top: 0;
margin-bottom: 6px;
line-height: 24px;
}
.list-thematic-collection-section .description-text {
margin-top: 0;
margin-bottom: 12px;
font-family: SohoGothicPro-Regular;
font-size: 13px;
text-align: left;
color: #333;
line-height: 20px;
}
.list-thematic-collection-section .price-container {
display: flex;
flex-direction: column;
text-align: left;
letter-spacing: -0.02em;
margin-top: auto;
}
.list-thematic-collection-section .price-container .price-ae {
font-size: 20px;
font-weight: bold;
margin-bottom: 10px;
color: #1a4b94;
}
.list-thematic-collection-section .standard-button {
border: 0;
outline: 0;
padding: 17px;
width: 100%;
text-align: center;
display: block;
background-color: var(--brand-color-1, #1f57a3);
color: #fff;
text-transform: uppercase;
font-family: SohoStd-Medium;
font-size: 14px;
font-weight: 500;
line-height: 14px;
text-decoration: none;
}
.list-thematic-collection-section .standard-button:hover { cursor: pointer; }
.list-thematic-collection-section .standard-button.disabled,
.list-thematic-collection-section .standard-button:disabled,
.list-thematic-collection-section .standard-button[disabled],
.list-thematic-collection-section .standard-button.ecom-btn-loading {
opacity: .6;
pointer-events: none;
filter: brightness(0.85);
}
.list-thematic-collection-section .thematic-collection-container .item-thematic-collection-adt {
width: calc((100% - (3 * 3.5%)) / 4);
}
.list-thematic-collection-section .view-grid { gap: 20px 3.5%; }
.list-thematic-collection-section .view-grid .item-thematic-collection-adt {
width: calc((100% - (3 * 3.5%)) / 4);
}
@media (max-width:1200px){ .list-thematic-collection-section .thematic-collection-container .item-thematic-collection-adt, .list-thematic-collection-section .view-grid .item-thematic-collection-adt { width: 48%; } }
@media (max-width: 576px) { .list-thematic-collection-section .thematic-collection-container .item-thematic-collection-adt, .list-thematic-collection-section .view-grid .item-thematic-collection-adt { width: 100%; } }
.list-thematic-collection-section .options-standard {
display: flex;
gap: 10px;
margin-bottom: 16px;
border: none;
}
.list-thematic-collection-section .options-standard .select-language,
.list-thematic-collection-section .options-standard .select-format {
background-color: #f5f5f5;
border: 1px solid #d0d0d0;
color: #2d2d2b;
font-size: 13px;
height: 38px;
}
.list-thematic-collection-section .options-standard .select-language:disabled,
.list-thematic-collection-section .options-standard .select-format:disabled {
background-color: #f5f5f5;
color: #2d2d2b;
opacity: 1;
}
.list-thematic-collection-section .options-standard .select-language { flex: 2; }
.list-thematic-collection-section .options-standard .select-format { flex: 1; }
select.form-control,
select.form-control:focus,
select.form-control:focus-visible {
background-image: url(/documents/d/global/ico-chevron-down);
background-size: 18px 10px;
background-position-x: 95%;
background-repeat: no-repeat;
position: relative;
}
.status-standard {
margin-right: 10px;
color: white;
font-size: 10px;
padding: 2px 6px;
border-radius: 3px;
font-weight: bold;
}
.list-thematic-collection-section .status-box {
text-transform: uppercase;
align-items: center;
display: flex;
flex-wrap: wrap;
margin: 0 0 10px;
gap: 4px 0;
}
.list-thematic-collection-section .status-box .status-standard.red-tag {
background-color: var(--ae-450, #D44436);
border: 1px solid var(--ae-450, #D44436);
color: #fff;
}
.list-thematic-collection-section .status-box .status-standard.green-tag {
background-color: #138636;
border: 1px solid #138636;
color: #fff;
}
.list-thematic-collection-section .status-box .status-standard.blue-tag {
background-color: #0078c0;
border: 1px solid #0078c0;
color: #fff;
}
.date-standard { font-size: 12px; color: #666; }
.list-thematic-collection-section .standard-button:hover,
.list-thematic-collection-section .standard-button:focus,
.list-thematic-collection-section .standard-button:focus-visible {
outline: 2px solid var(--brand-color-2, #6a9bd3);
outline-offset: 2px;
box-shadow: 0 0 0 3px rgba(106, 155, 211, 0.35);
}
window.ecomGenericScripts = window.ecomGenericScripts || (function () {
/* =====================================
PROPIEDADES PRIVADAS
===================================== */
const privateProps = window.ecomGenericScripts?.privateProps || {};
/* =====================================
PROPIEDADES PÚBLICAS
===================================== */
const publicProps = {
isDebug: false
};
/* =====================================
FUNCIONES PÚBLICAS
===================================== */
//En functions declaramos la functions publicas
const functions = {};
functions.init = async function () {
await _DOMContentLoaded();
};
/* =====================================
FUNCIONES PRIVADAS
===================================== */
const _loadInit = async function () {
if (publicProps.isDebug) console.log("DOMContentLoaded ecom Generic scripts");
};
const _parsePriceText = function (text) {
if (!text) return 0;
const cleaned = String(text)
.replace(/[^\d,.-]/g, "")
.replace(/\./g, "")
.replace(",", ".");
const n = Number(cleaned);
return Number.isFinite(n) ? n : 0;
};
const _getDetailContext = function (button) {
const wrapper = document.querySelector("#ecom-scripts .data-product-wrapper");
const purchaseBox = button?.closest(".purchase-box") || document;
const langSelect = purchaseBox.querySelector(".select-language");
const formatSelect = purchaseBox.querySelector(".select-format");
const qtyInput = purchaseBox.querySelector(".qty input[type='number']");
const priceNode = purchaseBox.querySelector(".price-header .price");
const titleNode = document.querySelector(".ecom-libro .title, .ecom-norma .title, .ecom-coleccion_tematica .title, .title-book");
return {
wrapper,
purchaseBox,
langSelect,
formatSelect,
qtyInput,
priceNode,
titleNode
};
};
const _getDetailData = async function (productERC, productId, isLibro, isNorma, isColeccionTematica) {
if (!window.ecomGlobalScripts?.functions) return null;
try {
if (isLibro) {
if (productERC) return await window.ecomGlobalScripts.functions.getProductBooksByERC(productERC);
if (productId) return await window.ecomGlobalScripts.functions.getProductBooks(productId);
}
if (isColeccionTematica) {
if (productERC) return await window.ecomGlobalScripts.functions.getProductThematicCollectionsByERC(productERC);
if (productId) return await window.ecomGlobalScripts.functions.getProductThematicCollections(productId);
}
if (isNorma) {
if (productERC) return await window.ecomGlobalScripts.functions.getProductNormasDetailsByERC(productERC);
if (productId) return await window.ecomGlobalScripts.functions.getProductNormasDetails(productId);
}
} catch (e) {}
return null;
};
const _syncDetailBuyButtonState = function (purchaseBox) {
if (!purchaseBox) return;
const btn = purchaseBox.querySelector(".buy-btn");
if (!btn) return;
const langSelect = purchaseBox.querySelector(".select-language");
const formatSelect = purchaseBox.querySelector(".select-format");
const hasSelectors = !!(langSelect || formatSelect);
const hasSelection = !!(langSelect?.value && formatSelect?.value);
if (!hasSelectors) {
if (!btn.disabled) btn.disabled = true;
if (!btn.classList.contains("disabled")) btn.classList.add("disabled");
return;
}
if (btn.disabled === hasSelection) {
btn.disabled = !hasSelection;
}
btn.classList.toggle("disabled", !hasSelection);
};
const _setupQtyPriceMultiplier = function (purchaseBox) {
if (!purchaseBox || purchaseBox.dataset.aeQtyMultBound === "true") return;
purchaseBox.dataset.aeQtyMultBound = "true";
const priceNode = purchaseBox.querySelector(".price-header .price");
const qtyInput = purchaseBox.querySelector(".qty input[type='number']");
if (!priceNode || !qtyInput) return;
const formatter = window.ecomGlobalScripts?.properties?.language?.formatterPrice;
const splitPriceAndCurrency = function (text) {
const m = String(text || "").match(/^(.*?)(\s*[^\d.,\s]+)\s*$/);
if (m) return [m[1].trim(), m[2].trim()];
return [String(text || "").trim(), ""];
};
const formatPrice = function (value, currency) {
const numText = formatter
? formatter.format(value)
: value.toLocaleString("es-ES", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
return currency ? numText + " " + currency : numText;
};
const captureUnit = function () {
const parts = splitPriceAndCurrency(priceNode.textContent);
const parsed = _parsePriceText(parts[0]);
if (parsed > 0) {
purchaseBox.dataset.aeUnitPrice = String(parsed);
purchaseBox.dataset.aeUnitCurrency = parts[1];
}
};
let observer;
const startObserve = function () {
observer.observe(priceNode, { childList: true, characterData: true, subtree: true });
};
const reapply = function () {
const unit = Number(purchaseBox.dataset.aeUnitPrice) || 0;
if (!unit) return;
const qty = Math.max(1, parseInt(qtyInput.value, 10) || 1);
const total = unit * qty;
const currency = purchaseBox.dataset.aeUnitCurrency || "";
if (observer) observer.disconnect();
priceNode.textContent = formatPrice(total, currency);
if (observer) startObserve();
};
// Cuando _renderFragmentPrice (en ECOM-Global_functions/index.js) reescribe
// .price con el precio unitario tras cambiar idioma/formato, recapturamos
// el unitario y reaplicamos la cantidad actual.
observer = new MutationObserver(function () {
captureUnit();
reapply();
});
startObserve();
qtyInput.addEventListener("input", reapply);
qtyInput.addEventListener("change", reapply);
// Captura inicial por si el precio ya estaba renderizado antes de montar el observer.
captureUnit();
reapply();
};
const _bindDetailSelectorState = function (purchaseBox) {
if (!purchaseBox) return;
const sync = function () {
_syncDetailBuyButtonState(purchaseBox);
};
if (purchaseBox.dataset.aeSelectorsBound === "true") {
sync();
return;
}
purchaseBox.dataset.aeSelectorsBound = "true";
purchaseBox.addEventListener("change", function (event) {
if (!event.target?.matches(".select-language, .select-format")) return;
sync();
});
const selectorsRoot = purchaseBox.querySelector(".selector-language_format") || purchaseBox;
const observer = new MutationObserver(function () {
sync();
});
observer.observe(selectorsRoot, {
childList: true,
subtree: true
});
sync();
};
const _attachDetailAddToCart = async function () {
const buttons = document.querySelectorAll(".purchase-box .buy-btn");
if (!buttons.length) return;
buttons.forEach(btn => {
_bindDetailSelectorState(btn.closest(".purchase-box"));
_setupQtyPriceMultiplier(btn.closest(".purchase-box"));
if (btn.dataset.aeBound === "true") return;
btn.dataset.aeBound = "true";
btn.addEventListener("click", (e) => {
e.preventDefault();
const run = async () => {
const ctx = _getDetailContext(btn);
const wrapper = ctx.wrapper;
if (!wrapper) {
window.dispatchEvent(new CustomEvent("cart:error", { detail: { message: "Error al añadir el producto a la cesta" } }));
return;
}
const productId = Number(wrapper.dataset.productId) || null;
const productERC = wrapper.dataset.productErc || "";
const isLibro = wrapper.dataset.productIslibro === "true";
const isNorma = wrapper.dataset.productIsnorma === "true";
const isColeccionTematica = wrapper.dataset.productIscolecciontematica === "true";
const codIdioma = (ctx.langSelect?.value || "").toString();
const codFormato = (ctx.formatSelect?.value || "").toString();
if ((ctx.langSelect || ctx.formatSelect) && (!codIdioma || !codFormato)) {
window.dispatchEvent(new CustomEvent("cart:error", { detail: { message: "Selecciona idioma y formato" } }));
return;
}
const entryType = isLibro ? "Libro" : isColeccionTematica ? "Colección Temática" : "Norma";
const code = productERC || (ctx.titleNode?.textContent || "").trim();
const qty = Math.max(1, parseInt(ctx.qtyInput?.value, 10) || 1);
const name = (ctx.titleNode?.textContent || "").trim();
let priceToSend = 0;
const data = await _getDetailData(productERC, productId, isLibro, isNorma, isColeccionTematica);
if (Array.isArray(data) && data.length && codIdioma && codFormato) {
const entry = data.find(item => {
const langKey = item.codLanguage ?? item.language;
const fmtKey = item.codFormat ?? item.format;
return String(langKey) === codIdioma && String(fmtKey) === codFormato;
});
if (entry) {
const basePrice = Number(entry.price) || 0;
const discount = Number(entry.webDiscount) || 0;
priceToSend = discount > 0 ? Math.floor((basePrice - (basePrice * discount / 100)) * 100) / 100 : basePrice;
}
}
if (!priceToSend && ctx.priceNode) {
priceToSend = _parsePriceText(ctx.priceNode.textContent);
}
await window.ecomGlobalScripts.functions.addToCart({
entryType: entryType,
code: code,
codIdioma: codIdioma,
codFormato: codFormato,
price: priceToSend,
name: name,
amount: qty
});
};
const helper = window.ecomGlobalScripts?.functions?.withButtonSpinner;
if (typeof helper === "function") {
return helper(btn, run, { spinnerClass: "spinner-border spinner-border-sm text-light", mode: "replace" });
}
return run();
});
});
};
const _DOMContentLoaded = async function() {
//Event DOMContentLoaded
if (publicProps.isDebug) console.log("DOMContentLoaded ecom Generic scripts");
if (publicProps.isDebug) console.log("DOMContentLoaded ecom Generic scripts - _loadInit execute");
await _loadInit();
await _attachDetailAddToCart();
};
// ---- Execute Listener DOMContentLoaded ----
document.addEventListener("DOMContentLoaded", async function() {
await _DOMContentLoaded();
});
/* =====================================
API PÚBLICA
===================================== */
return {
properties: publicProps, // properties public
functions: functions // functions public
};
})();
<script id="ecom-norma-referenced">
//TODO: repasar y quitar lo relacionado con selectores y precio.
/*TODO:
-Se llama a la [async function init()] dentro de aqui [ecomNormaReferencedScript]
desde fragment [dxp-ecom-portal/misc/fragments/Collection Tienda/ECOM-Global_functions/index.js] de la siguiente manera:
if (typeof window.ecomNormaReferencedScript?.init === "function") {
await window.ecomNormaReferencedScript.init();
}
*/
window.ecomNormaReferencedScript = (function ($) {
/* === CONFIG === */
let DEBUG = false;
let ROOT_SELECTOR = null;
function log(...args) {
if (DEBUG) console.log("[ecomNorma]", ...args);
}
/* === FUNCIONES PRIVADAS === */
function _euros(v) {
const n = Number(v) || 0;
return n.toLocaleString("es-ES", { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + " €";
}
function _uniq(a) {
return Array.from(new Set(a));
}
function _fill($sel, values, textFn) {
const keep = $sel.val();
$sel.empty();
values.forEach(v => {
$sel.append($("<option>", { value: v, text: textFn ? textFn(v) : v }));
});
if (keep && values.includes(keep)) $sel.val(keep);
else if (values.length) $sel.val(values[0]);
}
function _relabel($sel, textFn) {
$sel.find("option").each(function () {
const v = $(this).attr("value");
$(this).text(textFn ? textFn(v) : v);
});
}
/* === initCarousel — PÚBLICA === */
function initCarousel(force = false) {
const $owl = $(ROOT_SELECTOR + " .standards-container");
// no inicializar si no existe, está oculto o no tiene items
if (!$owl.length || !$owl.hasClass("owl-carousel") || !$owl.is(':visible') || $owl.children().length === 0) {
log("initCarousel abortado: no visible o sin items", $owl);
return;
}
if (force && $owl.hasClass("owl-loaded") && $owl.data("owl.carousel")) {
log("initCarousel Destruyendo Owl Carousel existent:", $owl);
$owl.trigger('destroy.owl.carousel');
// limpiar también owl-hidden para permitir reinicialización
$owl.removeClass('owl-loaded owl-hidden');
// limpiar markup de Owl
$owl.find('.owl-stage-outer').children().unwrap();
}
if ($owl.length && !$owl.hasClass("owl-loaded") && !$owl.data("owl.carousel")) {
$owl.owlCarousel({
nav: true,
navText: [
'<i class="fa-solid fa-chevron-left"></i>',
'<i class="fa-solid fa-chevron-right"></i>'
],
loop: false,
dots: false,
pagination: false,
margin: 25,
autoHeight: false,
responsive: {
0: { items: 1 }, 500: { items: 1 }, 767: { items: 2 }, 1000: { items: 3 }, 1200: { items: 4 }
}
});
$owl.off("initialized.owl.carousel refreshed.owl.carousel resized.owl.carousel translated.owl.carousel")
.on("initialized.owl.carousel refreshed.owl.carousel resized.owl.carousel translated.owl.carousel", adjustHeights);
log("initCarousel executed");
}
}
/* === initCard — PÚBLICA === */
function initCard($card) {
const dataNode = $card.find("script.normas-data")[0];
let data = [];
if (dataNode) {
try { data = JSON.parse(dataNode.textContent); } catch {}
}
const hasData = Array.isArray(data) && data.length > 0;
let langMap = {};
const mapNode = $card.find("script.lang-map")[0];
try { if (mapNode) langMap = JSON.parse(mapNode.textContent); } catch {}
const $lang = $card.find(".select-language");
const $fmt = $card.find(".select-format");
const $price = $card.find(".price-ae");
const toUC = s => (s || "").toString().toUpperCase();
const labelOf = lang => langMap[toUC(lang)] || lang;
const formatsFor = lang => _uniq(data.filter(d => d.language === lang).map(d => d.format));
const languagesFor = fmt => _uniq(data.filter(d => d.format === fmt).map(d => d.language));
const priceOf = (lang, fmt) => {
const m = data.find(d => d.language === lang && d.format === fmt);
return m ? Number(m.price) || 0 : 0;
};
const parsePriceText = (text) => {
if (!text) return 0;
const clean = String(text).replace(/[^\d,.-]/g, "").trim();
if (!clean) return 0;
if (clean.includes(",") && clean.includes(".")) {
const normalized = clean.replace(/\./g, "").replace(",", ".");
return Number(normalized) || 0;
}
const normalized = clean.replace(",", ".");
return Number(normalized) || 0;
};
if (hasData) {
function onLanguageChange() {
const lang = $lang.val();
const fmts = formatsFor(lang);
_fill($fmt, fmts);
$price.text(_euros(priceOf(lang, $fmt.val())));
}
function onFormatChange() {
const fmt = $fmt.val();
const langs = languagesFor(fmt);
_fill($lang, langs, labelOf);
$price.text(_euros(priceOf($lang.val(), fmt)));
}
const l0 = $lang.val();
const f0 = $fmt.val();
if (!data.find(d => d.language === l0 && d.format === f0)) onLanguageChange();
else $price.text(_euros(priceOf(l0, f0)));
_relabel($lang, labelOf);
$lang.off("change.ae").on("change.ae", onLanguageChange);
$fmt.off("change.ae").on("change.ae", onFormatChange);
}
async function onAdd(e) {
e.preventDefault();
var entryType = ($card.data('entrytype') || 'Norma');
var code = ($card.data('code') || '').toString();
var codIdioma = ($card.find('.select-language').val() || '').toString();
var codFormato = ($card.find('.select-format').val() || '').toString();
if (!code) code = ($card.find('.title-standard').text() || '').trim();
await window.ecomGlobalScripts.functions.addToCart({
entryType: entryType,
code: code,
codIdioma: codIdioma,
codFormato: codFormato,
price: Number(priceOf(codIdioma, codFormato)) || 0,
name: ($card.data('title') || '').toString(),
amount: 1
});
}
$card.find(".standard-button").off("click.ae").on("click.ae", function(e){
const btn = this;
const run = () => onAdd(e);
const helper = window.ecomGlobalScripts?.functions?.withButtonSpinner;
if (typeof helper === "function") {
return helper(btn, run, { spinnerClass: "spinner-border spinner-border-sm text-light", mode: "replace" });
}
return run();
});
// Evita que Owl Carousel interprete el click como drag horizontal
$card.find(".standard-button")
.off("pointerdown.owl mousedown.owl touchstart.owl")
.on("pointerdown.owl mousedown.owl touchstart.owl", function(e){
e.stopPropagation();
});
}
/* === adjustHeights — PÚBLICA === */
function adjustHeights() {
if ($(window).width() > 766.98) {
let hT = 0, hD = 0;
$(ROOT_SELECTOR + " .title-standard").css("height","auto").each(function(){ hT=Math.max(hT,$(this).outerHeight()); });
$(ROOT_SELECTOR + " .description-text").css("height","auto").each(function(){ hD=Math.max(hD,$(this).outerHeight()); });
$(ROOT_SELECTOR + " .title-standard").height(hT);
$(ROOT_SELECTOR + " .description-text").height(hD);
} else {
$(ROOT_SELECTOR + " .title-standard, .description-text").css("height","auto");
}
log("adjustHeights executed");
}
/* === init — PÚBLICA === */
async function init() {
// debug externo
DEBUG = window.ecomNormaScripts?.properties?.isDebug === true;
// prefijo para todos los selectores
ROOT_SELECTOR =
window.ecomGlobalScripts?.properties?.querySelectors?.rootSelector ||
window.ecomNormaScripts?.properties?.querySelectors?.rootSelector ||
"#ecom-norma-detail-normas-referenced .standards-section";
log("window.ecomNormaReferencedScript init");
$(ROOT_SELECTOR + " .item-standard").each(function(){ initCard($(this)); });
initCarousel(true);
adjustHeights();
$(window).off("resize.standards").on("resize.standards", adjustHeights);
log("init executed");
}
/* === API pública === */
return { init, initCard, adjustHeights, initCarousel };
})(jQuery);