1// NEW WC 2024 VERSION 2 3// push data to GTM 4window.dataLayer = window.dataLayer || []; 5window.dataLayer.push({ 6 'fb_pixel_lang': digi_e_vars.lang, // digi_e_vars.pixel_lang 7}); 8 9;(w => { 10 w.addEventListener('DOMContentLoaded', ()=>{ 11 const $ = jQuery; 12 13 // Boolean - enable/disable notice popup before redirecting to lender external website 14 const _notice_popup = true; 15 16 let vv = 37; 17 18 console.log('V-'+vv); 19 20 function spark_v3_find_variation_id_by_lend_amount($form, lend_amount) { 21 if (!$form || !$form.length || typeof lend_amount === 'undefined' || lend_amount === '') { 22 return ''; 23 } 24 25 var raw_variations = $form.attr('data-product_variations'); 26 if (!raw_variations) { 27 return ''; 28 } 29 30 var variations = raw_variations; 31 if (typeof raw_variations === 'string') { 32 try { 33 variations = JSON.parse(raw_variations); 34 } catch (e) { 35 return ''; 36 } 37 } 38 39 if (!Array.isArray(variations)) { 40 return ''; 41 } 42 43 for (var i = 0; i < variations.length; i++) { 44 var v = variations[i]; 45 if (!v || !v.attributes) { 46 continue; 47 } 48 if (v.attributes['attribute_pa_lend-amount'] === lend_amount && v.variation_id) { 49 return String(v.variation_id); 50 } 51 } 52 53 return ''; 54 } 55 56 /** 57 * V3 custom amount option value for lend dropdown 58 * @since 2.4.0 59 * @returns {string} 60 */ 61 function spark_get_v3_custom_amount_option_value() { 62 return 'spark-custom-amount'; 63 } 64 65 /** 66 * Resolve open price min/max from input with language defaults fallback 67 * @since 2.4.0 68 * @param {jQuery} $input 69 * @returns {{min_amount:number,max_amount:number}} 70 */ 71 function spark_get_open_price_range_from_input($input) { 72 var defaults = { 73 min_amount: 36, 74 max_amount: 720 75 }; 76 77 if (typeof digi_e_vars !== 'undefined' && digi_e_vars.lang == 'he') { 78 defaults.min_amount = 50; 79 defaults.max_amount = 2400; 80 } 81 82 if (!$input || !$input.length) { 83 return defaults; 84 } 85 86 var min_attr = parseInt($input.attr('min'), 10); 87 var max_attr = parseInt($input.attr('max'), 10); 88 89 if (!isNaN(min_attr)) { 90 defaults.min_amount = min_attr; 91 } 92 93 if (!isNaN(max_attr)) { 94 defaults.max_amount = max_attr; 95 } 96 97 return defaults; 98 } 99 100 /** 101 * Default labels and values for V3 custom amount UI 102 * @since 2.4.0 103 * @returns {{placeholder_text:string,currency_symbol:string,custom_option_text:string,min_amount:number,max_amount:number}} 104 */ 105 function spark_get_v3_open_price_defaults() { 106 var defaults = { 107 placeholder_text: 'Type Amount', 108 currency_symbol: '$', 109 custom_option_text: 'Other Amount', 110 min_amount: 36, 111 max_amount: 720 112 }; 113 114 if (typeof digi_e_vars !== 'undefined' && digi_e_vars.lang == 'he') { 115 defaults.placeholder_text = '××× ××¡× ×¡×××'; 116 defaults.currency_symbol = 'âª'; 117 defaults.custom_option_text = 'ס××× ××ר'; 118 defaults.min_amount = 50; 119 defaults.max_amount = 2400; 120 } 121 122 return defaults; 123 } 124 125 /** 126 * Build V3 custom amount input markup 127 * @since 2.4.0 128 * @returns {string} 129 */ 130 function spark_get_v3_custom_open_price_input_html() { 131 var defaults = spark_get_v3_open_price_defaults(); 132 var input_html = ''; 133 134 input_html += '<div class="spark-v3-open-price-wrap product-single-open-price">'; 135 input_html += '<div class="open-price-input-wrapper">'; 136 input_html += '<input type="number" name="open_price" class="open-price-input" placeholder="' + defaults.placeholder_text + '" min="' + defaults.min_amount + '" max="' + defaults.max_amount + '" step="1" pattern="[0-9]+" />'; 137 input_html += '<span class="currency-symbol">' + defaults.currency_symbol + '</span>'; 138 input_html += '</div>'; 139 input_html += '<span class="validation-message" style="display:none; color: #e74c3c; font-size: 12px;"></span>'; 140 input_html += '</div>'; 141 142 return input_html; 143 } 144 145 /** 146 * Toggle V3 custom amount input based on dropdown selection 147 * @since 2.4.0 148 * @param {jQuery} $form 149 */ 150 function spark_toggle_v3_custom_amount_input($form) { 151 if (!$form || !$form.length) { 152 return; 153 } 154 155 var custom_option_value = spark_get_v3_custom_amount_option_value(); 156 var $select = $form.find("select[name='attribute_pa_lend-amount'], #pa_lend-amount").first(); 157 var $open_price_wrap = $form.find('.spark-v3-open-price-wrap').first(); 158 159 if (!$select.length || !$open_price_wrap.length) { 160 return; 161 } 162 163 var is_custom_selected = ($select.val() === custom_option_value); 164 var $open_price_input = $open_price_wrap.find('.open-price-input').first(); 165 var $validation_message = $open_price_wrap.find('.validation-message').first(); 166 167 if (is_custom_selected) { 168 $open_price_wrap.addClass('spark-v3-open-price-visible'); 169 170 var $variation_id_input = $form.find("input[name='variation_id']"); 171 if ($variation_id_input.length) { 172 $variation_id_input.val('0'); 173 } 174 175 var $buy_buttons = $form.find('button.nasa-buy-now, button.single_add_to_cart_button'); 176 if ($buy_buttons.length) { 177 $buy_buttons.prop('disabled', false);
178 $buy_buttons.removeClass('disabled wc-variation-selection-needed'); 179 } 180 181 return; 182 } 183 184 $open_price_wrap.removeClass('spark-v3-open-price-visible'); 185 if ($open_price_input.length) { 186 $open_price_input.val(''); 187 $open_price_input.removeClass('error valid'); 188 } 189 190 if ($validation_message.length) { 191 $validation_message.hide().text(''); 192 } 193 } 194 195 function spark_is_quickview_scope(_scope) { 196 if (!_scope || !_scope.length) { 197 return false; 198 } 199 200 return _scope.is('#nasa-quickview-sidebar-content, #nasa-quickview-popup, .product-lightbox') || _scope.closest('#nasa-quickview-sidebar-content, #nasa-quickview-popup, .product-lightbox').length > 0; 201 } 202 203 function spark_ensure_v3_custom_amount_ui($form) { 204 if (!$form || !$form.length) { 205 return; 206 } 207 208 var $select = $form.find("select[name='attribute_pa_lend-amount'], #pa_lend-amount").first(); 209 if (!$select.length) { 210 return; 211 } 212 213 var custom_option_value = spark_get_v3_custom_amount_option_value(); 214 var open_price_defaults = spark_get_v3_open_price_defaults(); 215 216 if (!$select.find('option[value="' + custom_option_value + '"]').length) { 217 $select.append('<option value="' + custom_option_value + '" data-spark-custom-amount="1">' + open_price_defaults.custom_option_text + '</option>'); 218 } 219 220 var $actions = $form.find('.spark-v3-lend-actions').first(); 221 var $btn = $form.find('button.nasa-buy-now, button.single_add_to_cart_button').first(); 222 223 if ($actions.length && $btn.length && !$actions.find('.spark-v3-open-price-wrap').length) { 224 $btn.before(spark_get_v3_custom_open_price_input_html()); 225 } 226 } 227 228 function spark_init_v3_lend_actions(_scope) { 229 var is_v3 = $('body').hasClass('spark-grid-v3'); 230 var is_quickview_scope = spark_is_quickview_scope(_scope); 231 if (!is_v3 && !is_quickview_scope) { 232 return; 233 } 234 235 var $scope = _scope && _scope.length ? _scope : $(document); 236 var $forms = $scope.find('form.cart'); 237 if ($scope.is('form.cart')) { 238 $forms = $forms.add($scope); 239 } 240 $forms = $forms.filter(function() { 241 var $f = $(this); 242 return spark_is_quickview_scope($f) || $f.closest('body.single-product').length > 0; 243 }); 244 245 $forms.each(function() { 246 var $form = $(this); 247 if ($form.data('spark_v3_lend_init') === 1) { 248 if (is_v3 || spark_is_quickview_scope($form)) { 249 spark_ensure_v3_custom_amount_ui($form); 250 spark_toggle_v3_custom_amount_input($form); 251 } 252 return; 253 } 254 255 var $select = $form.find("select[name='attribute_pa_lend-amount'], #pa_lend-amount").first(); 256 if (!$select.length) { 257 return; 258 } 259 260 var $select_row = $select.closest('tr'); 261 var $select_label = $form.find('label[for="pa_lend-amount"], label[for="attribute_pa_lend-amount"]'); 262 263 $form.data('spark_v3_lend_init', 1); 264 $form.addClass('spark-v3-lend-form'); 265 266 var $btn = $form.find('button.nasa-buy-now').first(); 267 if (!$btn.length) { 268 $btn = $form.find('button.single_add_to_cart_button').first(); 269 } 270 if (!$btn.length) { 271 return; 272 } 273 274 var $actions = $form.find('.spark-v3-lend-actions'); 275 if (!$actions.length) { 276 $actions = $('<div class="spark-v3-lend-actions" />'); 277 } 278 279 var $btn_wrap = $btn.closest('.woocommerce-variation-add-to-cart, .single_variation_wrap, .variations_button'); 280 if (!$btn_wrap.length) { 281 $btn_wrap = $form; 282 } 283 284 $btn_wrap.prepend($actions); 285 $select.appendTo($actions); 286 $btn.appendTo($actions); 287 288 if (is_v3 || spark_is_quickview_scope($form)) { 289 spark_ensure_v3_custom_amount_ui($form); 290 } 291 292 var giftcard_url = '/giftcard/'; 293 var giftcard_text = 'Buy as a Giftcard'; 294 if (typeof digi_e_vars !== 'undefined' && digi_e_vars.lang == 'he') { 295 giftcard_url = '/gifcardhe/'; 296 giftcard_text = '×§× × ×××פ××§×ר×'; 297 } 298 299 var $giftcard_btn = $actions.find('.spark-giftcard-inline'); 300 if (!$giftcard_btn.length) { 301 $actions.append('<a href="' + giftcard_url + '" class="button nasa-button giftcard-button spark-giftcard-inline">' + giftcard_text + '</a>'); 302 $giftcard_btn = $actions.find('.spark-giftcard-inline'); 303 } 304 305 // Ensure order: Select -> Lend Now -> GiftCard 306 $giftcard_btn.insertAfter($btn); 307 308 if ($select_row.length) { 309 $select_row.addClass('spark-v3-variation-row-hidden'); 310 } 311 312 if ($select_label.length) { 313 $select_label.addClass('spark-v3-lend-label-hidden'); 314 } 315 316 var $placeholder_opt = $select.find('option[value=""]'); 317 if ($placeholder_opt.length) { 318 $placeholder_opt.remove(); 319 } 320 321 if (!$select.val()) { 322 $select.prop('selectedIndex', 0); 323 } 324 325 setTimeout(function() { 326 $select.trigger('change'); 327 $form.trigger('check_variations'); 328 spark_toggle_v3_custom_amount_input($form); 329 }, 10); 330 }); 331 } 332 333 function spark_v3_mark_reached_icon(_scope) { 334 var $scope = _scope && _scope.length ? _scope : $(document); 335 var $items = $scope.find('.spark-v3-progress-wrap.spark-v3-detailed .spark-v3-detail-item'); 336 if (!$items.length) { 337 return; 338 } 339 340 $items.each(function() { 341 var $item = $(this); 342 var label_text = String($item.find('.spark-v3-detail-label').text() || '').trim(); 343 if (!label_text) { 344 return; 345 } 346 347 var is_reached = (label_text.indexOf('×××ס ×¢× ××') !== -1) || (label_text.toLowerCase().indexOf("i've reached") !== -1); 348 if (!is_reached) { 349 return; 350 } 351 352 var $icon = $item.find('.spark-v3-detail-icon').first(); 353 if ($icon.length) { 354 $icon.addClass('spark-v3-detail-icon-reached'); 355 } 356 }); 357 } 358 359 spark_init_v3_lend_actions($(document)); 360 spark_v3_mark_reached_icon($(document)); 361 362 var _spark_qv_observer = null; 363 364 function spark_bind_quickview_observer() { 365 var _spark_qv_selector = '#nasa-quickview-sidebar-content'; 366 var _spark_qv_node = document.getElementById('nasa-quickview-sidebar-content'); 367 if (!_spark_qv_node) { 368 _spark_qv_selector = '#nasa-quickview-popup'; 369 _spark_qv_node = document.getElementById('nasa-quickview-popup'); 370 } 371 if (!_spark_qv_node) { 372 return false; 373 } 374 375 if (_spark_qv_observer) { 376 return true; 377 } 378 379 var $qv = $(_spark_qv_selector); 380 spark_init_v3_lend_actions($qv); 381 spark_v3_mark_reached_icon($qv); 382 383 _spark_qv_observer = new MutationObserver(function() { 384 var $qv_inner = $(_spark_qv_selector); 385 spark_init_v3_lend_actions($qv_inner); 386 spark_v3_mark_reached_icon($qv_inner); 387 }); 388 _spark_qv_observer.observe(_spark_qv_node, { childList: true, subtree: true });
389 390 return true; 391 } 392 393 // Quickview container is created dynamically; watch for it. 394 if (!spark_bind_quickview_observer() && document.body) { 395 var _spark_body_observer = new MutationObserver(function() { 396 if (spark_bind_quickview_observer()) { 397 _spark_body_observer.disconnect(); 398 } 399 }); 400 _spark_body_observer.observe(document.body, { childList: true, subtree: true }); 401 } 402 403 $('body').on('init_quickview_variations_form nasa_after_quickview', function(e, formLightBox) { 404 var $qv_scope = formLightBox && $(formLightBox).length ? $(formLightBox) : $('#nasa-quickview-sidebar-content, #nasa-quickview-popup'); 405 if (!$qv_scope.length) { 406 return; 407 } 408 409 spark_init_v3_lend_actions($qv_scope); 410 spark_v3_mark_reached_icon($qv_scope); 411 }); 412 413 $(document).on('change', '.spark-v3-lend-form select[name="attribute_pa_lend-amount"], .spark-v3-lend-form #pa_lend-amount', function() { 414 var $form = $(this).closest('form.cart'); 415 spark_toggle_v3_custom_amount_input($form); 416 }); 417 418 //et slider_campaign_id = 0; 419 //let slider_campaign_name = null; 420 421 /** 422 * Single product Page - Add campaign ID to Body & send GA event 423 */ 424 if($("body").hasClass("single-product")) { 425 if(typeof _this_product_campaign_id !== 'undefined') { 426 $("body").attr("data-campaign_id", _this_product_campaign_id); 427 } 428 429 if($("body.single-product FORM BUTTON.nasa-buy-now").length) { 430 $("body.single-product FORM BUTTON.nasa-buy-now").addClass('buy-lender'); 431 } 432 433 // PUSH View GA event 434 if(typeof _this_product_campaign_id !== 'undefined' && typeof _this_product_campaign_name !== 'undefined') { 435 push_ga_view_item_event(_this_product_campaign_id, _this_product_campaign_name); 436 } 437 438 439 } 440 441 // Nasa Buy now BUTTON 442 $('body.single-product').on('click', 'form.cart .nasa-buy-now.buy-lender', function(e) { 443 e.preventDefault(); 444 e.stopImmediatePropagation(); 445 446 var $form = $(this).closest('form.cart'); 447 448 variation_selected = $form.find("INPUT[name=variation_id]").val(); 449 lend_amount = $form.find("#pa_lend-amount option:selected").val(); 450 var custom_option_value = spark_get_v3_custom_amount_option_value(); 451 var is_custom_amount_option = (lend_amount === custom_option_value); 452 453 if (!is_custom_amount_option && (typeof variation_selected === 'undefined' || variation_selected === '0') && typeof lend_amount !== 'undefined' && lend_amount !== '') { 454 var _found_variation_id = spark_v3_find_variation_id_by_lend_amount($form, lend_amount); 455 if (_found_variation_id) { 456 variation_selected = _found_variation_id; 457 $form.find("INPUT[name=variation_id]").val(variation_selected); 458 } 459 } 460 461 // No variation Selected - check for custom open price input 462 if(typeof variation_selected == 'undefined' || variation_selected == '0' || typeof lend_amount == 'undefined' || lend_amount == '' || is_custom_amount_option) { 463 464 // Check if there's a valid custom open price input 465 var customOpenPriceInput = $( this ).closest( "form.cart" ).find(".open-price-input"); 466 var customInputValue = null; 467 var hasValidCustomInput = false; 468 469 if (customOpenPriceInput.length > 0 && customOpenPriceInput.val() !== '') { 470 var open_price_range = spark_get_open_price_range_from_input(customOpenPriceInput); 471 customInputValue = parseInt(customOpenPriceInput.val(), 10); 472 hasValidCustomInput = !isNaN(customInputValue) && customInputValue >= open_price_range.min_amount && customInputValue <= open_price_range.max_amount; 473 } 474 475 if (hasValidCustomInput) { 476 // Use the custom input value as the lend amount 477 lend_amount = 'lend-' + customInputValue; 478 variation_selected = '1'; // Set variation as selected 479 480 // Also set the form data for consistency 481 $( this ).closest( "form.cart" ).find("INPUT[name=variation_id]").val('custom-' + customInputValue); 482 $( this ).closest( "form.cart" ).find("select[name='attribute_pa_lend-amount']").val(lend_amount); 483 484 } else { 485 // No valid variation or custom input 486 _alertTxt = 'Please select some product options before adding this product to your cart.'; 487 488 if(digi_e_vars.lang == 'he') { 489 _alertTxt = '× × ××××ר ס××× ××××××'; 490 } 491 492 alert(_alertTxt); 493 return false; 494 } 495 } 496 497 lend_amount = lend_amount.replace('lend-', ''); 498 499 // Get current raised amount
500 raised = $( this ).closest(".nasa-product-info-wrap").find(".progress-container-v2 .progress-raised-number").text(); 501 raised = raised.replace(/[$,]/g, ""); // removes $ and commas 502 raised = parseInt(raised, 10); 503 504 updated_raised = raised + parseInt(lend_amount, 10); 505 506 //console.log(raised); 507 //console.log(updated_raised); 508 509 // Deprecated Aug 2025 510 //call_ajax_update_campaign_raised(_this_product_campaign_id, updated_raised, parseInt(lend_amount, 10)); 511 512 // variation select - redirect to lender 513 redirect_to_lender(_this_product_campaign_id, lend_amount); 514 //window.location.assign("https://lender.sparkil.org/"+digi_e_vars.lang+"/projects/"+_this_product_campaign_id+"/checkout?amount="+lend_amount+"¤cy="+digi_e_vars.currency+"&anonymouns=true"); 515 516 return false; 517 }); 518 519 // Buy Now on Loop Grid Button 520 $('body.digi-no-checkout').on('click','.add-to-cart-grid.buy-lender', function(e){ 521 if($(this).hasClass('nasa-active')) { 522 e.preventDefault(); 523 e.stopImmediatePropagation(); 524 525 variation_selected = $( this ).attr('data-product_id'); 526 variation_data = $( this ).attr('data-variation'); 527 campaign_id = $( this ).attr('data-campaign_id'); 528 529 if(typeof variation_data == 'undefined' || variation_data == '' || typeof campaign_id == 'undefined' || campaign_id == '') return false; 530 531 variation_data_json = JSON.parse(variation_data); 532 533 lend_amount = variation_data_json["attribute_pa_lend-amount"]; 534 535 lend_amount = lend_amount.replace('lend-', ''); 536 537 // Get current raised amount 538 raised = $( this ).closest(".product-info-wrap").find(".progress-container-v2 .progress-raised-number").text(); 539 raised = raised.replace(/[$,]/g, ""); // removes $ and commas 540 raised = parseInt(raised, 10); 541 542 updated_raised = raised + parseInt(lend_amount, 10); 543 544 // Deprecated Aug 2025 545 //call_ajax_update_campaign_raised(campaign_id, updated_raised, parseInt(lend_amount, 10)); 546 547 //console.log(raised); 548 //console.log(updated_raised); 549 550 // variation select - redirect to lender 551 redirect_to_lender(campaign_id, lend_amount); 552 //window.location.assign("https://lender.sparkil.org/"+digi_e_vars.lang+"/projects/"+campaign_id+"/checkout?amount="+lend_amount+"¤cy="+digi_e_vars.currency+"&anonymouns=true"); 553 554 555 } else { 556 return false; 557 } 558 559 }); 560 561 document.addEventListener('click', function(e) { 562 var btn = e.target && e.target.closest ? e.target.closest('#nasa-quickview-sidebar-content form.cart button.nasa-buy-now, #nasa-quickview-popup form.cart button.nasa-buy-now') : null; 563 if (!btn) { 564 return; 565 } 566 567 if (!$('body').hasClass('digi-no-checkout')) { 568 return; 569 } 570 571 // Capture phase: stop WooCommerce's variation validation alert from firing first. 572 e.preventDefault(); 573 e.stopPropagation(); 574 e.stopImmediatePropagation(); 575 576 var $btn = $(btn); 577 var $form = $btn.closest('form.cart'); 578 579 var variation_selected = $form.find("input[name='variation_id']").val(); 580 var lend_amount = $form.find("select[name='attribute_pa_lend-amount'], #pa_lend-amount").val(); 581 var custom_option_value = spark_get_v3_custom_amount_option_value(); 582 var is_custom_amount_option = (lend_amount === custom_option_value); 583 584 if (!is_custom_amount_option && (typeof variation_selected === 'undefined' || variation_selected === '0') && typeof lend_amount !== 'undefined' && lend_amount !== '') { 585 var _found_variation_id = spark_v3_find_variation_id_by_lend_amount($form, lend_amount); 586 if (_found_variation_id) { 587 variation_selected = _found_variation_id; 588 $form.find("input[name='variation_id']").val(variation_selected); 589 } 590 } 591 if ((typeof lend_amount === 'undefined' || lend_amount === '') && !is_custom_amount_option) { 592 lend_amount = $form.find('.nasa-attr-ux_wrap .selected').attr('data-value'); 593 } 594 595 var campaign_id = $form.find("input[name='spark_campaign_id'], #spark_campaign_id").val(); 596 597 if (typeof lend_amount === 'undefined' || lend_amount === '' || typeof variation_selected === 'undefined' || variation_selected === '0' || is_custom_amount_option) { 598 var customOpenPriceInput = $form.find('.open-price-input').first(); 599 var customInputValue = null; 600 var hasValidCustomInput = false; 601 602 if (customOpenPriceInput.length > 0 && customOpenPriceInput.val() !== '') { 603 var open_price_range = spark_get_open_price_range_from_input(customOpenPriceInput); 604 customInputValue = parseInt(customOpenPriceInput.val(), 10); 605 hasValidCustomInput = !isNaN(customInputValue) && customInputValue >= open_price_range.min_amount && customInputValue <= open_price_range.max_amount; 606 } 607 608 if (hasValidCustomInput) { 609 lend_amount = 'lend-' + customInputValue; 610 variation_selected = '1'; 611 $form.find("input[name='variation_id']").val('custom-' + customInputValue); 612 $form.find("select[name='attribute_pa_lend-amount']").val(lend_amount); 613 } else { 614 var _alertTxt = 'Please select some product options before adding this product to your cart.'; 615 if (digi_e_vars.lang == 'he') { 616 _alertTxt = '× × ××××ר ס××× ××××××'; 617 } 618 alert(_alertTxt); 619 return; 620 } 621 } 622 623 lend_amount = lend_amount.replace('lend-', ''); 624 redirect_to_lender(campaign_id, lend_amount); 625 }, true); 626 627 // Checkout Button Click 628 /* 629 $(document).on('click', ['.button.checkout', '.wp-block-woocommerce-cart .wc-block-cart__submit-button'], function(e) { 630 e.preventDefault(); 631 e.stopImmediatePropagation(); 632 633 // run ajax function 634 $.ajax({
635 type: "post", 636 dataType: "json", 637 url: "/wp-admin/admin-ajax.php", 638 data: { 639 action:'spark_checkout_order', 640 }, 641 success: function(data){ 642 var json = JSON.parse(data); 643 644 if(json.status == 1) { 645 alert('new order success'); 646 return false; 647 } else { 648 // error 649 alert('new order error'); 650 return false; 651 } 652 } 653 }); 654 655 return false; 656 }); 657 */ 658 659 /** 660 * Redirec to lender 661 * @param string campaign_id 662 * @param int lend_amount 663 */ 664 function redirect_to_lender(campaign_id, lend_amount) { 665 popup_en_id = 2587; 666 popup_heb_id = 1862; 667 popup_id = 0; 668 669 debug_redirect = false; 670 671 /* ===== Maintenance Mode ===== */ 672 if (window.__SPARKIL_MAINTENANCE__ === true) { 673 let maintenanceUrl = null; 674 675 if(digi_e_vars.lang == 'he') { 676 maintenanceUrl = 'https://www.sparkil.org/he/%d7%aa%d7%97%d7%96%d7%95%d7%a7%d7%94-200/'; 677 } else { 678 maintenanceUrl = 'https://www.sparkil.org/maintenance-200/'; 679 } 680 681 window.location.assign(maintenanceUrl); 682 return; 683 684 } 685 /* ===== END Maintenance Mode ===== */ 686 687 if(digi_e_vars.lang == 'he') { 688 popup_id = popup_heb_id; 689 } else { 690 popup_id = popup_en_id; 691 } 692 693 /* 694 * Push Tag Manager Evenet 695 */ 696 window.dataLayer = window.dataLayer || []; 697 window.dataLayer.push({ 698 'event': 'popup_to_lender_'+digi_e_vars.lang, 699 'lender_amount' : lend_amount , 700 'lender_currency': digi_e_vars.currency 701 }); 702 703 if(debug_redirect) { 704 console.log("https://lender.sparkil.org/"+digi_e_vars.lang+"/projects/"+campaign_id+"/checkout?amount="+lend_amount+"¤cy="+digi_e_vars.currency+"&anonymouns=true"); 705 } 706 707 if(_notice_popup) { 708 elementorProFrontend.modules.popup.showPopup( { id: popup_id } ); 709 710 // wait X seconds before redirecting 1000 = 1 second 711 setTimeout(() => { 712 window.location.assign("https://lender.sparkil.org/"+digi_e_vars.lang+"/projects/"+campaign_id+"/checkout?amount="+lend_amount+"¤cy="+digi_e_vars.currency+"&anonymouns=true"); 713 }, 4000); 714 715 716 } else{ 717 // redirect 718 window.location.assign("https://lender.sparkil.org/"+digi_e_vars.lang+"/projects/"+campaign_id+"/checkout?amount="+lend_amount+"¤cy="+digi_e_vars.currency+"&anonymouns=true"); 719 } 720 721 722 } 723 724 /** 725 * PUSH View GA Tag Manager Evenet 726 * @param string campaign_id 727 * @param string campaign_name 728 */ 729 function push_ga_view_item_event(campaign_id, campaign_name) { 730 window.dataLayer = window.dataLayer || []; 731 window.dataLayer.push({ 732 'event': 'view_item', 733 'items': [ 734 { 735 item_id: ""+campaign_id+"", 736 item_name: ""+campaign_name+"", 737 quantity: 1 738 } 739 ] 740 }); 741 742 } 743 744 /** 745 * Send to ajax function to update a campaign updatees raised amount - the current raised amount + the new loan 746 * Deprecated Aug 2025 !! 747 */ 748 function call_ajax_update_campaign_raised(campaignId, updatedRaised, loan_amount) { 749 $.ajax({
750 url: digi_e_vars.ajaxurl, // AJAX URL from localized script 751 type: 'POST', 752 dataType: 'json', 753 data: { 754 action : 'spark_campaign_raised_update', // Action name 755 //security : digi_e_vars.nonce, // Nonce for validation 756 campaign_id : campaignId, 757 updated_raised : updatedRaised, 758 loan_value : loan_amount 759 }, 760 success: function (response) { 761 if (response.success) { 762 //console.log('success1'); // Success message 763 } else { 764 //console.log('ajax error'); // Error message 765 } 766 }, 767 error: function (xhr, status, error) { 768 //console.error('AJAX error:', status, error); 769 }, 770 }); 771 772 } 773 774 // Grid Overlay - Porim Advertisment 775 $(".product-item.grid .spark-grid-overlay.porim").on('click',function() { 776 alert('PORIMMMMM'); 777 console.log(digi_e_vars.ad_overlay_url); 778 779 //window.location.assign(digi_e_vars.ad_overlay_url); 780 }); 781 782 783 // On grid page, find an item that has an overlay div and disable the after hover event 784 $('ul.products.grid li.product-warp-item div.product-item ').each(function() { 785 if ($(this).find('div.spark-grid-overlay').length > 0) { 786 //console.log('FFF'); 787 $(this).addClass('disable-after'); 788 } 789 }); 790 791 /** 792 * ------------------------------------------------------------------------------------------- 793 * Open Price Input - NO CART 794 * @since 1.2.0 795 * ------------------------------------------------------------------------------------------- 796 */ 797 798 // Real-time validation for open price inputs (Shop Loop) 799 $(document).on('input', '.product-info-wrap .open-price-input', function() { 800 var input = $(this); 801 var value = parseInt(input.val()); 802 var messageSpan = input.closest('.product-item-loop-open-price').find('.validation-message'); 803 804 var min_amount = input.attr('min'); 805 var max_amount = input.attr('max'); 806 807 808 // Clear previous validation state 809 input.removeClass('error valid'); 810 messageSpan.hide().text(''); 811 812 if (input.val() === '') { 813 // Reset button to "Select options" when input is empty 814 resetButtonToSelectOptions(input); 815 return; 816 } 817 818 // set lanuage texts 819 let please_enter_numbers_only = spark_open_price_events_texts('please_enter_numbers_only', min_amount, max_amount); 820 let minimum_amount_err_txt = spark_open_price_events_texts('minimum_amount_err_txt', min_amount, max_amount); 821 let maximum_amount_err_txt = spark_open_price_events_texts('maximum_amount_err_txt', min_amount, max_amount); 822 let add_to_cart_button_text = spark_open_price_events_texts('add_to_cart_button_text', min_amount, max_amount); 823 824 // Check if value is a number 825 if (isNaN(value) || !/^[0-9]+$/.test(input.val())) { 826 input.addClass('error'); 827 messageSpan.text(please_enter_numbers_only).show(); 828 829 // Reset button text to "Select options" when input is invalid 830 resetButtonToSelectOptions(input); 831 return; 832 } 833 834 // Check min/max range 835 if (value < min_amount) { 836 input.addClass('error'); 837 messageSpan.text(minimum_amount_err_txt).show(); 838 839 // Reset button text to "Select options" when input is invali
839d 840 resetButtonToSelectOptions(input); 841 } else if (value > max_amount) { 842 input.addClass('error'); 843 messageSpan.text(maximum_amount_err_txt).show(); 844 845 // Reset button text to "Select options" when input is invalid 846 resetButtonToSelectOptions(input); 847 } else { 848 input.addClass('valid'); 849 messageSpan.hide(); 850 851 // Deactivate NASA attribute UX items when valid number is entered 852 var productInfoWrap = input.closest('.product-info-wrap'); 853 if (productInfoWrap.length > 0) { 854 // Find the NASA variable wrapper within the product info 855 var nasaVariableWrap = productInfoWrap.find('.nasa-product-content-variable-warp'); 856 if (nasaVariableWrap.length > 0) { 857 // Find all matching a tags within the lend amount wrap child 858 var targetLinks = nasaVariableWrap.find('.nasa-product-content-lend-amount-wrap-child a.nasa-attr-ux-item.nasa-attr-ux-nasa_label'); 859 860 targetLinks.each(function() { 861 var linkElement = $(this); 862 863 // Remove nasa-active class if it exists 864 if (linkElement.hasClass('nasa-active')) { 865 linkElement.removeClass('nasa-active'); 866 } 867 868 // Set data-act attribute to 0 869 linkElement.attr('data-act', '0'); 870 }); 871 872 // Remove data-variation attribute from add-to-cart button when variations are deselected 873 var addWrap = productInfoWrap.find('.add-to-cart-grid'); 874 if (addWrap.length > 0) { 875 addWrap.removeAttr('data-variation'); 876 addWrap.removeAttr('data-variation_id'); 877 addWrap.addClass('product_type_variable'); 878 addWrap.removeClass('product_type_variation'); 879 } 880 } 881 882 // Update button text to "Add to cart" and activate button 883 // Following Elessi theme's logic from nasa.functions.js 884 var addWrap = productInfoWrap.find('.add-to-cart-grid'); 885 886 if (addWrap.hasClass('nasa-variable-add-to-cart-in-grid') && !$('body').hasClass('nasa-ywraq-hide-add-to-cart')) { 887 // Get the "Add to cart" text from theme localization or fallback 888 var addText = $('input[name="add_to_cart_text"]').val() || add_to_cart_button_text; 889 890 // Update button text and attributes 891 addWrap.find('.add_to_cart_text').html(addText); 892 addWrap.attr('title', addText); 893 894 // Update tooltip if present 895 if (addWrap.hasClass('nasa-tip')) { 896 addWrap.attr('data-tip', addText); 897 898 if (addWrap.find('.nasa-tip-content').length) { 899 addWrap.find('.nasa-tip-content').html(addText); 900 } 901 } 902 903 // Activate the button by adding nasa-active class 904 if (!addWrap.hasClass('nasa-active')) { 905 addWrap.addClass('nasa-active'); 906 } 907 } 908 } 909 } 910 }); 911jQuery(document).ready(function($) { 912 // ×××× × ×ר×ת ×-document (Event Delegation) שת×פסת ×ת ×××××¦× ×ª××× 913 $(document).on('click', '.e-n-tab-title, .e-n-tab-title *, [role="tab"]', function() { 914 915 // ××××§× ×§×¡×§××ת ×××× ××× ×× (××××ת ס××× ××× ××צ×× ×©× ×××× ××ר)
916 [100, 300, 600].forEach(function(delay) { 917 setTimeout(function() { 918 // 1. ×ר××ר resize ×××× ××פ××¤× 919 window.dispatchEvent(new Event('resize')); 920 921 // 2. ××ר×ת Slick Slider ×ת×× ×××× ×פע×× ×××©× ××××ת ×××ש 922 $('.slick-slider:visible').each(function() { 923 if ($(this).hasClass('slick-initialized')) { 924 $(this).slick('setPosition'); 925 } 926 }); 927 }, delay); 928 }); 929 }); 930}); 931 // Real-time validation for open price inputs (Single Product Page) 932 $(document).on('input', '.variations_form .open-price-input', function() { 933 var input = $(this); 934 var value = parseInt(input.val()); 935 var messageSpan = input.closest('.product-single-open-price, .product-item-loop-open-price').find('.validation-message'); 936 var variationsForm = input.closest('.variations_form'); 937 var is_v3_custom_input = input.closest('.spark-v3-open-price-wrap').length > 0; 938 939 var min_amount = input.attr('min'); 940 var max_amount = input.attr('max'); 941 942 // Clear previous validation state 943 input.removeClass('error valid'); 944 messageSpan.hide().text(''); 945 946 if (input.val() === '') { 947 // Clear any validation when input is empty 948 return; 949 } 950 951 // set lanuage texts 952 let please_enter_numbers_only = spark_open_price_events_texts('please_enter_numbers_only', min_amount, max_amount); 953 let minimum_amount_err_txt = spark_open_price_events_texts('minimum_amount_err_txt', min_amount, max_amount); 954 let maximum_amount_err_txt = spark_open_price_events_texts('maximum_amount_err_txt', min_amount, max_amount); 955 let add_to_cart_button_text = spark_open_price_events_texts('add_to_cart_button_text', min_amount, max_amount); 956 957 // Check if value is a number 958 if (isNaN(value) || !/^[0-9]+$/.test(input.val())) { 959 input.addClass('error'); 960 messageSpan.text(please_enter_numbers_only).show(); 961 return; 962 } 963 964 // Check min/max range 965 if (value < min_amount) { 966 input.addClass('error'); 967 messageSpan.text(minimum_amount_err_txt).show(); 968 } else if (value > max_amount) { 969 input.addClass('error'); 970 messageSpan.text(maximum_amount_err_txt).show(); 971 } else { 972 input.addClass('valid'); 973 messageSpan.hide(); 974 975 if (is_v3_custom_input && variationsForm.length > 0) { 976 var custom_option_value = spark_get_v3_custom_amount_option_value(); 977 var v3_attribute_select = variationsForm.find("select[name='attribute_pa_lend-amount'], #pa_lend-amount").first(); 978 if (v3_attribute_select.length && v3_attribute_select.val() !== custom_option_value) { 979 v3_attribute_select.val(custom_option_value); 980 } 981 982 var v3_add_to_cart_button = variationsForm.find('.single_add_to_cart_button, .nasa-buy-now'); 983 if (v3_add_to_cart_button.length > 0) { 984 v3_add_to_cart_button.prop('disabled', false); 985 v3_add_to_cart_button.removeClass('disabled wc-variation-selection-needed'); 986 } 987 988 return; 989 } 990 991 // Deactivate NASA attribute UX items when valid number is entered 992 if (variationsForm.length > 0) { 993 // Find all selected variation items and deselect them (single product page uses 'selected' class) 994 var selectedItems = variationsForm.find('.nasa-attr-ux.selected'); 995 selectedItems.each(function() { 996 $(this).removeClass('selected').attr('data-act', '0'); 997 }); 998 999 // Also check for nasa-active class (fallback) 1000 var activeItems = variationsForm.find('.nasa-attr-ux.nasa-active'); 1001 activeItems.each(function() { 1002 $(this).removeClass('nasa-active').attr('data-act', '0'); 1003 }); 1004 1005 // Clear the variation_id hidden input 1006 var variationIdInput = variationsForm.find('input[name="variation_id"]'); 1007 if (variationIdInput.length > 0) { 1008 variationIdInput.val('0'); 1009 } 1010 1011 // Clear the attribute select value 1012 var attributeSelect = variationsForm.find('select[name="attribute_pa_lend-amount"]'); 1013 if (attributeSelect.length > 0) { 1014 attributeSelect.val(''); 1015 } 1016 1017 // Reset the add-to-cart button to disabled state 1018 var addToCartButton = variationsForm.find('.single_add_to_cart_button'); 1019 if (addToCartButton.length > 0) {
1020 addToCartButton.addClass('disabled wc-variation-selection-needed'); 1021 addToCartButton.removeClass('alt'); 1022 } 1023 1024 // Trigger change event to notify WooCommerce that variation was cleared 1025 if (attributeSelect.length > 0) { 1026 attributeSelect.trigger('change'); 1027 } 1028 } 1029 } 1030 }); 1031 1032 /** 1033 * Handle focus out event to reset button when user leaves input 1034 * @since 1.2.0 1035 */ 1036 $(document).on('focusout', '.open-price-input', function() { 1037 var input = $(this); 1038 var value = parseInt(input.val()); 1039 1040 if (input.closest('.spark-v3-open-price-wrap').length > 0) { 1041 return; 1042 } 1043 1044 var min_amount = input.attr('min'); 1045 var max_amount = input.attr('max'); 1046 1047 // If input is empty or invalid, reset button to "Select options" 1048 if (input.val() === '' || isNaN(value) || value < min_amount || value > max_amount) { 1049 resetButtonToSelectOptions(input); 1050 } 1051 }); 1052 1053 // Prevent non-numeric input 1054 $(document).on('keypress', '.open-price-input', function(e) { 1055 // Allow backspace, delete, tab, escape, enter 1056 if ($.inArray(e.keyCode, [46, 8, 9, 27, 13]) !== -1 || 1057 // Allow Ctrl+A, Ctrl+C, Ctrl+V, Ctrl+X 1058 (e.keyCode === 65 && e.ctrlKey === true) || 1059 (e.keyCode === 67 && e.ctrlKey === true) || 1060 (e.keyCode === 86 && e.ctrlKey === true) || 1061 (e.keyCode === 88 && e.ctrlKey === true)) { 1062 return; 1063 } 1064 // Ensure that it is a number and stop the keypress 1065 if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) { 1066 e.preventDefault(); 1067 } 1068 }); 1069 1070 /** 1071 * Clear custom input when variation label is selected (Shop Loop) 1072 * @since 1.2.0 1073 */ 1074 $(document).on('click', '.product-info-wrap .nasa-attr-ux-item', function() { 1075 var clickedVariation = $(this); 1076 1077 // Use setTimeout to ensure the nasa-active class has been added by the theme's JS 1078 setTimeout(function() { 1079 // Check if this variation item now has the nasa-active class 1080 if (clickedVariation.hasClass('nasa-active')) { 1081 // Find the product container 1082 var productInfoWrap = clickedVariation.closest('.product-info-wrap'); 1083 1084 // Find the custom open price input within this product 1085 var openPriceInput = productInfoWrap.find('.open-price-input'); 1086 1087 if (openPriceInput.length > 0 && openPriceInput.val() !== '') { 1088 // Clear the input value 1089 openPriceInput.val(''); 1090 1091 // Remove any validation classes 1092 openPriceInput.removeClass('error valid'); 1093 1094 // Hide validation message 1095 var messageSpan = productInfoWrap.find('.validation-message'); 1096 messageSpan.hide().text(''); 1097 1098 // Optional: Add a subtle visual feedback that input was cleared 1099 openPriceInput.addClass('cleared'); 1100 setTimeout(function() { 1101 openPriceInput.removeClass('cleared'); 1102 }, 300); 1103 } 1104 } 1105 }, 50); // Small delay to ensure theme's JS has processed the click 1106 }); 1107 1108 /** 1109 * Clear custom input when variation label is selected (Single Product Page) 1110 * @since 1.3.0 1111 */ 1112 $(document).on('click', '.variations_form .nasa-attr-ux', function() { 1113 var clickedVariation = $(this); 1114 1115 // Use setTimeout to ensure the nasa-active class has been added by the theme's JS 1116 setTimeout(function() { 1117 // Check if this variation item now has the nasa-active class 1118 if (clickedVariation.hasClass('nasa-active')) { 1119 // Find the variations form container 1120 var variationsForm = clickedVariation.closest('.variations_form'); 1121 1122 // Find the custom open price input within this form 1123 var openPriceInput = variationsForm.find('.open-price-input'); 1124 1125 if (openPriceInput.length > 0 && openPriceInput.val() !== '') { 1126 // Clear the input value 1127 openPriceInput.val(''); 1128 1129 // Remove any validation classes 1130 openPriceInput.removeClass('error valid'); 1131 1132 // Hide validation message 1133 var messageSpan = variationsForm.find('.validation-message'); 1134 messageSpan.hide().text(''); 1135 1136 // Optional: Add a subtle visual feedback that input was cleared 1137 openPriceInput.addClass('cleared'); 1138 setTimeout(function() { 1139 openPriceInput.removeClass('cleared'); 1140 }, 300); 1141 } 1142 } 1143 }, 50); // Small delay to ensure theme's JS has processed the click 1144 }); 1145 1146 /** 1147 * Intercept add-to-cart button mousedown to handle custom input validation 1148 * and set data-variation attributes before theme handlers run 1149 * @since 1.2.0 1150 */
1151 $(document).on('mousedown', '.add-to-cart-grid', function(e) { 1152 var button = $(this); 1153 var productInfoWrap = button.closest('.product-info-wrap'); 1154 var openPriceInput = productInfoWrap.find('.open-price-input'); 1155 var activeVariations = productInfoWrap.find('.nasa-attr-ux-item.nasa-active'); 1156 var attributeSelect = productInfoWrap.find("select[name='attribute_pa_lend-amount'], #pa_lend-amount"); 1157 var hasValidDropdown = false; 1158 var hasValidInput = false; 1159 var inputValue = null; 1160 1161 var min_amount = openPriceInput.attr('min'); 1162 var max_amount = openPriceInput.attr('max'); 1163 1164 // Check if we have a valid custom input 1165 if (openPriceInput.length > 0 && openPriceInput.val() !== '') { 1166 inputValue = parseInt(openPriceInput.val()); 1167 hasValidInput = !isNaN(inputValue) && inputValue >= min_amount && inputValue <= max_amount; 1168 } 1169 1170 if (attributeSelect.length > 0) { 1171 var dd_val = attributeSelect.val(); 1172 hasValidDropdown = (typeof dd_val !== 'undefined' && dd_val !== ''); 1173 } 1174 1175 // If no variation selected and no valid input, show tooltip and prevent action 1176 if (activeVariations.length === 0 && !hasValidInput && !hasValidDropdown) { 1177 e.preventDefault(); 1178 e.stopPropagation(); 1179 e.stopImmediatePropagation(); 1180 1181 // Store original href and temporarily disable it 1182 var originalHref = button.attr('href'); 1183 if (originalHref) { 1184 button.attr('data-original-href', originalHref); 1185 button.removeAttr('href'); 1186 } 1187 1188 // Show tooltip with validation message 1189 let select_options_missimg_notification = spark_open_price_events_texts('select_options_missimg_notification', min_amount, max_amount); 1190 1191 var tooltip = $('<div class="open-price-tooltip">' + select_options_missimg_notification + '</div>'); 1192 var buttonOffset = button.offset(); 1193 var buttonHeight = button.outerHeight(); 1194 1195 tooltip.css({ 1196 'position': 'absolute', 1197 'top': (buttonOffset.top - buttonHeight + 5) + 'px', 1198 'left': buttonOffset.left + 'px', 1199 'z-index': 9999 1200 }).appendTo('body').fadeIn(200); 1201 1202 // Add shake animation to button 1203 button.addClass('shake-animation'); 1204 1205 // Remove tooltip, animation, and restore href after 3 seconds 1206 setTimeout(function() { 1207 tooltip.fadeOut(200, function() { 1208 tooltip.remove(); 1209 }); 1210 button.removeClass('shake-animation'); 1211 1212 // Restore original href 1213 var storedHref = button.attr('data-original-href'); 1214 if (storedHref) { 1215 button.attr('href', storedHref); 1216 button.removeAttr('data-original-href'); 1217 } 1218 }, 3000); 1219 1220 return false; 1221 } 1222 1223 // If we have valid input but no preset variation, set up variation data 1224 if (hasValidInput && activeVariations.length === 0) { 1225 // Remove any existing data-variation to avoid conflicts 1226 button.removeAttr('data-variation'); 1227 button.removeAttr('data-variation_id'); 1228 1229 // Set new variation data for custom input 1230 var variationData = { 1231 'attribute_pa_lend-amount': 'lend-' + inputValue 1232 }; 1233 var variationJson = JSON.stringify(variationData); 1234 button.attr('data-variation', variationJson); 1235 button.attr('data-variation_id', 'custom-' + inputValue); 1236 1237 // Also try setting the href to include variation data (fallback approach) 1238 var currentHref = button.attr('href'); 1239 if (currentHref && !currentHref.includes('add-to-cart=')) { 1240 var separator = currentHref.includes('?') ? '&' : '?'; 1241 var newHref = currentHref + separator + 'add-to-cart=' + button.attr('data-product_id') + '&variation_id=custom-' + inputValue + '&attribute_pa_lend-amount=lend-' + inputValue; 1242 button.attr('href', newHref); 1243 } 1244 } 1245 1246 // Let the original theme handler continue 1247 return true; 1248 }); 1249 1250 /** 1251 * Additional click handler to prevent link navigation when validation fails (Shop Loop) 1252 * @since 1.2.0 1253 * This prevents the href redirect when validation shows tooltip 1254 */
1255 $(document).on('click', '.add-to-cart-grid', function(e) { 1256 var button = $(this); 1257 var productInfoWrap = button.closest('.product-info-wrap'); 1258 var openPriceInput = productInfoWrap.find('.open-price-input'); 1259 1260 var min_amount = openPriceInput.attr('min'); 1261 var max_amount = openPriceInput.attr('max'); 1262 1263 // Check current state (same logic as mousedown) 1264 var activeVariations = productInfoWrap.find('.nasa-attr-ux-item.nasa-active'); 1265 var attributeSelect = productInfoWrap.find("select[name='attribute_pa_lend-amount'], #pa_lend-amount"); 1266 var hasValidDropdown = false; 1267 var hasValidInput = false; 1268 1269 if (openPriceInput.length > 0 && openPriceInput.val() !== '') { 1270 var inputValue = parseInt(openPriceInput.val()); 1271 hasValidInput = !isNaN(inputValue) && inputValue >= min_amount && inputValue <= max_amount; 1272 } 1273 1274 if (attributeSelect.length > 0) { 1275 var dd_val = attributeSelect.val(); 1276 hasValidDropdown = (typeof dd_val !== 'undefined' && dd_val !== ''); 1277 } 1278 1279 // If validation failed (no selection), prevent the link navigation aggressively 1280 if (activeVariations.length === 0 && !hasValidInput && !hasValidDropdown) { 1281 e.preventDefault(); 1282 e.stopPropagation(); 1283 e.stopImmediatePropagation(); 1284 1285 // Also check if href was temporarily removed and don't restore it yet 1286 if (button.attr('data-original-href') && !button.attr('href')) { 1287 // Keep href disabled until timeout completes 1288 return false; 1289 } 1290 1291 return false; 1292 } 1293 }); 1294 1295 /** 1296 * Single Product Page: Handle add-to-cart button validation and custom input 1297 * @since 1.2.0 1298 */ 1299 $(document).on('click', '.single_add_to_cart_button, .nasa-buy-now', function(e) { 1300 var button = $(this); 1301 var variationsForm = button.closest('.variations_form'); 1302 var openPriceInput = variationsForm.find('.open-price-input'); 1303 var activeVariations = variationsForm.find('.nasa-attr-ux.nasa-active'); 1304 var attributeSelect = variationsForm.find("select[name='attribute_pa_lend-amount'], #pa_lend-amount"); 1305 var hasValidDropdown = false; 1306 var hasValidInput = false; 1307 var inputValue = null; 1308 1309 var min_amount = openPriceInput.attr('min'); 1310 var max_amount = openPriceInput.attr('max'); 1311 1312 // Check if we have a valid custom input 1313 if (openPriceInput.length > 0 && openPriceInput.val() !== '') { 1314 inputValue = parseInt(openPriceInput.val()); 1315 hasValidInput = !isNaN(inputValue) && inputValue >= min_amount && inputValue <= max_amount; 1316 } 1317 1318 // If no variation selected and no valid input, show tooltip and prevent action 1319 if (activeVariations.length === 0 && !hasValidInput) { 1320 e.preventDefault(); 1321 e.stopPropagation(); 1322 e.stopImmediatePropagation(); 1323 1324 // Show tooltip with validation message 1325 let select_options_missimg_notification = spark_open_price_events_texts('select_options_missimg_notification', min_amount, max_amount); 1326 var tooltip = $('<div class="open-price-tooltip">' + select_options_missimg_notification + '</div>'); 1327 var buttonOffset = button.offset(); 1328 var buttonHeight = button.outerHeight(); 1329 1330 tooltip.css({ 1331 'position': 'absolute', 1332 'top': (buttonOffset.top - buttonHeight + 5) + 'px', 1333 'left': buttonOffset.left + 'px', 1334 'z-index': 9999 1335 }).appendTo('body').fadeIn(200); 1336 1337 // Add shake animation to button 1338 button.addClass('shake-animation'); 1339 1340 // Remove tooltip and animation after 3 seconds 1341 setTimeout(function() { 1342 tooltip.fadeOut(200, function() { 1343 tooltip.remove(); 1344 }); 1345 button.removeClass('shake-animation'); 1346 }, 3000); 1347 1348 return false; 1349 } 1350 1351 // If we have valid input but no preset variation, set up variation data 1352 if (hasValidInput && activeVariations.length === 0) { 1353 // Set the variation_id hidden input for custom amount 1354 var variationIdInput = variationsForm.find('input[name="variation_id"]'); 1355 if (variationIdInput.length > 0) { 1356 variationIdInput.val('custom-' + inputValue); 1357 } 1358 1359 // Set the attribute value in the hidden select 1360 var attributeSelect = variationsForm.find('select[name="attribute_pa_lend-amount"]'); 1361 if (attributeSelect.length > 0) { 1362 attributeSelect.val('lend-' + inputValue); 1363 } 1364 1365 // Trigger change event to notify WooCommerce 1366 attributeSelect.trigger('change'); 1367 } 1368 }); 1369 1370 /** 1371 * Helper function to get texts for validation and errors 1372 * @since 1.2.0 1373 */ 1374 function spark_open_price_events_texts($text_key, $min_amount, $max_amount){ 1375 let return_text = ''; 1376 switch ($text_key) { 1377 case 'please_enter_numbers_only' : 1378 return_text = 'Please enter numbers only'; 1379 1380 if(digi_e_vars.lang == 'he') { 1381 return_text = '×× × ××× ×¡ ×ספר×× ××××'; 1382 } 1383 return return_text; 1384 1385 break; 1386 1387 case 'minimum_amount_err_txt' : 1388 return_text = 'Minimum amount is ' + $min_amount; 1389 1390 if(digi_e_vars.lang == 'he') { 1391 return_text = '×ס××× ×××× ×××× ××× ' + $min_amount; 1392 } 1393 return return_text; 1394 1395 break; 1396 1397 case 'maximum_amount_err_txt' : 1398 return_text = 'Maximum amount is ' + $max_amount; 1399 1400 if(digi_e_vars.lang == 'he') { 1401 return_text = '×ס××× ×××× ×××× ××× ' + $max_amount; 1402 } 1403 return return_text; 1404 1405 break; 1406 1407 case 'add_to_cart_button_text' : 1408 return_text = 'Lend Now'; 1409 1410 if(digi_e_vars.lang == 'he') { 1411 return_text = '×××××× ×עסק'; 1412 } 1413 return return_text; 1414 1415 break; 1416 1417 case 'select_options_missimg_notification' : 1418 return_text = 'Please Select an Option'; 1419 1420 if(digi_e_vars.lang == 'he') { 1421 return_text = '×× × ××ר ×פשר×ת'; 1422 } 1423 return return_text; 1424 1425 break; 1426 } 1427 1428 return return_text; 1429 } 1430 1431 1432 1433 /** 1434 * Helper function to reset button text to "Select options" 1435 * @since 1.2.0 1436 * @param {jQuery} input - The input element that triggered the reset 1437 */ 1438 function resetButtonToSelectOptions(input) { 1439 var productInfoWrap = input.closest('.product-info-wrap');
1440 var addWrap = productInfoWrap.find('.add-to-cart-grid'); 1441 var variationsWrap = productInfoWrap.find('.nasa-product-content-variations'); 1442 1443 let select_options_missimg_notification = spark_open_price_events_texts('select_options_missimg_notification', min_amount, max_amount); 1444 1445 if (addWrap.hasClass('nasa-variable-add-to-cart-in-grid') && !$('body').hasClass('nasa-ywraq-hide-add-to-cart')) { 1446 // Get the "Select options" text from data attribute or fallback 1447 var selectText = variationsWrap.attr('data-select_text') || select_options_missimg_notification; 1448 1449 // Reset button text and attributes 1450 addWrap.find('.add_to_cart_text').html(selectText); 1451 addWrap.attr('title', selectText); 1452 1453 // Update tooltip if present 1454 if (addWrap.hasClass('nasa-tip')) { 1455 addWrap.attr('data-tip', selectText); 1456 1457 if (addWrap.find('.nasa-tip-content').length) { 1458 addWrap.find('.nasa-tip-content').html(selectText); 1459 } 1460 } 1461 1462 // Deactivate the button by removing nasa-active class 1463 addWrap.removeClass('nasa-active'); 1464 } 1465 } 1466 1467 /** ------------------------------------------------------------------------------------- */ 1468 1469 /** Programs filter icon toggle */ 1470 $(document).on('click', '#programs-filter-icon-toggle', function (e) { 1471 e.preventDefault(); 1472 1473 const $target = $("#programs-filter-search"); 1474 1475 // If it's currently visible, slide it up; otherwise, slide it down 1476 if ($target.is(':visible')) { 1477 $target.slideUp(200, function () { 1478 $target.addClass('spark-hide'); // re-add the hidden class after animation 1479 }); 1480 } else { 1481 $target.removeClass('spark-hide').hide().slideDown(200); 1482 } 1483 }); 1484 1485 /** Programs go to section after select*/ 1486 $(document).on('change', '#programs-age-filter .spark-taxonomy-filter-select', function (e) { 1487 // Scroll smoothly to the target element 1488 $('html, body').animate({ 1489 scrollTop: $('#programs-filter-icon-toggle').offset().top 1490 }, 600); // 600ms for smoothness 1491 }); 1492 1493 /**** 1494 * HP Tabs Products Slider ---------------------------------------------------------- 1495 * @since 2.1 1496 */ 1497 1498 // Helper: normalize NASA slider to single row on mobile 1499 function normalizeSliderToSingleRow($slider) { 1500 if (!$slider.length || $slider.data('normalized-mobile')) return; 1501 1502 const isMobile = window.matchMedia('(max-width: 767px)').matches; 1503 if (!isMobile) return; 1504 1505 if ($slider.hasClass('nasa-slide-double-row')) { 1506 //console.log('Normalizing NASA double-row â single row for:', $slider.attr('class')); 1507 1508 // Unslick if initialized 1509 if ($slider.hasClass('slick-initialized')) { 1510 $slider.slick('unslick'); 1511 } 1512 1513 // Flatten DOM: one product per column 1514 const $newSlides = []; 1515 $slider.find('.nasa-wrap-column').each(function () { 1516 $(this).find('.product').each(function () { 1517 $newSlides.push($('<div class="nasa-wrap-column"></div>').append($(this))); 1518 }); 1519 }); 1520 1521 $slider.empty().append($newSlides); 1522 $slider.removeClass('nasa-slide-double-row'); 1523 1524 // Re-init Slick as a single-row slider 1525 const columns = parseInt($slider.data('columns-small'), 10) || 1; 1526 const tabletColumns = parseInt($slider.data('columns-tablet'), 10) || 2; 1527 const desktopColumns = parseInt($slider.data('columns'), 10) || 4; 1528 1529 $slider.slick({ 1530 rows: 1, 1531 slidesToShow: columns, 1532 slidesToScroll: 1, 1533 mobileFirst: true, 1534 rtl: $('html').attr('dir') === 'rtl', 1535 responsive: [ 1536 { breakpoint: 768, settings: { slidesToShow: tabletColumns, rows: 1 } }, 1537 { breakpoint: 1024, settings: { slidesToShow: desktopColumns, rows: 1 } }, 1538 ], 1539 }); 1540 1541 $slider.data('normalized-mobile', true); 1542 //console.log('NASA slider rebuilt for mobile.'); 1543 } 1544 } 1545 1546 // Intercept "All Businesses" tab before Elementor handles it 1547 document.addEventListener( 1548 'click', 1549 function (e) { 1550 const el = e.target.closest('#hp-products-tabs .e-n-tab-title#all-tab'); 1551 1552 let redirect_to = '/lend/'; 1553 1554 if(digi_e_vars.lang == 'he') { 1555 redirect_to = '/he/lend/'; 1556 } 1557 1558 1559 if (el) { 1560 e.preventDefault(); // stop default action 1561 e.stopImmediatePropagation(); // block Elementorâs listener 1562 e.stopPropagation(); // block bubbling 1563 window.location.href = redirect_to; // redirect immediately 1564 } 1565 }, 1566 true // <--- capture phase: runs before Elementor's own click handler 1567 ); 1568 1569 1570 // Listen for Elementor tab clicks 1571 $(document).on('click', '#hp-products-tabs .e-n-tab-title', function (e) { 1572 const $this = $(this); 1573 const targetId = $this.attr('aria-controls'); 1574 const $targetPanel = $('#' + targetId); 1575 1576 const waitForVisible = setInterval(function () { 1577 if ($targetPanel.is(':visible') && $targetPanel.height() > 0) { 1578 clearInterval(waitForVisible); 1579 1580 const $tabsWrapper = $targetPanel.closest('.e-n-tabs-content'); 1581 $tabsWrapper.css({ height: 'auto', overflow: 'visible' }); 1582 $targetPanel.css({ 1583 height: 'auto', 1584 opacity: 1, 1585 visibility: 'visible', 1586 transform: 'none', 1587 display: 'block', 1588 }); 1589 1590 setTimeout(function () { 1591 const $sliders = $targetPanel.find('.nasa-slick-slider'); 1592 1593 $sliders.each(function () { 1594 const $slider = $(this); 1595 if ($slider.hasClass('slick-initialized')) { 1596 $slider.slick('setPosition'); 1597 } else { 1598 $slider.slick(); 1599 } 1600 1601 // Normalize NASA slider if on mobile 1602 normalizeSliderToSingleRow($slider); 1603 }); 1604 1605 // Force browser reflow & repaint to fix âblank until scrollâ issue 1606 $targetPanel[0].style.willChange = 'transform'; 1607 void $targetPanel[0].offsetHeight; 1608 $targetPanel[0].style.willChange = 'auto'; 1609 window.scrollBy(0, 1); 1610 window.scrollBy(0, -1); 1611 }, 100); 1612 } 1613 }, 100); 1614 }); // #hp-products-tabs .e-n-tab-title onclick 1615 1616 $(document).on('click', '.spark-biz-gallery-slider .spark-gallery-nav', function(e) { 1617 e.preventDefault(); 1618 1619 var $btn = $(this); 1620 var $slider = $btn.closest('.spark-biz-gallery-slider'); 1621 1622 if (!$slider.length) { 1623 return; 1624 } 1625 1626 var dir = parseInt($btn.attr('data-dir'), 10); 1627 if (isNaN(dir) || (dir !== 1 && dir !== -1)) { 1628 dir = 1; 1629 } 1630 1631 var $slides = $slider.find('.spark-gallery-slide'); 1632 var total = $slides.length; 1633 1634 if (total < 2) { 1635 return; 1636 } 1637 1638 var current = parseInt($slider.attr('data-current'), 10); 1639 if (isNaN(current)) { 1640 current = 0; 1641 } 1642 1643 var next = current + dir; 1644 if (next < 0) { 1645 next = total - 1; 1646 } 1647 if (next >= total) { 1648 next = 0; 1649 } 1650 1651 $slides.removeClass('is-active'); 1652 $slider.find('.spark-gallery-slide[data-index="' + next + '"]').addClass('is-active');
1653 $slider.attr('data-current', String(next)); 1654 }); 1655 1656 1657 1658 /** End HP Tabs Products Slider ---------------------------------------*/ 1659 1660 }); // domContentLoaded 1661 1662})(window); 1663 1664;(function($){ 1665 'use strict'; 1666 1667 /** 1668 * Elementor Pro Taxonomy Filter - Dropdown + Ignore Other Filters 1669 * 1670 * Reads custom controls from `includes/elementor_filter_widget_custom.php` and applies frontend behavior: 1671 * - If wrapper has `spark-tax-filter-as-dropdown`, build a <select> from rendered buttons and hide the bar. 1672 * - If wrapper has `spark-tax-filter-ignore-yes`, clear other taxonomy filters before applying this one. 1673 * 1674 * Security/Performance/Data Privacy: 1675 * - No external requests; scoped DOM operations; URL cleaned with history.replaceState. 1676 * - Human readable code and comments. 1677 * 1678 * @since 2 1679 */ 1680 function spark_register_taxonomy_filter_behavior() { 1681 if (typeof elementorFrontend === 'undefined' || !elementorFrontend.hooks) { 1682 return; 1683 } 1684 elementorFrontend.hooks.addAction('frontend/element_ready/taxonomy-filter.default', function(scope){ 1685 var $scope = jQuery(scope); 1686 1687 // avoid double init on rerenders 1688 if ($scope.data('spark_dropdown_initialized')) { 1689 return; 1690 } 1691 1692 // detect settings via wrapper classes added by prefix_class 1693 var is_dropdown = $scope.hasClass('spark-tax-filter-as-dropdown'); 1694 var ignore_others = $scope.hasClass('spark-tax-filter-ignore-yes'); 1695 1696 // Helper: enhance original buttons with taxonomy images (button mode only) 1697 function enhance_taxonomy_images($sc, $cont, $btns){ 1698 var tax_img_enabled = $sc.attr('data-spark-tax-image') === 'yes'; 1699 if (!tax_img_enabled) { return; } 1700 // If server-side already injected images/classes, skip AJAX enhancement 1701 if ($btns.filter('.spark-taxonomy-button').length || $btns.find('.spark-tax-image-wrap').length) { 1702 return; 1703 } 1704 try { 1705 var st = $sc.data('settings') || {}; 1706 var taxonomy = st.taxonomy || null; 1707 var meta_key = $sc.attr('data-spark-tax-image-key') || ''; 1708 var img_extra_class = $sc.attr('data-spark-tax-image-class') || ''; 1709 if (!taxonomy || !meta_key) { return; } 1710 1711 var slugs = []; 1712 $btns.each(function(){ 1713 var v = jQuery(this).data('filter'); 1714 if (v && v !== '__all') { slugs.push(String(v)); } 1715 }); 1716 if (!slugs.length) { return; } 1717 1718 jQuery.ajax({ 1719 url: (typeof digi_e_vars !== 'undefined' ? digi_e_vars.ajaxurl : '/wp-admin/admin-ajax.php'), 1720 method: 'POST', 1721 dataType: 'json', 1722 data: { 1723 action: 'spark_get_tax_images', 1724 taxonomy: taxonomy, 1725 meta_key: meta_key, 1726 slugs: slugs 1727 } 1728 }).done(function(resp){ 1729 var images = resp && resp.success && resp.data && resp.data.images ? resp.data.images : {}; 1730 $btns.each(function(){ 1731 var $btn = jQuery(this); 1732 var slug = String($btn.data('filter') || ''); 1733 if (slug === '__all') { return; } 1734 var img_url = images[slug] || ''; 1735 var label_text = ($btn.text() || '').trim(); 1736 var safe_label = label_text.replace(/</g,'<').replace(/>/g,'>'); 1737 if (img_url) { 1738 var img_cls = img_extra_class ? ' ' + img_extra_class : ''; 1739 var html = '' + 1740 '<span class="spark-tax-image-wrap">' + 1741 '<img src="' + img_url + '" alt="' + safe_label + '" class="spark-tax-image' + img_cls + '" />' + 1742 '</span>' + 1743 '<span class="spark-tax-title-wrap">' + safe_label + '</span>'; 1744 $btn.empty().append(html).addClass('spark-taxonomy-button'); 1745 } else { 1746 var html2 = '<span class="spark-tax-title-wrap">' + safe_label + '</span>'; 1747 $btn.empty().append(html2).addClass('spark-taxonomy-button'); 1748 } 1749 }); 1750 }); 1751 } catch(e) {} 1752 } 1753 1754 // Observe class changes to handle live toggling in Elementor editor (both ON and OFF) 1755 if (!$scope.data('spark_class_observer_attached')) { 1756 try { 1757 var class_observer = new MutationObserver(function(mutations){ 1758 mutations.forEach(function(m){ 1759 if (m.attributeName !== 'class') return; 1760 var has_dropdown_now = $scope.hasClass('spark-tax-filter-as-dropdown'); 1761 var built_now = !!$scope.data('spark_dropdown_initialized'); 1762 var $container_now = $scope.find('.e-filter'); 1763 1764 if (has_dropdown_now && !built_now) { 1765 // Build dropdown 1766 var $buttons_now = $container_now.find('.e-filter-item'); 1767 if (!$buttons_now.length) return; 1768 var $select_now = jQuery('<select class="spark-taxonomy-filter-select" aria-label="Taxonomy filter"></select>'); 1769 var all_label_now = $scope.attr('data-spark-dropdown-all-label') || 'All'; 1770 var active_slugs_now = []; 1771 $buttons_now.filter('[aria-pressed="true"]').each(function(){ 1772 var slug = jQuery(this).data('filter'); 1773 if (typeof slug !== 'undefined') active_slugs_now.push(String(slug));
1774 }); 1775 if (!active_slugs_now.length) active_slugs_now = ['__all']; 1776 1777 var $opt_all_now = jQuery('<option></option>').attr('value', '__all').text(all_label_now); 1778 if (active_slugs_now.indexOf('__all') !== -1) { $opt_all_now.prop('selected', true); } 1779 $select_now.append($opt_all_now); 1780 1781 $buttons_now.each(function(){ 1782 var $b = jQuery(this); 1783 var val = String($b.data('filter')); 1784 if (val === '__all') return; 1785 var lbl = ($b.text() || '').trim(); 1786 var $op = jQuery('<option></option>').attr('value', val).text(lbl); 1787 if (active_slugs_now.indexOf(val) !== -1) { $op.prop('selected', true); } 1788 $select_now.append($op); 1789 }); 1790 1791 $container_now.before($select_now); 1792 $container_now.attr('hidden', 'hidden'); 1793 1794 $select_now.on('change', function(){ 1795 var sel = jQuery(this).val(); 1796 if ($scope.hasClass('spark-tax-filter-ignore-yes')) { clear_other_tax_filters($scope); } 1797 var $t = $container_now.find('.e-filter-item[data-filter="' + sel + '"]'); 1798 if ($t.length) { 1799 $t.trigger('click'); 1800 } else if (sel === '__all') { 1801 try { 1802 var st = $scope.data('settings') || {}; 1803 var se = st.selected_element || null; 1804 var fid = $scope.data('id'); 1805 if (!fid) { 1806 var mm = ($scope.attr('class') || '').match(/elementor-element-([a-f0-9]+)/i); 1807 if (mm && mm[1]) { fid = mm[1]; } 1808 } 1809 if (se && fid && elementorProFrontend && elementorProFrontend.modules && elementorProFrontend.modules.taxonomyFilter) { 1810 elementorProFrontend.modules.taxonomyFilter.removeFilterFromLoopWidget(se, fid, ''); 1811 } 1812 } catch(e) {} 1813 } 1814 }); 1815 1816 $scope.data('spark_dropdown_initialized', true); 1817 } 1818 1819 if (!has_dropdown_now && built_now) { 1820 // Tear down dropdown 1821 $scope.find('select.spark-taxonomy-filter-select').remove(); 1822 $container_now.removeAttr('hidden'); 1823 $scope.removeData('spark_dropdown_initialized'); 1824 1825 // Re-apply taxonomy images on returning to button mode 1826 var $buttons_now = $container_now.find('.e-filter-item'); 1827 if ($buttons_now.length) { 1828 enhance_taxonomy_images($scope, $container_now, $buttons_now); 1829 } 1830 } 1831 }); 1832 }); 1833 class_observer.observe($scope[0], { attributes: true, attributeFilter: ['class'] }); 1834 $scope.data('spark_class_observer_attached', true); 1835 } catch(e) {} 1836 } 1837 1838 // If ignore-other-filters is enabled but widget is not dropdown, bind a lightweight handler 1839 // so interacting will clear other filters first. Use mousedown to run before Elementor's click. 1840 if (ignore_others && !is_dropdown) { 1841 $scope.find('.e-filter').off('mousedown.sparkIgnore').on('mousedown.sparkIgnore', '.e-filter-item', function(){ 1842 clear_other_tax_filters($scope); 1843 }); 1844 } 1845 1846 if (!is_dropdown) { 1847 // Editor fallback: if user toggles to dropdown in the editor, Elementor sometimes updates classes 1848 // without a full re-render. Poll briefly to detect the class and build the dropdown once. 1849 var tries = 0; 1850 var poll_id = setInterval(function(){ 1851 tries++; 1852 if ($scope.hasClass('spark-tax-filter-as-dropdown') && !$scope.data('spark_dropdown_initialized')) { 1853 var $container_fb = $scope.find('.e-filter'); 1854 if (!$container_fb.length) { return; } 1855 var $buttons_fb = $container_fb.find('.e-filter-item'); 1856 if (!$buttons_fb.length) { return; } 1857 1858 var $select_fb = jQuery('<select class="spark-taxonomy-filter-select" aria-label="Taxonomy filter"></select>'); 1859 var dropdown_all_label_fb = $scope.attr('data-spark-dropdown-all-label') || 'All'; 1860 1861 var active_slugs_fb = []; 1862 $buttons_fb.filter('[aria-pressed="true"]').each(function(){ 1863 var slug = jQuery(this).data('filter'); 1864 if (typeof slug !== 'undefined') { active_slugs_fb.push(String(slug)); } 1865 }); 1866 if (!active_slugs_fb.length) { active_slugs_fb = ['__all']; } 1867 1868 var $opt_all_fb = jQuery('<option></option>').attr('value', '__all').text(dropdown_all_label_fb); 1869 if (active_slugs_fb.indexOf('__all') !== -1) { $opt_all_fb.prop('selected', true); } 1870 $select_fb.append($opt_all_fb); 1871 1872 $buttons_fb.each(function(){ 1873 var $btn = jQuery(this);
1874 var value = String($btn.data('filter')); 1875 if (value === '__all') { return; } 1876 var label = ($btn.text() || '').trim(); 1877 var $opt = jQuery('<option></option>').attr('value', value).text(label); 1878 if (active_slugs_fb.indexOf(value) !== -1) { $opt.prop('selected', true); } 1879 $select_fb.append($opt); 1880 }); 1881 1882 $container_fb.before($select_fb); 1883 $container_fb.attr('hidden', 'hidden'); 1884 1885 // bind change like main path 1886 $select_fb.on('change', function(){ 1887 var selected_value_fb = jQuery(this).val(); 1888 if (ignore_others) { clear_other_tax_filters($scope); } 1889 var $target_fb = $container_fb.find('.e-filter-item[data-filter="' + selected_value_fb + '"]'); 1890 if ($target_fb.length) { 1891 $target_fb.trigger('click'); 1892 } else if (selected_value_fb === '__all') { 1893 try { 1894 var settings_fb = $scope.data('settings') || {}; 1895 var selected_element_id_fb = settings_fb.selected_element || null; 1896 var filter_id_fb = $scope.data('id'); 1897 if (!filter_id_fb) { 1898 var m_fb = ($scope.attr('class') || '').match(/elementor-element-([a-f0-9]+)/i); 1899 if (m_fb && m_fb[1]) { filter_id_fb = m_fb[1]; } 1900 } 1901 if (selected_element_id_fb && filter_id_fb && elementorProFrontend && elementorProFrontend.modules && elementorProFrontend.modules.taxonomyFilter) { 1902 elementorProFrontend.modules.taxonomyFilter.removeFilterFromLoopWidget(selected_element_id_fb, filter_id_fb, ''); 1903 } 1904 } catch(e) {} 1905 } 1906 }); 1907 1908 $scope.data('spark_dropdown_initialized', true); 1909 clearInterval(poll_id); 1910 } 1911 if (tries > 80) { 1912 clearInterval(poll_id); 1913 } 1914 }, 150); 1915 // Before exiting (button mode), enhance buttons with taxonomy images once 1916 var $cont_btn = $scope.find('.e-filter'); 1917 var $btns_btn = $cont_btn.find('.e-filter-item'); 1918 if ($cont_btn.length && $btns_btn.length) { 1919 enhance_taxonomy_images($scope, $cont_btn, $btns_btn); 1920 } 1921 return; // nothing else to do when not dropdown 1922 } 1923 1924 var $container = $scope.find('.e-filter'); 1925 if (!$container.length) { 1926 return; 1927 } 1928 1929 var $buttons = $container.find('.e-filter-item'); 1930 if (!$buttons.length) { 1931 return; 1932 } 1933 1934 // Note: taxonomy image enhancement runs only in button mode; skipped in dropdown mode 1935 1936 // build dropdown 1937 var $select = jQuery('<select class="spark-taxonomy-filter-select" aria-label="Taxonomy filter"></select>'); 1938 1939 // read custom first option label from wrapper data attribute 1940 var dropdown_all_label = $scope.attr('data-spark-dropdown-all-label') || 'All'; 1941 1942 // determine currently active slugs 1943 var active_slugs = []; 1944 $buttons.filter('[aria-pressed="true"]').each(function(){ 1945 var slug = jQuery(this).data('filter'); 1946 if (typeof slug !== 'undefined') { 1947 active_slugs.push(String(slug)); 1948 } 1949 }); 1950 if (!active_slugs.length) { 1951 active_slugs = ['__all']; 1952 } 1953 1954 // 1) add first option for clearing filter ("All") 1955 var $opt_all = jQuery('<option></option>').attr('value', '__all').text(dropdown_all_label); 1956 if (active_slugs.indexOf('__all') !== -1) { 1957 $opt_all.prop('selected', true); 1958 } 1959 $select.append($opt_all); 1960 1961 // 2) add other options, skipping the original __all button to avoid duplication 1962 $buttons.each(function(){ 1963 var $btn = jQuery(this); 1964 var value = String($btn.data('filter')); 1965 if (value === '__all') { 1966 return; // skip duplicate of first option 1967 } 1968 var label = ($btn.text() || '').trim(); 1969 var $opt = jQuery('<option></option>').attr('value', value).text(label); 1970 if (active_slugs.indexOf(value) !== -1) { 1971 $opt.prop('selected', true); 1972 } 1973 $select.append($opt); 1974 }); 1975 1976 // insert and hide original bar (kept for accessibility and event wiring) 1977 $container.before($select); 1978 $container.attr('hidden', 'hidden'); 1979 1980 /** 1981 * clear_other_tax_filters 1982 * 1983 * Reset other taxonomy-filter widgets to default (All) and remove their query params. 1984 * @param {jQuery} current_scope 1985 * @since 2 1986 */ 1987 function clear_other_tax_filters(current_scope){ 1988 // clean URL e-filter-* params 1989 try { 1990 var url_obj = new URL(window.location.href); 1991 var keys_to_delete = []; 1992
1993 url_obj.searchParams.forEach(function(_v, key){ 1994 if (key.indexOf('e-filter-') === 0) { 1995 keys_to_delete.push(key); 1996 } 1997 }); 1998 1999 if (keys_to_delete.length) { 2000 keys_to_delete.forEach(function(k){ url_obj.searchParams.delete(k); }); 2001 var new_qs = url_obj.searchParams.toString(); 2002 window.history.replaceState({}, '', url_obj.pathname + (new_qs ? '?' + new_qs : '') + url_obj.hash); 2003 } 2004 } catch(err) { 2005 // ignore silently 2006 } 2007 2008 // click "All" on other widgets to reset their state, or deactivate active terms if no All option exists 2009 jQuery('.elementor-widget-taxonomy-filter').each(function(){ 2010 var $widget = jQuery(this); 2011 if ($widget.is(current_scope)) { 2012 return; 2013 } 2014 var $all_btn = $widget.find('.e-filter .e-filter-item[data-filter="__all"]'); 2015 if ($all_btn.length) { 2016 if ($all_btn.attr('aria-pressed') !== 'true') { 2017 $all_btn.trigger('click'); 2018 } 2019 } else { 2020 // No All button configured: deactivate any active terms to clear filter store 2021 var $active_terms = $widget.find('.e-filter .e-filter-item[aria-pressed="true"]'); 2022 $active_terms.each(function(){ 2023 var $btn = jQuery(this); 2024 var val = String($btn.data('filter')); 2025 if (val !== '__all') { 2026 $btn.trigger('click'); 2027 } 2028 }); 2029 } 2030 2031 // Final assurance: directly clear filter via Elementor API if available 2032 try { 2033 var w_settings = $widget.data('settings') || {}; 2034 var w_selected_element = w_settings.selected_element || null; 2035 var w_filter_id = $widget.data('id'); 2036 if (!w_filter_id) { 2037 var m2 = ($widget.attr('class') || '').match(/elementor-element-([a-f0-9]+)/i); 2038 if (m2 && m2[1]) { w_filter_id = m2[1]; } 2039 } 2040 if (w_selected_element && w_filter_id && elementorProFrontend && elementorProFrontend.modules && elementorProFrontend.modules.taxonomyFilter) { 2041 elementorProFrontend.modules.taxonomyFilter.removeFilterFromLoopWidget(w_selected_element, w_filter_id, ''); 2042 } 2043 } catch(e) {} 2044 }); 2045 } 2046 2047 // apply selection from dropdown 2048 $select.on('change', function(){ 2049 var selected_value = jQuery(this).val(); 2050 2051 if (ignore_others) { 2052 clear_other_tax_filters($scope); 2053 } 2054 2055 // delegate to built-in button logic for consistency 2056 var $target = $container.find('.e-filter-item[data-filter="' + selected_value + '"]'); 2057 if ($target.length) { 2058 $target.trigger('click'); 2059 } else if (selected_value === '__all') { 2060 // Fallback: widget may not render an "All" button; clear filter via public API 2061 try { 2062 var settings = $scope.data('settings') || {}; 2063 var selected_element_id = settings.selected_element || null; 2064 var filter_id = $scope.data('id'); 2065 if (!filter_id) { 2066 var m = ($scope.attr('class') || '').match(/elementor-element-([a-f0-9]+)/i); 2067 if (m && m[1]) { filter_id = m[1]; } 2068 } 2069 if (selected_element_id && filter_id && elementorProFrontend && elementorProFrontend.modules && elementorProFrontend.modules.taxonomyFilter) { 2070 elementorProFrontend.modules.taxonomyFilter.removeFilterFromLoopWidget(selected_element_id, filter_id, ''); 2071 } 2072 } catch(e) { 2073 // ignore runtime errors 2074 } 2075 } 2076 }); 2077 2078 $scope.data('spark_dropdown_initialized', true); 2079 }); 2080 } 2081 2082 // Register immediately if Elementor is already initialized (covers editor preview load order) 2083 if (typeof elementorFrontend !== 'undefined' && elementorFrontend.hooks) { 2084 spark_register_taxonomy_filter_behavior(); 2085 } 2086 2087 // Also register on the standard init event (covers normal frontend load order) 2088 $(window).on('elementor/frontend/init', function(){ 2089 spark_register_taxonomy_filter_behavior(); 2090 }); 2091 2092})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.