function () { 'use strict'; var WHEEL_COUNT = 4; var LINE_CLASS = 'productView-price-setOf4'; var STYLE_ID = 'srb-price-for-4-style'; /* ------------------------------------------------------------------ * * Money helpers: parse an already-formatted price ("£1,113.60") and * re-format a number with exactly the same currency tokens. * ------------------------------------------------------------------ */ // Returns null for empty text and for price ranges ("£150.00 - £200.00") function parseMoney(text) { if (!text) { return null; } var s = String(text).replace(/\u00a0/g, ' ').trim(); if (!s || /\d\s*[-\u2013]\s*\d/.test(s)) { return null; } var m = s.match(/^(\D*)(\d[\d.,\s]*\d|\d)(\D*)$/); if (!m) { return null; } var raw = m[2].replace(/\s+/g, ''); var lastDot = raw.lastIndexOf('.'); var lastComma = raw.lastIndexOf(','); var decIndex = -1; if (lastDot > -1 && lastComma > -1) { decIndex = Math.max(lastDot, lastComma); } else if (lastDot > -1) { decIndex = lastDot; } else if (lastComma > -1) { // a lone comma followed by exactly 3 digits is a thousands separator ("1,113") var commas = (raw.match(/,/g) || []).length; var after = raw.length - lastComma - 1; decIndex = (commas === 1 && after !== 3) ? lastComma : -1; } var decSep = decIndex > -1 ? raw.charAt(decIndex) : ''; var groupSep = decSep === ',' ? '.' : ','; var intPart = decIndex > -1 ? raw.slice(0, decIndex) : raw; var decPart = decIndex > -1 ? raw.slice(decIndex + 1) : ''; var value = parseFloat(intPart.split(groupSep).join('') + (decPart ? '.' + decPart : '')); if (isNaN(value)) { return null; } return { value: value, symbol: m[1].trim() || m[3].trim(), symbolLeft: !!m[1].trim(), decSep: decSep || '.', groupSep: groupSep, decPlaces: decPart.length }; } function formatMoney(value, money) { var fixed = Math.abs(value).toFixed(money.decPlaces); var bits = fixed.split('.'); var intPart = bits[0].replace(/\B(?=(\d{3})+(?!\d))/g, money.groupSep); var out = (value < 0 ? '-' : '') + intPart + (bits[1] ? money.decSep + bits[1] : ''); return money.symbolLeft ? money.symbol + out : out + money.symbol; } function setText(el, text) { if (el && el.textContent !== text) { el.textContent = text; } } /* ------------------------------------------------------------------ * * Markup + styles * ------------------------------------------------------------------ */ function ensureStyles() { if (document.getElementById(STYLE_ID)) { return; } var css = '.' + LINE_CLASS + '{clear:both;display:block;margin-top:4px;line-height:1.5;}' + '.' + LINE_CLASS + ' .price,' + '.' + LINE_CLASS + ' .price-label,' + '.' + LINE_CLASS + ' .price-was-label{' + 'font-size:inherit;margin-top:0;text-transform:none;vertical-align:baseline;}'; var style = document.createElement('style'); style.id = STYLE_ID; style.appendChild(document.createTextNode(css)); (document.head || document.documentElement).appendChild(style); } function createLine(scope) { var line = document.createElement('div'); line.className = LINE_CLASS; line.setAttribute('data-set-of-four', ''); line.style.display = 'none'; var label = document.createElement('span'); label.className = 'price-label ' + LINE_CLASS + '-text'; label.appendChild(document.createTextNode('Price for 4 wheels')); var now = document.createElement('span'); now.className = 'price price--main ' + LINE_CLASS + '-value'; now.setAttribute('data-set-of-four-now', ''); var wasWrap = document.createElement('span'); wasWrap.className = 'price-was-label ' + LINE_CLASS + '-text'; wasWrap.setAttribute('data-set-of-four-was-wrap', ''); wasWrap.hidden = true; wasWrap.appendChild(document.createTextNode('\u2014 was ')); var was = document.createElement('span'); was.className = 'price price--non-sale ' + LINE_CLASS + '-value'; was.setAttribute('data-set-of-four-was', ''); wasWrap.appendChild(was); line.appendChild(label); line.appendChild(now); line.appendChild(wasWrap); scope.appendChild(line); return line; } /* ------------------------------------------------------------------ * * Per price-block logic * ------------------------------------------------------------------ */ function init(scope) { if (scope.__setOfFourReady) { return; } scope.__setOfFourReady = true; var line = createLine(scope); var nowEl = line.querySelector('[data-set-of-four-now]'); var wasWrap = line.querySelector('[data-set-of-four-was-wrap]'); var wasEl = line.querySelector('[data-set-of-four-was]'); function update() { if (!line.isConnected) { return; } var nowSrc = scope.querySelector('[data-product-price-with-tax]') || scope.querySelector('[data-product-price-without-tax]'); var wasSrc = scope.querySelector('[data-product-non-sale-price-with-tax]') || scope.querySelector('[data-product-non-sale-price-without-tax]'); var now = nowSrc ? parseMoney(nowSrc.textContent) : null; if (!now || !now.value) { line.style.display = 'none'; return; } setText(nowEl, formatMoney(now.value * WHEEL_COUNT, now)); var was = wasSrc ? parseMoney(wasSrc.textContent) : null; if (was && was.value > now.value) { setText(wasEl, formatMoney(was.value * WHEEL_COUNT, was)); wasWrap.hidden = false; } else { wasWrap.hidden = true; } line.style.display = 'block'; } update(); // keeps the line in step when options change the price if (window.MutationObserver) { new MutationObserver(update).observe(scope, { subtree: true, childList: true, characterData: true }); } } /* ------------------------------------------------------------------ * * Wiring * ------------------------------------------------------------------ */ function scan() { var scopes = document.querySelectorAll('.productView-price'); for (var i = 0; i < scopes.length; i++) { init(scopes[i]); } } function start() { ensureStyles(); scan(); // catch pages swapped in client-side (InstantLoad, Quick View, etc.) if (window.MutationObserver) { new MutationObserver(scan).observe(document.documentElement, { childList: true, subtree: true }); } // belt and braces: the theme's own InstantLoad event if (window.jQuery) { window.jQuery('body').on('loaded.instantload', scan); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', start); } else { start(); } }());