/******/ (() => { // webpackBootstrap let __webpack_exports__ = {}; /*global wc_gzd_unit_price_observer_params, accounting */ ; (function ($, window, document, undefined) { var GermanizedUnitPriceObserver = function ($wrapper) { var self = this; self.params = wc_gzd_unit_price_observer_params; self.$wrapper = $wrapper.closest(self.params.wrapper); self.$form = self.$wrapper.find('.variations_form, .cart').length > 0 ? self.$wrapper.find('.variations_form, .cart') : false; self.isVar = self.$form ? self.$form.hasClass('variations_form') : false; self.$product = self.$wrapper.closest('.product'); self.requests = []; self.observer = {}; self.timeout = false; self.priceData = false; self.productId = 0; if (self.$wrapper.length <= 0) { self.$wrapper = self.$product; } self.replacePrice = self.$wrapper.hasClass('bundled_product') ? false : self.params.replace_price; if ("MutationObserver" in window || "WebKitMutationObserver" in window || "MozMutationObserver" in window) { self.$wrapper.addClass('has-unit-price-observer'); self.initObservers(self); if (self.isVar && self.$form) { self.productId = parseInt(self.$form.find('input[name=product_id]').length > 0 ? self.$form.find('input[name=product_id]').val() : self.$form.data('product_id')); self.variationId = parseInt(self.$form.find('input[name=variation_id]').length > 0 ? self.$form.find('input[name=variation_id]').val() : 0); if (self.$form.find('input[name=variation_id]').length <= 0) { self.variationId = parseInt(self.$form.find('input.variation_id').length > 0 ? self.$form.find('input.variation_id').val() : 0); } self.$form.on('reset_data.unit-price-observer', { GermanizedUnitPriceObserver: self }, self.onResetVariation); self.$form.on('found_variation.unit-price-observer', { GermanizedUnitPriceObserver: self }, self.onFoundVariation); } else { if (self.$form && self.$form.find('*[name=add-to-cart][type=submit]').length > 0) { self.productId = parseInt(self.$form.find('*[name=add-to-cart][type=submit]').val()); } else if (self.$form && self.$form.data('product_id')) { self.productId = parseInt(self.$form.data('product_id')); } else { var classList = self.$product.attr('class').split(/\s+/); /** * Check whether we may find the post/product by a class added by Woo, e.g. post-64 */ $.each(classList, function (index, item) { if ('post-' === item.substring(0, 5)) { var postId = parseInt(item.substring(5).replace(/[^0-9]/g, '')); if (postId > 0) { self.productId = postId; return true; } } }); /** * Do only use the add to cart button attribute as fallback as there might be a lot of * other product/add to cart buttons within a single product main product wrap (e.g. related products). */ if (self.productId <= 0 && 1 === self.$product.find('a.ajax_add_to_cart[data-product_id], a.add_to_cart_button[data-product_id]').length) { self.productId = parseInt(self.$product.find('a.ajax_add_to_cart, a.add_to_cart_button').data('product_id')); } } } if (self.productId <= 0) { self.destroy(self); return false; } if (self.params.refresh_on_load) { /** * Do not refresh variable products on single product pages * as that leads to race conditions with the Woo Core. */ if (self.isVar && self.$form) { self.$form.on('show_variation.unit-price-observer', { GermanizedUnitPriceObserver: self }, function (event) { var self = event.data.GermanizedUnitPriceObserver; self.forceRefresh(self); }); self.$form.on('reset_data.unit-price-observer', { GermanizedUnitPriceObserver: self }, function (event) { var self = event.data.GermanizedUnitPriceObserver; self.forceRefresh(self); }); } else { self.forceRefresh(self); } } } $wrapper.data('unitPriceObserver', self); }; GermanizedUnitPriceObserver.prototype.destroy = function (self) { self = self || this; self.cancelObservers(self); if (self.$form) { self.$form.off('.unit-price-observer'); } self.$wrapper.removeClass('has-unit-price-observer'); }; GermanizedUnitPriceObserver.prototype.getTextWidth = function ($element) { var htmlOrg = $element.html(); var html_calc = '' + htmlOrg + ''; $element.html(html_calc); var textWidth = $element.find('span:first').width(); $element.html(htmlOrg); return textWidth; }; GermanizedUnitPriceObserver.prototype.getPriceNode = function (self, priceSelector, isPrimarySelector, visibleOnly) { isPrimarySelector = typeof isPrimarySelector === 'undefined' ? false : isPrimarySelector; visibleOnly = typeof visibleOnly === 'undefined' ? true : visibleOnly; let visibleSelector = visibleOnly ? ':visible' : ''; var $node = self.$wrapper.find(priceSelector + ':not(.price-unit)' + visibleSelector).not('.variations_form .single_variation .price').first(); if (isPrimarySelector && self.isVar && ($node.length <= 0 || !self.replacePrice)) { $node = self.$wrapper.find('.woocommerce-variation-price span.price:not(.price-unit):last' + visibleSelector); } else if (isPrimarySelector && $node.length <= 0) { $node = self.$wrapper.find('.price:not(.price-unit):last' + visibleSelector); } if ($node.length <= 0 && self.$wrapper.hasClass('wc-block-product')) { $node = self.$wrapper.find('.wc-block-grid__product-price'); } return $node; }; GermanizedUnitPriceObserver.prototype.getObserverNode = function (self, priceSelector, isPrimarySelector) { var $node = self.getPriceNode(self, priceSelector, isPrimarySelector, false); if (isPrimarySelector && self.isVar && !self.replacePrice) { $node = self.$wrapper.find('.single_variation:last'); } return $node; }; GermanizedUnitPriceObserver.prototype.getUnitPriceNode = function (self, $price) { if ($price.length <= 0) { return []; } var $element = []; var isSingleProductBlock = $price.parents('.wp-block-woocommerce-product-price[data-is-descendent-of-single-product-template]').length > 0; var isProductGridBlock = self.$wrapper.hasClass('wc-block-product'); if ('SPAN' === $price[0].tagName) { $element = self.$wrapper.find('.price-unit'); } else { if (isSingleProductBlock) { $element = self.$wrapper.find('.wp-block-woocommerce-gzd-product-unit-price[data-is-descendent-of-single-product-template] .price-unit'); } else if (isProductGridBlock) { $element = self.$wrapper.find('.price-unit:not(.wc-gzd-additional-info-placeholder)'); } else { $element = self.$wrapper.find('.price-unit:not(.wc-gzd-additional-info-placeholder, .wc-gzd-additional-info-loop)'); } } /** * Check whether the unit price is empty - prevent refreshing empty prices. */ if ($element.length > 0) { if ($element.is(':empty') || $element.find('.wc-gzd-additional-info-placeholder').is(':empty')) { $element = []; } } return $element; }; GermanizedUnitPriceObserver.prototype.stopObserver = function (self, priceSelector) { var observer = self.getObserver(self, priceSelector); if (observer) { observer.disconnect(); } }; GermanizedUnitPriceObserver.prototype.startObserver = function (self, priceSelector, isPrimary) { var observer = self.getObserver(self, priceSelector), $node = self.getObserverNode(self, priceSelector, isPrimary); if (observer) { self.stopObserver(self, priceSelector); if ($node.length > 0) { observer.observe($node[0], { attributes: true, childList: true, subtree: true, characterData: true, attributeFilter: ['style', 'data-force-refresh'] }); } return true; } return false; }; GermanizedUnitPriceObserver.prototype.initObservers = function (self) { if (Object.keys(self.observer).length !== 0) { return; } $.each(self.params.price_selector, function (priceSelector, priceArgs) { var isPrimary = priceArgs.hasOwnProperty('is_primary_selector') ? priceArgs['is_primary_selector'] : false, $observerNode = self.getObserverNode(self, priceSelector, isPrimary), currentObserver = false; if ($observerNode.length > 0 && $observerNode.is(':visible')) { // Callback function to execute when mutations are observed var callback = function (mutationsList, observer) { var $priceNode = self.getPriceNode(self, priceSelector, isPrimary); for (let mutation of mutationsList) { let $element = $(mutation.target); if ($element.length > 0) { let $priceElement; if ($element.is(priceSelector)) { $priceElement = $element; } else { $priceElement = $element.parents(priceSelector); } if ($priceElement.length > 0) { $priceNode = $priceElement; } } } /** * Clear the timeout and abort open AJAX requests as * a new mutation has been observed */ if (self.timeout) { clearTimeout(self.timeout); } var $unitPrice = self.getUnitPriceNode(self, $priceNode), hasRefreshed = false; if ($priceNode.length <= 0) { return false; } self.stopObserver(self, priceSelector); if ($unitPrice.length > 0) { self.setUnitPriceLoading(self, $unitPrice); /** * Need to use a tweak here to make sure our variation listener * has already adjusted the variationId (in case necessary). */ self.timeout = setTimeout(function () { self.stopObserver(self, priceSelector); $priceNode = self.getPriceNode(self, priceSelector, isPrimary); // Refresh dom instance as the price element may change during timeout if ($priceNode.length > 0) { var priceData = self.getCurrentPriceData(self, $priceNode, priceArgs['is_total_price'], isPrimary, priceArgs['quantity_selector']); var isVisible = $priceNode.is(':visible'); if (priceData) { if (self.isRefreshingUnitPrice(self.getCurrentProductId(self))) { self.abortRefreshUnitPrice(self.getCurrentProductId(self)); } hasRefreshed = true; self.refreshUnitPrice(self, priceData, priceSelector, isPrimary); } if (!hasRefreshed && $unitPrice.length > 0) { self.unsetUnitPriceLoading(self, $unitPrice); if (!isVisible && isPrimary) { $unitPrice.hide(); } } } self.startObserver(self, priceSelector, isPrimary); }, 500); } }; if ("MutationObserver" in window) { currentObserver = new window.MutationObserver(callback); } else if ("WebKitMutationObserver" in window) { currentObserver = new window.WebKitMutationObserver(callback); } else if ("MozMutationObserver" in window) { currentObserver = new window.MozMutationObserver(callback); } if (currentObserver) { self.observer[priceSelector] = currentObserver; self.startObserver(self, priceSelector, isPrimary); } } }); }; GermanizedUnitPriceObserver.prototype.getObserver = function (self, priceSelector) { if (self.observer.hasOwnProperty(priceSelector)) { return self.observer[priceSelector]; } return false; }; GermanizedUnitPriceObserver.prototype.cancelObservers = function (self) { for (var key in self.observer) { if (self.observer.hasOwnProperty(key)) { self.observer[key].disconnect(); delete self.observer[key]; } } }; /** * Reset all fields. */ GermanizedUnitPriceObserver.prototype.onResetVariation = function (event) { var self = event.data.GermanizedUnitPriceObserver; self.variationId = 0; }; GermanizedUnitPriceObserver.prototype.forceRefresh = function (self) { $.each(self.params.price_selector, function (priceSelector, priceArgs) { var isPrimary = priceArgs.hasOwnProperty('is_primary_selector') ? priceArgs['is_primary_selector'] : false, $price = self.getPriceNode(self, priceSelector, isPrimary), $unitPrice = self.getUnitPriceNode(self, $price); /** * Do only refresh primary price nodes on load. */ if (!isPrimary) { return; } if ($unitPrice.length > 0) { $price[0].setAttribute('data-force-refresh', 'yes'); } }); }; GermanizedUnitPriceObserver.prototype.onFoundVariation = function (event, variation) { var self = event.data.GermanizedUnitPriceObserver; if (variation.hasOwnProperty('variation_id')) { self.variationId = parseInt(variation.variation_id); } self.initObservers(self); }; GermanizedUnitPriceObserver.prototype.getCurrentPriceData = function (self, priceSelector, isTotalPrice, isPrimary, quantitySelector) { quantitySelector = quantitySelector && '' !== quantitySelector ? quantitySelector : self.params.qty_selector; var $price = typeof priceSelector === 'string' || priceSelector instanceof String ? self.getPriceNode(self, priceSelector, isPrimary) : priceSelector; if ($price.length > 0) { // Add a tmp hidden class to detect hidden elements in cloned obj $price.find(':hidden').addClass('wc-gzd-is-hidden'); var $unit_price = self.getUnitPriceNode(self, $price), $priceCloned = $price.clone(); // Remove price suffix from cloned DOM element to prevent finding the wrong (sale) price $priceCloned.find('.woocommerce-price-suffix').remove(); $priceCloned.find('.wc-gzd-is-hidden').remove(); var sale_price = '', $priceInner = $priceCloned.find('.amount:first'), $qty = $(self.params.wrapper + ' ' + quantitySelector + ':first'), qty = 1, is_range = false; if ($qty.length > 0) { qty = parseFloat($qty.val()); } /** * In case the price element does not contain the default Woo price structure * search the whole element. */ if ($priceInner.length <= 0) { if ($priceCloned.find('.price').length > 0) { $priceInner = $priceCloned.find('.price'); } else { $priceInner = $priceCloned; } } var price = self.getRawPrice($priceInner, self.params.price_decimal_sep); /** * Is sale? */ if ($priceCloned.find('.amount').length > 1) { // The second .amount element is the sale price var $sale_price = $($priceCloned.find('.amount')[1]); sale_price = self.getRawPrice($sale_price, self.params.price_decimal_sep); } /** * Is price range, e.g. variable products */ if (sale_price && $priceCloned.find('del').length <= 0) { is_range = true; } $price.find('.wc-gzd-is-hidden').removeClass('wc-gzd-is-hidden'); if ($unit_price.length > 0 && price) { if (isTotalPrice) { price = parseFloat(price) / qty; if (sale_price) { sale_price = parseFloat(sale_price) / qty; } } return { 'price': price, 'unit_price': $unit_price, 'sale_price': sale_price, 'quantity': qty, 'is_range': is_range }; } } return false; }; GermanizedUnitPriceObserver.prototype.getCurrentProductId = function (self) { var productId = self.productId; if (self.variationId > 0) { productId = self.variationId; } return parseInt(productId); }; GermanizedUnitPriceObserver.prototype.getRawPrice = function ($el, decimal_sep) { var price_raw = $el.length > 0 ? $el.text() : '', price = false; try { price = accounting.unformat(price_raw, decimal_sep); } catch (e) { price = false; } return price; }; GermanizedUnitPriceObserver.prototype.setUnitPriceLoading = function (self, $unit_price) { var unitPriceOrg = $unit_price.html(); if (!$unit_price.hasClass('wc-gzd-loading')) { if ($unit_price.find('.wc-gzd-placeholder-loading').length <= 0) { var textWidth = self.getTextWidth($unit_price), textHeight = $unit_price.find('span').length > 0 ? $unit_price.find('span').innerHeight() : $unit_price.height(); /** * @see https://github.com/zalog/placeholder-loading */ $unit_price.html(''); } $unit_price.addClass('wc-gzd-loading'); } $unit_price.data('org-html', unitPriceOrg); return unitPriceOrg; }; GermanizedUnitPriceObserver.prototype.unsetUnitPriceLoading = function (self, $unit_price, newHtml) { newHtml = newHtml || $unit_price.data('org-html'); $unit_price.html(newHtml); if ($unit_price.hasClass('wc-gzd-loading')) { $unit_price.removeClass('wc-gzd-loading'); } if (typeof newHtml === "string" && newHtml.length > 0) { $unit_price.show(); } }; GermanizedUnitPriceObserver.prototype.isRefreshingUnitPrice = function (currentProductId) { return germanized.unit_price_observer_queue.exists(currentProductId); }; GermanizedUnitPriceObserver.prototype.abortRefreshUnitPrice = function (currentProductId) { return germanized.unit_price_observer_queue.abort(currentProductId); }; GermanizedUnitPriceObserver.prototype.refreshUnitPrice = function (self, priceData, priceSelector, isPrimary) { germanized.unit_price_observer_queue.add(self, self.getCurrentProductId(self), priceData, priceSelector, isPrimary); }; /** * Function to call wc_gzd_variation_form on jquery selector. */ $.fn.wc_germanized_unit_price_observer = function () { if ($(this).data('unitPriceObserver')) { $(this).data('unitPriceObserver').destroy(); } new GermanizedUnitPriceObserver(this); return this; }; $(function () { if (typeof wc_gzd_unit_price_observer_params !== 'undefined') { const initObservations = function () { $(wc_gzd_unit_price_observer_params.wrapper).each(function () { if ($(this).is('body')) { return; } $(this).wc_germanized_unit_price_observer(); }); }; initObservations(); /** * Support (async) navigation for product collection block */ if ($('.wp-block-woocommerce-product-collection').length > 0) { let currentObserver = false; const maybeInitObserver = function (mutationsList, observer) { let needsInit = false; for (let mutation of mutationsList) { let $element = $(mutation.target); if ($element.length > 0 && 'woocommerce/product-template' === $element.data('block-name')) { needsInit = true; break; } } if (needsInit) { initObservations(); } }; if ("MutationObserver" in window) { currentObserver = new window.MutationObserver(maybeInitObserver); } else if ("WebKitMutationObserver" in window) { currentObserver = new window.WebKitMutationObserver(maybeInitObserver); } else if ("MozMutationObserver" in window) { currentObserver = new window.MozMutationObserver(maybeInitObserver); } if (currentObserver) { $('.wp-block-woocommerce-product-collection').each(function () { let $node = $(this); currentObserver.observe($node[0], { childList: true, subtree: true }); }); } } } }); })(jQuery, window, document); window.germanized = window.germanized || {}; ((window.germanized = window.germanized || {})["static"] = window.germanized["static"] || {})["unit-price-observer"] = __webpack_exports__; /******/ })() ;