(function ($, window) {
"use strict";
var WooLentorBlocks = {
/**
* [init]
* @return {[void]} Initial Function
*/
init: function () {
this.TabsMenu($(".ht-tab-menus"), ".ht-tab-pane");
this.TabsMenu($(".woolentor-product-video-tabs"), ".video-cus-tab-pane");
if ($("[class*='woolentorblock-'] .ht-product-image-slider").length > 0) {
this.productImageThumbnailsSlider($(".ht-product-image-slider"));
}
this.thumbnailsimagescontroller();
this.ThumbNailsTabs(
".woolentor-thumbanis-image",
".woolentor-advance-product-image-area"
);
},
/**
* [TabsMenu] Active first menu item
*/
TabsMenu: function ($tabmenus, $tabpane) {
$tabmenus.on("click", "a", function (e) {
e.preventDefault();
var $this = $(this),
$target = $this.attr("href");
$this
.addClass("htactive")
.parent()
.siblings()
.children("a")
.removeClass("htactive");
$($tabpane + $target)
.addClass("htactive")
.siblings()
.removeClass("htactive");
// slick refresh
if ($(".slick-slider").length > 0) {
var $id = $this.attr("href");
$($id).find(".slick-slider").slick("refresh");
}
});
},
/**
*
* @param {TabMen area selector} $tabmenu
* @param {Image Area} $area
*/
ThumbNailsTabs: function ($tabmenu, $area) {
$($tabmenu).on("click", "li", function (e) {
e.preventDefault();
var $image = $(this).data("wlimage");
if ($image) {
$($area)
.find(".woocommerce-product-gallery__image .wp-post-image")
.attr("src", $image);
$($area)
.find(".woocommerce-product-gallery__image .wp-post-image")
.attr("srcset", $image);
}
});
},
/**
* Slick Slider
*/
initSlickSlider: function ($block) {
$($block).css("display", "block");
var settings = WooLentorBlocks.sanitizeObject($($block).data("settings"));
if (settings) {
var arrows = settings["arrows"];
var dots = settings["dots"];
var autoplay = settings["autoplay"];
var rtl = settings["rtl"];
var autoplay_speed = parseInt(settings["autoplay_speed"]) || 3000;
var animation_speed = parseInt(settings["animation_speed"]) || 300;
var fade = false;
var pause_on_hover = settings["pause_on_hover"];
var display_columns = parseInt(settings["product_items"]) || 4;
var scroll_columns = parseInt(settings["scroll_columns"]) || 4;
var tablet_width = parseInt(settings["tablet_width"]) || 800;
var tablet_display_columns =
parseInt(settings["tablet_display_columns"]) || 2;
var tablet_scroll_columns =
parseInt(settings["tablet_scroll_columns"]) || 2;
var mobile_width = parseInt(settings["mobile_width"]) || 480;
var mobile_display_columns =
parseInt(settings["mobile_display_columns"]) || 1;
var mobile_scroll_columns =
parseInt(settings["mobile_scroll_columns"]) || 1;
$($block)
.not(".slick-initialized")
.slick({
arrows: arrows,
prevArrow:
'',
nextArrow:
'',
dots: dots,
infinite: true,
autoplay: autoplay,
autoplaySpeed: autoplay_speed,
speed: animation_speed,
fade: fade,
pauseOnHover: pause_on_hover,
slidesToShow: display_columns,
slidesToScroll: scroll_columns,
rtl: rtl,
responsive: [
{
breakpoint: tablet_width,
settings: {
slidesToShow: tablet_display_columns,
slidesToScroll: tablet_scroll_columns,
},
},
{
breakpoint: mobile_width,
settings: {
slidesToShow: mobile_display_columns,
slidesToScroll: mobile_scroll_columns,
},
},
],
});
// A11y fix: Slick adds role="listbox" to .slick-track which is semantically
// incorrect for a carousel and triggers a Lighthouse accessibility failure.
$($block).find(".slick-track").removeAttr("role");
}
},
/**
* Slick Nav For As Slider Initial
* @param {*} $sliderwrap
*/
initSlickNavForAsSlider: function ($sliderwrap) {
$($sliderwrap).find(".woolentor-learg-img").css("display", "block");
$($sliderwrap).find(".woolentor-thumbnails").css("display", "block");
var settings = WooLentorBlocks.sanitizeObject($($sliderwrap).data("settings"));
if (settings) {
$($sliderwrap)
.find(".woolentor-learg-img")
.not(".slick-initialized")
.slick({
slidesToShow: 1,
slidesToScroll: 1,
dots: settings["mainslider"].dots,
arrows: settings["mainslider"].arrows,
fade: false,
asNavFor: ".woolentor-thumbnails",
prevArrow:
'',
nextArrow:
'',
});
$($sliderwrap)
.find(".woolentor-thumbnails")
.not(".slick-initialized")
.slick({
slidesToShow: settings["thumbnailslider"].slider_items,
slidesToScroll: 1,
asNavFor: ".woolentor-learg-img",
centerMode: false,
dots: false,
arrows: settings["thumbnailslider"].arrows,
vertical: settings["thumbnailslider"].slidertype,
focusOnSelect: true,
prevArrow:
'',
nextArrow:
'',
});
// A11y fix: remove semantically incorrect role="listbox" Slick adds to .slick-track.
$($sliderwrap).find(".slick-track").removeAttr("role");
}
},
/**
* Accordion
*/
initAccordion: function ($block) {
var settings = $($block).data("settings");
if ($block.length > 0) {
var $id = $block.attr("id");
new Accordion("#" + $id, {
duration: 500,
showItem: settings.showitem,
elementClass: "htwoolentor-faq-card",
questionClass: "htwoolentor-faq-head",
answerClass: "htwoolentor-faq-body",
});
}
},
/**
* Senitize HTML
*/
sanitizeHTML: function (str) {
if( str ){
return str.replace(/[&<>"']/g, function (c) {
switch (c) {
case '&': return '&';
case '<': return '<';
case '>': return '>';
case '"': return '"';
case "'": return ''';
default: return c;
}
});
}else{
return '';
}
},
/**
* Object Sanitize
*/
sanitizeObject: function (inputObj) {
const sanitizedObj = {};
for (let key in inputObj) {
if (inputObj.hasOwnProperty(key)) {
let value = inputObj[key];
// Sanitize based on the value type
if (typeof value === 'string') {
// Sanitize strings to prevent injection
sanitizedObj[key] = WooLentorBlocks.sanitizeHTML(value);
} else if (typeof value === 'number') {
// Ensure numbers are valid (you could also set limits if needed)
sanitizedObj[key] = Number.isFinite(value) ? value : 0;
} else if (typeof value === 'boolean') {
// Keep boolean values as they are
sanitizedObj[key] = value;
} else {
// Handle other types if needed (e.g., arrays, objects)
sanitizedObj[key] = value;
}
}
}
return sanitizedObj;
},
/*
* Tool Tip
*/
woolentorToolTips: function (element, content) {
if (content == "html") {
var tipText = element.text();
} else {
var tipText = element.attr("title");
}
element.on("mouseover", function () {
if ($(".woolentor-tip").length == 0) {
element.before('' + WooLentorBlocks.sanitizeHTML(tipText) + "");
$(".woolentor-tip").css("transition", "all 0.5s ease 0s");
$(".woolentor-tip").css("margin-left", 0);
}
});
element.on("mouseleave", function () {
$(".woolentor-tip").remove();
});
},
woolentorToolTipHandler: function () {
$("a.woolentor-compare").each(function () {
WooLentorBlocks.woolentorToolTips($(this), "title");
});
$(
".woolentor-cart a.add_to_cart_button,.woolentor-cart a.added_to_cart,.woolentor-cart a.button"
).each(function () {
WooLentorBlocks.woolentorToolTips($(this), "html");
});
},
/*
* Universal product
*/
productImageThumbnailsSlider: function ($slider) {
$slider.slick({
dots: true,
arrows: true,
prevArrow:
'',
nextArrow:
'',
});
// A11y fix: remove semantically incorrect role="listbox" Slick adds to .slick-track.
$slider.find(".slick-track").removeAttr("role");
},
thumbnailsimagescontroller: function () {
this.TabsMenu($(".ht-product-cus-tab-links"), ".ht-product-cus-tab-pane");
this.TabsMenu($(".ht-tab-menus"), ".ht-tab-pane");
// Countdown
$(".ht-product-countdown").each(function () {
var $this = $(this),
finalDate = $(this).data("countdown");
var customlavel = $(this).data("customlavel");
$this.countdown(finalDate, function (event) {
$this.html(
event.strftime(
'
%D
' +
WooLentorBlocks.sanitizeHTML(customlavel.daytxt) +
'
%H
' +
WooLentorBlocks.sanitizeHTML(customlavel.hourtxt) +
'
%M
' +
WooLentorBlocks.sanitizeHTML(customlavel.minutestxt) +
'
%S
' +
WooLentorBlocks.sanitizeHTML(customlavel.secondstxt) +
"
"
)
);
});
});
},
/**
* Single Product Quantity Increase/decrease manager
*/
quantityIncreaseDescrease: function ($area) {
$area
.find("form.cart")
.on(
"click",
"span.wl-quantity-plus, span.wl-quantity-minus",
function () {
const poductType = $area.data("producttype");
// Get current quantity values
if ("grouped" != poductType) {
var qty = $(this).closest("form.cart").find(".qty:visible");
var val = parseFloat(qty.val());
var min_val = 1;
} else {
var qty = $(this)
.closest(".wl-quantity-grouped-cal")
.find(".qty:visible");
var val = !qty.val() ? 0 : parseFloat(qty.val());
var min_val = 0;
}
var max = parseFloat(qty.attr("max"));
var min = parseFloat(qty.attr("min"));
var step = parseFloat(qty.attr("step"));
// Change the value if plus or minus
if ($(this).is(".wl-quantity-plus")) {
if (max && max <= val) {
qty.val(max);
} else {
qty.val(val + step);
}
} else {
if (min && min >= val) {
qty.val(min);
} else if (val > min_val) {
qty.val(val - step);
}
}
}
);
},
CartTableHandler: function () {
// Product Details Slide Toggle
$('body').on("click", '[class*="woolentorblock-"] .woolentor-cart-product-details-toggle', function (e) {
e.preventDefault();
const $target = $(this).data('target');
if($(`[data-id="${$target}"]`).is(':hidden')) {
$(`[data-id="${$target}"]`).slideDown();
} else {
$(`[data-id="${$target}"]`).slideUp();
}
});
},
/**
* Initialize View Switcher for Grid/List Tab Layout
*/
viewSwitcher: function ( $grid, $selector, $style = 'modern' ) {
const $viewButtons = $grid.find( '.woolentor-layout-btn' );
if ( $viewButtons.length === 0 ) {
return; // No view switcher, probably grid or list only mode
}
$viewButtons.on( 'click', function( e ) {
e.preventDefault();
const $this = $(this);
const layout = $this.data('layout');
const $gridContainer = $this.closest('.woolentor-product-grid, .woolentor-filters-enabled').find($selector);
// console.log($gridContainer,$selector, $this);
// Update active button state
$this.siblings().removeClass('woolentor-active');
$this.addClass('woolentor-active');
// Update grid container layout classes
if ($gridContainer.length > 0) {
// Remove existing layout classes from container
$gridContainer.removeClass('woolentor-layout-grid woolentor-layout-list');
// Add new layout class to container
$gridContainer.addClass('woolentor-layout-' + layout);
$gridContainer.attr('data-show-layout', layout);
// Update product card classes
const $productCards = $gridContainer.find('.woolentor-product-card');
$productCards.removeClass('woolentor-grid-card woolentor-list-card');
if (layout === 'grid') {
if($style === 'editorial'){
$productCards.removeClass('woolentor-editorial-list-card');
$productCards.addClass('woolentor-editorial-grid-card');
}else if($style === 'magazine'){
$productCards.removeClass('woolentor-magazine-list-card');
$productCards.addClass('woolentor-magazine-grid-card');
}else{
$productCards.addClass('woolentor-grid-card');
}
} else if (layout === 'list') {
if($style === 'editorial'){
$productCards.removeClass('woolentor-editorial-grid-card');
$productCards.addClass('woolentor-editorial-list-card');
}else if($style === 'magazine'){
$productCards.removeClass('woolentor-magazine-grid-card');
$productCards.addClass('woolentor-magazine-list-card');
}else{
$productCards.addClass('woolentor-list-card');
}
}
}
// Trigger custom event for potential extensions
$grid.trigger( 'woolentor:viewChanged', [ layout ] );
});
},
/**
* Initialize Quantity Selectors (List View)
*/
quantitySelectors: function( $grid ) {
// Plus button
$grid.on( 'click', '.woolentor-qty-plus', function( e ) {
e.preventDefault();
const $button = $( this );
const $input = $button.siblings( '.woolentor-qty-input' );
const currentValue = parseInt( $input.val() ) || 1;
const max = parseInt( $input.attr( 'max' ) ) || 999;
if ( currentValue < max ) {
$input.val( currentValue + 1 ).trigger( 'change' );
}
});
// Minus button
$grid.on( 'click', '.woolentor-qty-minus', function( e ) {
e.preventDefault();
const $button = $( this );
const $input = $button.siblings( '.woolentor-qty-input' );
const currentValue = parseInt( $input.val() ) || 1;
const min = parseInt( $input.attr( 'min' ) ) || 1;
if ( currentValue > min ) {
$input.val( currentValue - 1 ).trigger( 'change' );
}
});
// Sync quantity input with add to cart button
$grid.on( 'change', '.woolentor-qty-input', function() {
const $input = $( this );
const quantity = $input.val();
const $cartButton = $input.closest( '.woolentor-product-actions' ).find( '.woolentor-cart-btn' );
if ( $cartButton.length ) {
$cartButton.attr( 'data-quantity', quantity );
}
});
},
/**
* LoadMore Product Ajax Action handeler
* @param {String} gridArea // gridArea area Selector
*/
loadMore: function( $gridArea ){
let loadMoreButton = $gridArea.find('.woolentor-load-more-btn');
if (loadMoreButton.length > 0) {
loadMoreButton.on('click', function(e) {
e.preventDefault();
const $button = loadMoreButton;
const uniqIdentifire = $button.data('grid-id');
const $loader = $button.siblings('.woolentor-ajax-loader');
const $grid = $('#' + uniqIdentifire);
const currentPage = parseInt($button.data('page'));
const maxPages = parseInt($button.data('max-pages'));
const dataLayout = $grid.attr('data-show-layout');
const loadMoreWrapper = $('.' + uniqIdentifire).find('.woolentor-ajax-enabled');
if (currentPage > maxPages) {
return;
}
$button.hide();
$loader.show();
let settings = loadMoreWrapper.attr( 'data-wl-widget-settings' );
// Prepare AJAX data
const ajaxData = {
action: 'woolentor_load_more_products',
nonce: typeof window?.woolentorLocalizeData !== 'undefined' ? window?.woolentorLocalizeData.security : '',
page: currentPage,
settings: settings,
viewlayout: typeof dataLayout === 'undefined' ? '' : dataLayout
};
// AJAX request to load more products
$.ajax({
url: typeof window?.woolentorLocalizeData !== 'undefined' ? window?.woolentorLocalizeData.ajaxUrl : '',
type: 'POST',
data: ajaxData,
success: function(response) {
if (response.success && response.data.html) {
// Append new products
const $newProducts = $(response.data.html);
$grid.append($newProducts);
// Update page counter
$button.data('page', currentPage+1);
// Show button if more pages available
if (currentPage < maxPages) {
$button.show();
} else {
$button.text($button.data('complete-loadtxt')).prop('disabled', true).show();
}
}
$loader.hide();
},
error: function(xhr, status, error) {
$loader.hide();
$button.show();
console.log("Status:", status, "Error:", error);
}
});
});
}
},
infiniteScroll: function($gridArea){
let selectorBtn = $gridArea.find('.woolentor-infinite-scroll');
let isLoading = false;
const uniqIdentifire = selectorBtn.data('grid-id');
const productLoadWrapper = $('.' + uniqIdentifire).find('.woolentor-ajax-enabled');
const $loader = selectorBtn.find('.woolentor-ajax-loader');
const $grid = $('#' + uniqIdentifire);
const paginationArea = productLoadWrapper.find('.woolentor-pagination-infinite');
function loadMoreOnScroll() {
if (isLoading) return;
// Calculate trigger point based on product grid bottom position
const gridOffset = $grid?.offset()?.top;
const gridHeight = $grid.outerHeight();
const gridBottom = gridOffset + gridHeight;
const scrollTop = $(window).scrollTop();
const windowHeight = $(window).height();
const triggerPoint = gridBottom - windowHeight - 100; // 100px before grid end
if (scrollTop >= triggerPoint) {
const currentPage = parseInt(selectorBtn.data('page'));
const maxPages = parseInt(selectorBtn.data('max-pages'));
if (currentPage > maxPages) {
$(window).off('scroll', loadMoreOnScroll);
return;
}
paginationArea.css('margin-top', '30px');
isLoading = true;
$loader.show();
let settings = productLoadWrapper.attr( 'data-wl-widget-settings' );
const dataLayout = $grid.attr('data-show-layout');
// AJAX request to load more products
$.ajax({
url: typeof woolentor_addons !== 'undefined' ? woolentor_addons.woolentorajaxurl : '',
type: 'POST',
data: {
action: 'woolentor_load_more_products',
nonce: typeof woolentor_addons !== 'undefined' ? woolentor_addons.ajax_nonce : '',
page: currentPage,
settings: settings,
viewlayout: typeof dataLayout === 'undefined' ? '' : dataLayout
},
success: function(response) {
if (response.success && response.data.html) {
// Append new products
const $newProducts = $(response.data.html);
$grid.append($newProducts);
// Update page counter
selectorBtn.data('page', currentPage + 1);
// Check if we've reached the last page
if (currentPage > maxPages) {
$(window).off('scroll', loadMoreOnScroll);
selectorBtn.remove();
}
}
},
complete: function() {
$loader.hide();
isLoading = false;
paginationArea.css('margin-top', '0');
},
error: function() {
$loader.hide();
isLoading = false;
}
});
}
}
// Bind scroll event
$(window).on('scroll', loadMoreOnScroll);
},
// Product Grid Related Script
initProductGridModern: function(){
// Initialize all product grids on the page
$( "[class*='woolentorblock-'] .woolentor-product-grid" ).each( function() {
const $grid = $( this );
if( $grid.hasClass('woolentor-style-editorial') ) {
WooLentorBlocks.viewSwitcher( $grid, '.woolentor-product-grid-editorial', 'editorial' );
}else if( $grid.hasClass('woolentor-style-magazine') ) {
WooLentorBlocks.viewSwitcher( $grid, '.woolentor-product-grid-magazine', 'magazine' );
}else{
WooLentorBlocks.viewSwitcher( $grid, '.woolentor-product-grid-modern' );
}
// Quantity Selectors
WooLentorBlocks.quantitySelectors( $grid );
// LoadMore
WooLentorBlocks.loadMore($grid);
// Infinite Scroll
WooLentorBlocks.infiniteScroll($grid);
});
}
};
$(document).ready(function () {
WooLentorBlocks.init();
WooLentorBlocks.CartTableHandler();
WooLentorBlocks.initProductGridModern();
$("[class*='woolentorblock-'] .product-slider").each(function () {
WooLentorBlocks.initSlickSlider($(this));
});
$("[class*='woolentorblock-'].woolentor-block-slider-navforas").each(
function () {
WooLentorBlocks.initSlickNavForAsSlider($(this));
}
);
$("[class*='woolentorblock-'] .htwoolentor-faq").each(function () {
WooLentorBlocks.initAccordion($(this));
});
$("[class*='woolentorblock-'].woolentor-product-addtocart").each(
function () {
WooLentorBlocks.quantityIncreaseDescrease($(this));
}
);
/**
* Tooltip Manager
*/
WooLentorBlocks.woolentorToolTipHandler();
});
// For Editor Mode Slider
document.addEventListener(
"WoolentorEditorModeSlick",
function (event) {
let editorMainArea = $(".block-editor__container"),
editorIframe = $("iframe.edit-site-visual-editor__editor-canvas"),
productSliderDiv =
editorIframe.length > 0
? editorIframe
.contents()
.find("body.block-editor-iframe__body")
.find(
`.woolentorblock-editor-${event.detail.uniqid} .product-slider`
)
: editorMainArea.find(
`.woolentorblock-editor-${event.detail.uniqid} .product-slider`
);
window.setTimeout(
WooLentorBlocks.initSlickSlider(productSliderDiv),
1000
);
},
false
);
// For Editor Mode Nav For As Slider
document.addEventListener(
"WoolentorEditorModeNavForSlick",
function (event) {
let editorMainArea = $(".block-editor__container"),
editorIframe = $("iframe.edit-site-visual-editor__editor-canvas"),
navForAsSliderDiv =
editorIframe.length > 0
? editorIframe
.contents()
.find("body.block-editor-iframe__body")
.find(
`.woolentorblock-editor-${event.detail.uniqid} .woolentor-block-slider-navforas`
)
: editorMainArea.find(
`.woolentorblock-editor-${event.detail.uniqid} .woolentor-block-slider-navforas`
);
window.setTimeout(
WooLentorBlocks.initSlickNavForAsSlider(navForAsSliderDiv),
1000
);
},
false
);
// Product Grid Modern Editor Script Run
document.addEventListener( "wooLentorProductGridModern", function (event) { WooLentorBlocks.initProductGridModern() }, false );
document.addEventListener( "wooLentorProductGridEditorial", function (event) { WooLentorBlocks.initProductGridModern() }, false );
document.addEventListener( "wooLentorProductGridMagazine", function (event) { WooLentorBlocks.initProductGridModern() }, false );
})(jQuery, window);