| 1 |
/** |
| 2 |
* Pricing Slider JavaScript |
| 3 |
* Handles interactive functionality for both single and multiple sliders. |
| 4 |
*/ |
| 5 |
(function($) { |
| 6 |
'use strict'; |
| 7 |
|
| 8 |
// Add basic CSS for notifications that will be created by JS |
| 9 |
function addBasicNotificationCSS() { |
| 10 |
if ($('#king-addons-pricing-slider-notification-styles').length) { |
| 11 |
return; // Already added |
| 12 |
} |
| 13 |
|
| 14 |
var css = ` |
| 15 |
.king-addons-slider-notice { |
| 16 |
display: block; |
| 17 |
padding: 10px 15px; |
| 18 |
margin: 10px 0; |
| 19 |
border-radius: 4px; |
| 20 |
font-size: 14px; |
| 21 |
line-height: 1.5; |
| 22 |
} |
| 23 |
.king-addons-slider-notice.success { |
| 24 |
color: #3c763d; |
| 25 |
background-color: #dff0d8; |
| 26 |
border: 1px solid #d6e9c6; |
| 27 |
} |
| 28 |
.king-addons-slider-notice.error { |
| 29 |
color: #a94442; |
| 30 |
background-color: #f2dede; |
| 31 |
border: 1px solid #ebccd1; |
| 32 |
} |
| 33 |
.king-addons-slider-view-cart { |
| 34 |
display: block; |
| 35 |
margin: 10px 0; |
| 36 |
padding: 8px 12px; |
| 37 |
text-align: center; |
| 38 |
text-decoration: none; |
| 39 |
color: #4e4e4e; |
| 40 |
background-color: #f7f7f7; |
| 41 |
border: 1px solid #ddd; |
| 42 |
border-radius: 4px; |
| 43 |
transition: all 0.3s ease; |
| 44 |
} |
| 45 |
.king-addons-slider-view-cart:hover { |
| 46 |
color: #23527c; |
| 47 |
background-color: #e6e6e6; |
| 48 |
border-color: #adadad; |
| 49 |
} |
| 50 |
`; |
| 51 |
|
| 52 |
$('<style id="king-addons-pricing-slider-notification-styles">' + css + '</style>').appendTo('head'); |
| 53 |
} |
| 54 |
|
| 55 |
// Execute once when script loads |
| 56 |
addBasicNotificationCSS(); |
| 57 |
|
| 58 |
// --- Shared Helper Functions --- (Moved here) |
| 59 |
|
| 60 |
/** |
| 61 |
* Calculates the price based on the value and formula settings. |
| 62 |
* @param {number} value The current slider value. |
| 63 |
* @param {object} formulaSettings Settings object containing formula type and parameters. |
| 64 |
* @returns {number} Calculated price. |
| 65 |
*/ |
| 66 |
function calculatePrice(value, formulaSettings) { |
| 67 |
if (!formulaSettings) return value; // Return raw value if no settings |
| 68 |
|
| 69 |
var formulaType = formulaSettings.advanced_formula_types || formulaSettings.formula || 'linear'; |
| 70 |
|
| 71 |
// Linear formula (Default in free version) |
| 72 |
if (formulaType === 'linear') { |
| 73 |
var a = typeof formulaSettings.a !== 'undefined' ? parseFloat(formulaSettings.a) : 1; |
| 74 |
var b = typeof formulaSettings.b !== 'undefined' ? parseFloat(formulaSettings.b) : 0; |
| 75 |
return a * value + b; |
| 76 |
} |
| 77 |
// Pro version formulas... |
| 78 |
else if (formulaType === 'exponential') { |
| 79 |
var base = typeof formulaSettings.formula_exp_base !== 'undefined' ? parseFloat(formulaSettings.formula_exp_base) : 1.1; |
| 80 |
var multiplier = typeof formulaSettings.formula_exp_multiplier !== 'undefined' ? parseFloat(formulaSettings.formula_exp_multiplier) : 1; |
| 81 |
return multiplier * Math.pow(base, value); |
| 82 |
} |
| 83 |
else if (formulaType === 'logarithmic') { |
| 84 |
var baseLog = typeof formulaSettings.formula_log_base !== 'undefined' ? parseFloat(formulaSettings.formula_log_base) : 10; |
| 85 |
var multiplierLog = typeof formulaSettings.formula_log_multiplier !== 'undefined' ? parseFloat(formulaSettings.formula_log_multiplier) : 10; |
| 86 |
value = Math.max(1, value); // Logarithm is undefined for 0 or negative |
| 87 |
return multiplierLog * (Math.log(value) / Math.log(baseLog)); |
| 88 |
} |
| 89 |
else if (formulaType === 'power') { |
| 90 |
var exponent = typeof formulaSettings.formula_power_exponent !== 'undefined' ? parseFloat(formulaSettings.formula_power_exponent) : 2; |
| 91 |
var multiplierPower = typeof formulaSettings.formula_power_multiplier !== 'undefined' ? parseFloat(formulaSettings.formula_power_multiplier) : 1; |
| 92 |
return multiplierPower * Math.pow(value, exponent); |
| 93 |
} |
| 94 |
else if (formulaType === 'custom') { |
| 95 |
// Find the closest custom price point <= current value |
| 96 |
var customPrices = formulaSettings.custom_prices || []; |
| 97 |
var bestMatchPrice = value; // Fallback |
| 98 |
var closestLowerVal = -Infinity; |
| 99 |
|
| 100 |
customPrices.forEach(function(point) { |
| 101 |
var pointValue = parseFloat(point.value); |
| 102 |
var pointPrice = parseFloat(point.price); |
| 103 |
if (!isNaN(pointValue) && !isNaN(pointPrice) && pointValue <= value && pointValue > closestLowerVal) { |
| 104 |
closestLowerVal = pointValue; |
| 105 |
bestMatchPrice = pointPrice; |
| 106 |
} |
| 107 |
}); |
| 108 |
return bestMatchPrice; |
| 109 |
} |
| 110 |
|
| 111 |
// Fallback to linear if formula type is unknown or default linear params if only 'linear' is specified |
| 112 |
var defaultA = typeof formulaSettings.a !== 'undefined' ? parseFloat(formulaSettings.a) : 1; |
| 113 |
var defaultB = typeof formulaSettings.b !== 'undefined' ? parseFloat(formulaSettings.b) : 0; |
| 114 |
return defaultA * value + defaultB; |
| 115 |
} |
| 116 |
|
| 117 |
/** |
| 118 |
* Formats a price number into an HTML string with currency, prefix, suffix, etc. |
| 119 |
* @param {number} price The numerical price. |
| 120 |
* @param {object} priceFormatData Settings for formatting (currency_symbol, etc.). |
| 121 |
* @returns {string} HTML string for the price display. |
| 122 |
*/ |
| 123 |
function formatPriceHTML(price, priceFormatData) { |
| 124 |
var decimals = typeof priceFormatData.decimals !== 'undefined' ? parseInt(priceFormatData.decimals) : 2; |
| 125 |
var formattedPrice = parseFloat(price).toFixed(decimals); |
| 126 |
var currencySymbol = priceFormatData.currency_symbol || ''; |
| 127 |
var pricePrefix = priceFormatData.price_prefix || ''; |
| 128 |
var priceSuffix = priceFormatData.price_suffix || ''; |
| 129 |
var period = priceFormatData.period || ''; |
| 130 |
var currencyPosition = priceFormatData.currency_position || 'before'; |
| 131 |
|
| 132 |
var price_html = ''; |
| 133 |
if (currencyPosition === 'before') { |
| 134 |
price_html += '<span class="king-addons-pricing-slider__currency">' + currencySymbol + '</span>'; |
| 135 |
} |
| 136 |
if (pricePrefix) { |
| 137 |
price_html += '<span class="king-addons-pricing-slider__prefix">' + pricePrefix + '</span>'; |
| 138 |
} |
| 139 |
// Ensure the value itself has the specific class for targeting if needed later |
| 140 |
price_html += '<span class="king-addons-pricing-slider__price-value">' + formattedPrice + '</span>'; |
| 141 |
if (priceSuffix) { |
| 142 |
price_html += '<span class="king-addons-pricing-slider__suffix">' + priceSuffix + '</span>'; |
| 143 |
} |
| 144 |
if (currencyPosition === 'after') { |
| 145 |
price_html += '<span class="king-addons-pricing-slider__currency">' + currencySymbol + '</span>'; |
| 146 |
} |
| 147 |
if (period) { |
| 148 |
price_html += '<span class="king-addons-pricing-slider__period">' + period + '</span>'; |
| 149 |
} |
| 150 |
return price_html; |
| 151 |
} |
| 152 |
|
| 153 |
/** |
| 154 |
* Updates the visual state (icon, class) of feature items based on the current value. |
| 155 |
* @param {number} value The current slider value. |
| 156 |
* @param {jQuery} featureItems jQuery object of all feature list items. |
| 157 |
* @param {Array} featuresDefinition Array of feature definition objects from settings. |
| 158 |
*/ |
| 159 |
function updateFeatures(value, featureItems, featuresDefinition) { |
| 160 |
featureItems.each(function() { |
| 161 |
var feature = $(this); |
| 162 |
// Use min-value from data attribute if present, otherwise assume 0 |
| 163 |
var minValueFeature = parseInt(feature.data('min-value')) || 0; |
| 164 |
// Determine if the feature should be 'included' based on the slider value |
| 165 |
var isIncluded = value >= minValueFeature; |
| 166 |
|
| 167 |
var featureTextElement = feature.find('.king-addons-pricing-slider__feature-text'); |
| 168 |
var featureText = featureTextElement.length ? featureTextElement.text().trim() : ''; // Get text content for matching |
| 169 |
var featureData = null; |
| 170 |
|
| 171 |
// Find the matching feature definition from the settings array |
| 172 |
if (Array.isArray(featuresDefinition) && featureText) { |
| 173 |
for (var i = 0; i < featuresDefinition.length; i++) { |
| 174 |
// Match based on the feature text content |
| 175 |
if (featuresDefinition[i] && featuresDefinition[i].text && featuresDefinition[i].text.trim() === featureText) { |
| 176 |
featureData = featuresDefinition[i]; |
| 177 |
break; |
| 178 |
} |
| 179 |
} |
| 180 |
} |
| 181 |
|
| 182 |
// Update icon and class if we found matching data |
| 183 |
if (featureData) { |
| 184 |
var iconSpan = feature.find('span:first-child'); // Assuming icon is in the first span |
| 185 |
var iconIncluded = featureData.icon_included || 'fas fa-check'; // Default icons |
| 186 |
var iconExcluded = featureData.icon_excluded || 'fas fa-times'; |
| 187 |
|
| 188 |
iconSpan.removeClass('king-addons-pricing-slider__feature-included king-addons-pricing-slider__feature-excluded'); |
| 189 |
|
| 190 |
if (isIncluded) { |
| 191 |
iconSpan.addClass('king-addons-pricing-slider__feature-included'); |
| 192 |
iconSpan.html('<i class="' + iconIncluded + '" aria-hidden="true"></i>'); |
| 193 |
} else { |
| 194 |
iconSpan.addClass('king-addons-pricing-slider__feature-excluded'); |
| 195 |
iconSpan.html('<i class="' + iconExcluded + '" aria-hidden="true"></i>'); |
| 196 |
} |
| 197 |
} else { |
| 198 |
// Optional: Handle case where feature item in HTML doesn't match any definition |
| 199 |
// console.warn('[KA Slider] No feature definition found for:', featureText); |
| 200 |
} |
| 201 |
}); |
| 202 |
} |
| 203 |
|
| 204 |
/** |
| 205 |
* Updates the UI elements of a single slider instance (progress bar, thumb, value display). |
| 206 |
* Moved here to be a shared helper. |
| 207 |
* @param {jQuery} singleSliderWrapper The wrapper (.king-addons-single-slider or .king-addons-pricing-slider). |
| 208 |
* @param {number} value The current value. |
| 209 |
*/ |
| 210 |
function sharedUpdateSliderUI(singleSliderWrapper, value) { |
| 211 |
var rangeInput = singleSliderWrapper.find('.king-addons-pricing-slider__range'); |
| 212 |
var progressBar = singleSliderWrapper.find('.king-addons-pricing-slider__progress'); |
| 213 |
var customThumb = singleSliderWrapper.find('.king-addons-pricing-slider__custom-thumb'); |
| 214 |
var currentValDisplay = singleSliderWrapper.find('.king-addons-pricing-slider__current-value'); |
| 215 |
|
| 216 |
if (!rangeInput.length) { |
| 217 |
// console.error('[KA Slider] Range input not found within:', singleSliderWrapper[0]); |
| 218 |
return; |
| 219 |
} |
| 220 |
if (!progressBar.length) { |
| 221 |
// console.warn('[KA Slider] Progress bar not found within:', singleSliderWrapper[0]); |
| 222 |
// Continue without progress bar update |
| 223 |
} |
| 224 |
if (!customThumb.length) { |
| 225 |
// console.warn('[KA Slider] Custom thumb not found within:', singleSliderWrapper[0]); // Log raw DOM element |
| 226 |
// Continue without thumb update |
| 227 |
} |
| 228 |
|
| 229 |
var min = parseFloat(rangeInput.attr('min')) || 0; |
| 230 |
var max = parseFloat(rangeInput.attr('max')) || 100; |
| 231 |
var percentage = 0; |
| 232 |
|
| 233 |
if (max > min) { |
| 234 |
percentage = ((value - min) / (max - min)) * 100; |
| 235 |
} else { |
| 236 |
// If max <= min, slider is effectively fixed. Percentage is 0 if value <= min, 100 if value >= max. |
| 237 |
// Or just treat as 0 to be safe. |
| 238 |
percentage = (value >= max) ? 100 : 0; |
| 239 |
// console.warn('[KA Slider] Max <= Min for slider:', rangeInput[0]); |
| 240 |
} |
| 241 |
|
| 242 |
percentage = Math.max(0, Math.min(100, percentage)); // Clamp percentage |
| 243 |
|
| 244 |
// console.log('[KA Slider] sharedUpdateSliderUI called:', { // Keep logs for now |
| 245 |
// wrapper: singleSliderWrapper[0], |
| 246 |
// value: value, |
| 247 |
// percentage: percentage, |
| 248 |
// thumbElement: customThumb.length ? customThumb[0] : 'Not Found' |
| 249 |
// }); |
| 250 |
|
| 251 |
// Apply styles |
| 252 |
if (progressBar.length) { |
| 253 |
progressBar.css('width', percentage + '%'); |
| 254 |
} |
| 255 |
if (customThumb.length) { |
| 256 |
customThumb.css('left', percentage + '%'); |
| 257 |
// console.log('[KA Slider] Applied left: ' + percentage + '% to thumb:', customThumb[0]); |
| 258 |
} |
| 259 |
|
| 260 |
// Update current value indicator (if exists) |
| 261 |
if (currentValDisplay.length) { |
| 262 |
currentValDisplay.text(value); |
| 263 |
currentValDisplay.css('left', percentage + '%'); |
| 264 |
// Recalculate margin based on actual thumb height at the time of update |
| 265 |
var thumbHeight = customThumb.length ? customThumb.outerHeight() : 0; |
| 266 |
if (thumbHeight) { |
| 267 |
var indicatorMarginTop = (thumbHeight / 2) + 10; // 10px gap above thumb center |
| 268 |
currentValDisplay.css('margin-top', indicatorMarginTop + 'px'); |
| 269 |
} else { |
| 270 |
// Fallback margin if thumb isn't found or has no height |
| 271 |
currentValDisplay.css('margin-top', '22px'); |
| 272 |
} |
| 273 |
} |
| 274 |
} |
| 275 |
|
| 276 |
// --- Initialization Functions (Using Shared Helpers) --- |
| 277 |
|
| 278 |
/** |
| 279 |
* Initialize a specific SINGLE pricing slider. (Revisited Version) |
| 280 |
* @param {jQuery} sliderWrapper The main wrapper element (.king-addons-pricing-slider). |
| 281 |
*/ |
| 282 |
function initSinglePricingSliderRevisited(sliderWrapper) { |
| 283 |
// Get elements |
| 284 |
var rangeInput = sliderWrapper.find('.king-addons-pricing-slider__range'); |
| 285 |
var priceWrapper = sliderWrapper.find('.king-addons-pricing-slider__price'); |
| 286 |
var button = sliderWrapper.find('.king-addons-pricing-slider__button'); // Could be <a> or <button> |
| 287 |
var features = sliderWrapper.find('.king-addons-pricing-slider__feature-item'); |
| 288 |
|
| 289 |
if (!rangeInput.length) { |
| 290 |
// console.error("[KA Slider] Single slider init failed: Range input not found in", sliderWrapper[0]); |
| 291 |
return; |
| 292 |
} |
| 293 |
|
| 294 |
// Get data (use attributes as fallback for robustness) |
| 295 |
var defaultValue = parseFloat(rangeInput.val()) || parseFloat(sliderWrapper.data('default-value')) || parseFloat(rangeInput.attr('min')) || 0; |
| 296 |
var priceData = sliderWrapper.data('price-data') || {}; // Get combined price settings |
| 297 |
var featuresData = sliderWrapper.data('features') || []; // Get features definitions |
| 298 |
|
| 299 |
// Correct initial value if it's outside min/max bounds |
| 300 |
var minValue = parseFloat(rangeInput.attr('min')) || 0; |
| 301 |
var maxValue = parseFloat(rangeInput.attr('max')) || 100; |
| 302 |
defaultValue = Math.max(minValue, Math.min(maxValue, defaultValue)); |
| 303 |
if (parseFloat(rangeInput.val()) !== defaultValue) { |
| 304 |
rangeInput.val(defaultValue); // Ensure input value matches calculated default |
| 305 |
} |
| 306 |
|
| 307 |
/** |
| 308 |
* Updates the price display, button link (if applicable), and features for the single slider. |
| 309 |
*/ |
| 310 |
function updateDisplay() { |
| 311 |
var value = parseFloat(rangeInput.val()); // Get current value from input |
| 312 |
var price = calculatePrice(value, priceData); // Use shared function |
| 313 |
var new_price_html = formatPriceHTML(price, priceData); // Use shared function |
| 314 |
|
| 315 |
if (priceWrapper.length) { |
| 316 |
priceWrapper.html(new_price_html); |
| 317 |
} |
| 318 |
|
| 319 |
// Update button URL only if it's a link (<a> tag) |
| 320 |
if (button.length && button.is('a')) { |
| 321 |
var url = button.attr('href'); |
| 322 |
// Check if href exists and is not just '#' or empty |
| 323 |
if (url && url !== '#') { |
| 324 |
try { |
| 325 |
var urlParts = url.split('?'); |
| 326 |
var baseUrl = urlParts[0]; |
| 327 |
var params = new URLSearchParams(urlParts.length > 1 ? urlParts[1] : ''); |
| 328 |
params.set('price', parseFloat(price).toFixed(priceData.decimals || 2)); // Use decimals from data |
| 329 |
button.attr('href', baseUrl + '?' + params.toString()); |
| 330 |
} catch (e) { |
| 331 |
// console.error("[KA Slider] Error updating button URL:", e); |
| 332 |
// Potentially invalid URL, leave it as is |
| 333 |
} |
| 334 |
} |
| 335 |
} |
| 336 |
|
| 337 |
updateFeatures(value, features, featuresData); // Update icons |
| 338 |
|
| 339 |
// --- Add dynamic class update for feature list items --- START |
| 340 |
if (features.length) { |
| 341 |
features.each(function() { |
| 342 |
var item = $(this); |
| 343 |
var minValue = parseFloat(item.data('min-value')); // Get minimum value from data-attribute |
| 344 |
var isIncluded = value >= minValue; |
| 345 |
|
| 346 |
// Remove both classes before adding the correct one |
| 347 |
item.removeClass('king-addons-feature-included king-addons-feature-excluded'); |
| 348 |
|
| 349 |
if (isIncluded) { |
| 350 |
item.addClass('king-addons-feature-included'); |
| 351 |
} else { |
| 352 |
item.addClass('king-addons-feature-excluded'); |
| 353 |
} |
| 354 |
}); |
| 355 |
} |
| 356 |
// --- Add dynamic class update for feature list items --- END |
| 357 |
} |
| 358 |
|
| 359 |
// --- Initialization --- |
| 360 |
sharedUpdateSliderUI(sliderWrapper, defaultValue); // Initial UI positioning |
| 361 |
updateDisplay(); // Initial price, features, button link update |
| 362 |
|
| 363 |
// --- Event Listener --- |
| 364 |
// Ensure previous listeners are removed before adding new ones (important for editor) |
| 365 |
rangeInput.off('.pricingSlider').on('input.pricingSlider change.pricingSlider', function() { |
| 366 |
var value = parseFloat($(this).val()); |
| 367 |
sharedUpdateSliderUI(sliderWrapper, value); // Update slider UI visuals |
| 368 |
updateDisplay(); // Update price, button, features based on new value |
| 369 |
}); |
| 370 |
} |
| 371 |
|
| 372 |
/** |
| 373 |
* Initialize MULTIPLE pricing sliders within a container. (Revisited Version) |
| 374 |
* @param {jQuery} slidersContainer The main wrapper element (.king-addons-pricing-sliders). |
| 375 |
*/ |
| 376 |
function initMultiplePricingSlidersRevisited(slidersContainer) { |
| 377 |
// Get common elements and data for the whole group |
| 378 |
var priceData = slidersContainer.data('price-data') || {}; // Combined price display settings |
| 379 |
var featuresData = slidersContainer.data('features') || []; // Combined features definitions |
| 380 |
var priceWrapper = slidersContainer.find('.king-addons-pricing-slider__price'); // The single price display for the group |
| 381 |
var featuresList = slidersContainer.find('.king-addons-pricing-slider__feature-list'); // Container for features |
| 382 |
var button = slidersContainer.find('.king-addons-pricing-slider__button'); // Combined button (link or WC) |
| 383 |
var addToCartButton = slidersContainer.find('.king-addons-pricing-slider__add-to-cart'); // Specific WC button |
| 384 |
var individualSliders = slidersContainer.find('.king-addons-single-slider'); // Wrappers for each slider |
| 385 |
var allSlidersData = slidersContainer.data('sliders') || []; // Array of settings for each slider (from repeater) |
| 386 |
|
| 387 |
if (!individualSliders.length) { |
| 388 |
// console.error("[KA Slider] Multi-slider init failed: No individual sliders found in", slidersContainer[0]); |
| 389 |
return; |
| 390 |
} |
| 391 |
if (allSlidersData.length !== individualSliders.length) { |
| 392 |
// console.warn("[KA Slider] Mismatch between slider data count and slider element count."); |
| 393 |
// Attempt to continue, but calculations might be off |
| 394 |
} |
| 395 |
|
| 396 |
/** |
| 397 |
* Calculates the combined weighted value/price for all sliders in the group. |
| 398 |
* @returns {number} The final calculated price. |
| 399 |
*/ |
| 400 |
function calculateCombinedPriceForMulti() { |
| 401 |
var combinedValue = 0; |
| 402 |
var totalWeight = 0; |
| 403 |
|
| 404 |
individualSliders.each(function(index) { |
| 405 |
var singleSliderWrapper = $(this); |
| 406 |
var rangeInput = singleSliderWrapper.find('.king-addons-pricing-slider__range'); |
| 407 |
if (!rangeInput.length) return; // Skip if input not found |
| 408 |
|
| 409 |
var value = parseFloat(rangeInput.val()); |
| 410 |
// Get weight from the corresponding data object, default to 1 if missing or invalid |
| 411 |
var weight = (allSlidersData[index] && typeof allSlidersData[index].weight !== 'undefined' && !isNaN(parseFloat(allSlidersData[index].weight))) |
| 412 |
? parseFloat(allSlidersData[index].weight) |
| 413 |
: 1; |
| 414 |
|
| 415 |
combinedValue += value * weight; |
| 416 |
totalWeight += weight; |
| 417 |
}); |
| 418 |
|
| 419 |
// Avoid division by zero if totalWeight is 0 |
| 420 |
var averageValue = (totalWeight > 0) ? (combinedValue / totalWeight) : 0; |
| 421 |
|
| 422 |
// Now calculate the final price based on the combined/averaged value using the group's price settings |
| 423 |
return calculatePrice(averageValue, priceData); // Use shared function |
| 424 |
} |
| 425 |
|
| 426 |
/** |
| 427 |
* Updates the combined price display, features list, and button(s) for the group. |
| 428 |
*/ |
| 429 |
function updateCombinedDisplayForMulti() { |
| 430 |
var finalPrice = calculateCombinedPriceForMulti(); // Use the final calculated price/value for feature check |
| 431 |
var new_price_html = formatPriceHTML(finalPrice, priceData); // Use shared function |
| 432 |
|
| 433 |
if (priceWrapper.length) { |
| 434 |
priceWrapper.html(new_price_html); |
| 435 |
} |
| 436 |
|
| 437 |
// Update features based on the final calculated price/value |
| 438 |
if (featuresList.length) { |
| 439 |
var featureItems = featuresList.find('.king-addons-pricing-slider__feature-item'); |
| 440 |
updateFeatures(finalPrice, featureItems, featuresData); // Update icons based on final price |
| 441 |
|
| 442 |
// --- Add dynamic class update for feature list items (Multi-Slider) --- START |
| 443 |
featureItems.each(function() { |
| 444 |
var item = $(this); |
| 445 |
var minValue = parseFloat(item.data('min-value')); |
| 446 |
// Use the final calculated price/value to determine inclusion for the combined list |
| 447 |
var isIncluded = finalPrice >= minValue; |
| 448 |
|
| 449 |
item.removeClass('king-addons-feature-included king-addons-feature-excluded'); |
| 450 |
|
| 451 |
if (isIncluded) { |
| 452 |
item.addClass('king-addons-feature-included'); |
| 453 |
} else { |
| 454 |
item.addClass('king-addons-feature-excluded'); |
| 455 |
} |
| 456 |
}); |
| 457 |
// --- Add dynamic class update for feature list items (Multi-Slider) --- END |
| 458 |
} |
| 459 |
|
| 460 |
// Update standard button link (if it's an <a> tag) |
| 461 |
if (button.length && button.is('a')) { |
| 462 |
var url = button.attr('href'); |
| 463 |
if (url && url !== '#') { |
| 464 |
try { |
| 465 |
var urlParts = url.split('?'); |
| 466 |
var baseUrl = urlParts[0]; |
| 467 |
var params = new URLSearchParams(urlParts.length > 1 ? urlParts[1] : ''); |
| 468 |
params.set('price', parseFloat(finalPrice).toFixed(priceData.decimals || 2)); |
| 469 |
button.attr('href', baseUrl + '?' + params.toString()); |
| 470 |
} catch(e) { |
| 471 |
// console.error("[KA Slider] Error updating multi-slider button URL:", e); |
| 472 |
} |
| 473 |
} |
| 474 |
} |
| 475 |
// Update WooCommerce button data attribute (if exists) |
| 476 |
if (addToCartButton.length) { |
| 477 |
addToCartButton.data('price', finalPrice); // Store calculated price for potential AJAX use |
| 478 |
addToCartButton.attr('data-price', finalPrice); // Also set attribute for easier debugging/selection |
| 479 |
} |
| 480 |
} |
| 481 |
|
| 482 |
// --- Initialization --- |
| 483 |
// Initialize UI for each individual slider |
| 484 |
individualSliders.each(function(index) { |
| 485 |
var singleSliderWrapper = $(this); |
| 486 |
var rangeInput = singleSliderWrapper.find('.king-addons-pricing-slider__range'); |
| 487 |
if (!rangeInput.length) return; // Skip if no input |
| 488 |
|
| 489 |
var minValue = parseFloat(rangeInput.attr('min')) || 0; |
| 490 |
var maxValue = parseFloat(rangeInput.attr('max')) || 100; |
| 491 |
// Use default value from data if available, otherwise from input, clamped |
| 492 |
var defaultValue = (allSlidersData[index] && typeof allSlidersData[index].default_value !== 'undefined') |
| 493 |
? parseFloat(allSlidersData[index].default_value) |
| 494 |
: parseFloat(rangeInput.val()); |
| 495 |
defaultValue = Math.max(minValue, Math.min(maxValue, defaultValue || minValue)); |
| 496 |
|
| 497 |
if (parseFloat(rangeInput.val()) !== defaultValue) { |
| 498 |
rangeInput.val(defaultValue); // Set initial value correctly |
| 499 |
} |
| 500 |
sharedUpdateSliderUI(singleSliderWrapper, defaultValue); // Use shared function |
| 501 |
}); |
| 502 |
// Update the combined display based on initial values |
| 503 |
updateCombinedDisplayForMulti(); |
| 504 |
|
| 505 |
// --- Event Listener (Delegated) --- |
| 506 |
// Remove previous listeners first |
| 507 |
slidersContainer.off('.pricingSlider', '.king-addons-pricing-slider__range'); |
| 508 |
// Add new delegated listener |
| 509 |
slidersContainer.on('input.pricingSlider change.pricingSlider', '.king-addons-pricing-slider__range', function() { |
| 510 |
var rangeInput = $(this); // The input that triggered the event |
| 511 |
var singleSliderWrapper = rangeInput.closest('.king-addons-single-slider'); |
| 512 |
var value = parseFloat(rangeInput.val()); |
| 513 |
|
| 514 |
// Log for debugging multi-slider events |
| 515 |
// console.log('[KA Slider] Multi-Slider Input Event Fired:', { |
| 516 |
// value: value, |
| 517 |
// targetSliderWrapper: singleSliderWrapper.length ? singleSliderWrapper[0] : 'Not Found', |
| 518 |
// eventTarget: rangeInput[0] |
| 519 |
// }); |
| 520 |
|
| 521 |
if (!singleSliderWrapper.length) { |
| 522 |
// console.error('[KA Slider] Could not find .king-addons-single-slider parent for', rangeInput[0]); |
| 523 |
return; |
| 524 |
} |
| 525 |
|
| 526 |
sharedUpdateSliderUI(singleSliderWrapper, value); // Update the UI of the slider that changed |
| 527 |
updateCombinedDisplayForMulti(); // Recalculate and update the combined price/features |
| 528 |
}); |
| 529 |
|
| 530 |
// --- WooCommerce Handler Placeholder --- |
| 531 |
if (addToCartButton.length) { |
| 532 |
addToCartButton.off('click.wcAddToCart').on('click.wcAddToCart', function(e) { |
| 533 |
e.preventDefault(); |
| 534 |
var $button = $(this); |
| 535 |
|
| 536 |
// --- DEBUGGING START --- |
| 537 |
// console.log('[KA Slider] Add to Cart clicked. Localized vars:', typeof king_addons_slider_vars !== 'undefined' ? king_addons_slider_vars : 'Not Defined'); |
| 538 |
// --- DEBUGGING END --- |
| 539 |
|
| 540 |
var price = $button.data('price') || calculateCombinedPriceForMulti(); // Get price |
| 541 |
var productId = $button.data('product-id'); |
| 542 |
var productType = $button.data('product-type') || 'dynamic'; // Get product type |
| 543 |
var autoQuantity = $button.data('auto-quantity') === 'yes'; // Check if auto quantity is enabled |
| 544 |
var useAsBudget = $button.data('use-budget') === 'yes'; // Check if using slider as budget |
| 545 |
|
| 546 |
var quantity = 1; // Default quantity |
| 547 |
|
| 548 |
// If auto quantity is enabled, try to get the value from the relevant slider |
| 549 |
// NOTE: This assumes auto_quantity makes sense primarily with a single slider scenario. |
| 550 |
// If used with multiple, logic might need refinement (e.g., use combined value?). |
| 551 |
if (autoQuantity) { |
| 552 |
// Find the slider input within the same container as the button |
| 553 |
// This works for single slider and might need adjustment for complex multi-slider quantity logic |
| 554 |
var $sliderInput = $button.closest('.king-addons-pricing-slider, .king-addons-pricing-sliders').find('.king-addons-pricing-slider__range').first(); // Get the first slider in the context |
| 555 |
if ($sliderInput.length) { |
| 556 |
quantity = parseInt($sliderInput.val()) || 1; |
| 557 |
} else { |
| 558 |
// console.warn('[KA Slider] Could not find slider input for auto quantity.'); |
| 559 |
} |
| 560 |
quantity = Math.max(1, quantity); // Ensure quantity is at least 1 |
| 561 |
} |
| 562 |
|
| 563 |
if (!productId && productType === 'specific') { // Only require product ID for specific type |
| 564 |
// Maybe show a user-facing error? |
| 565 |
// Clear any existing notices or links |
| 566 |
$button.siblings('.king-addons-slider-notice, .king-addons-slider-view-cart').remove(); |
| 567 |
var errorMsg = $('<span class="king-addons-slider-notice error">Missing Product ID.</span>').insertAfter($button); |
| 568 |
setTimeout(function(){ errorMsg.fadeOut(function(){ $(this).remove(); }); }, 5000); |
| 569 |
return; |
| 570 |
} |
| 571 |
|
| 572 |
// Basic AJAX add-to-cart implementation (needs refinement) |
| 573 |
// Consider adding loading state to button |
| 574 |
$button.addClass('loading'); |
| 575 |
// Clear any existing notices or links before making the request |
| 576 |
$button.siblings('.king-addons-slider-notice, .king-addons-slider-view-cart').remove(); |
| 577 |
|
| 578 |
$.ajax({ |
| 579 |
type: 'POST', |
| 580 |
url: king_addons_slider_vars.ajax_url, // Make sure this variable is localized |
| 581 |
data: { |
| 582 |
action: 'king_addons_add_to_cart', // PHP action hook |
| 583 |
nonce: $button.data('nonce'), // Get nonce from button data attribute |
| 584 |
product_id: productId, |
| 585 |
price: price, // Send the calculated price |
| 586 |
product_type: productType, |
| 587 |
quantity: quantity, |
| 588 |
use_as_budget: useAsBudget ? 'true' : 'false', // Send as string 'true'/'false' |
| 589 |
auto_quantity: autoQuantity ? 'true' : 'false' // Send as string 'true'/'false' |
| 590 |
}, |
| 591 |
success: function(response) { |
| 592 |
$button.removeClass('loading'); |
| 593 |
|
| 594 |
// Find the target container for notifications based on settings |
| 595 |
var notificationsContainer; |
| 596 |
var notificationPosition = (priceData && priceData.notification_position) ? priceData.notification_position : 'after_button'; |
| 597 |
|
| 598 |
// Remove existing notifications |
| 599 |
$button.closest('.king-addons-pricing-slider, .king-addons-pricing-sliders') |
| 600 |
.find('.king-addons-slider-notice, .king-addons-slider-view-cart').remove(); |
| 601 |
|
| 602 |
switch(notificationPosition) { |
| 603 |
case 'before_button': |
| 604 |
notificationsContainer = $button.parent(); |
| 605 |
// Insert before button |
| 606 |
if (response.success) { |
| 607 |
// console.log('[KA Slider] Product added to cart:', response.data); |
| 608 |
// Trigger WooCommerce added_to_cart event for themes/plugins to hook into |
| 609 |
$(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, $button]); |
| 610 |
|
| 611 |
var successMsg = $('<span class="king-addons-slider-notice success">' + (response.data.message || 'Added to cart!') + '</span>'); |
| 612 |
successMsg.insertBefore($button); |
| 613 |
|
| 614 |
if (response.data.cart_url) { |
| 615 |
var viewCartText = (typeof king_addons_slider_vars !== 'undefined' && king_addons_slider_vars.view_cart_text) |
| 616 |
? king_addons_slider_vars.view_cart_text : 'View Cart'; |
| 617 |
var viewCartLink = $('<a href="' + response.data.cart_url + '" class="king-addons-slider-view-cart">' + viewCartText + '</a>'); |
| 618 |
viewCartLink.insertBefore($button); |
| 619 |
|
| 620 |
setTimeout(function(){ |
| 621 |
successMsg.fadeOut(function(){ $(this).remove(); }); |
| 622 |
viewCartLink.fadeOut(function(){ $(this).remove(); }); |
| 623 |
}, 5000); |
| 624 |
} else { |
| 625 |
setTimeout(function(){ successMsg.fadeOut(function(){ $(this).remove(); }); }, 3000); |
| 626 |
} |
| 627 |
} else { |
| 628 |
var errorMessage = 'Could not add product to cart. Please try again.'; |
| 629 |
if (response.data && response.data.error_code === 'budget_too_low') { |
| 630 |
var templateMessage = priceData.budget_too_low_message || 'Your selected budget is too low. Please increase the budget to at least {product_price}.'; |
| 631 |
var productPrice = response.data.product_price || ''; |
| 632 |
errorMessage = templateMessage.replace('{product_price}', productPrice); |
| 633 |
} else if (response.data && response.data.message) { |
| 634 |
errorMessage = response.data.message; |
| 635 |
} |
| 636 |
|
| 637 |
var errorMsg = $('<span class="king-addons-slider-notice error">' + errorMessage + '</span>'); |
| 638 |
errorMsg.insertBefore($button); |
| 639 |
setTimeout(function(){ errorMsg.fadeOut(function(){ $(this).remove(); }); }, 5000); |
| 640 |
} |
| 641 |
break; |
| 642 |
|
| 643 |
case 'after_price': |
| 644 |
var priceElement = $button.closest('.king-addons-pricing-slider, .king-addons-pricing-sliders') |
| 645 |
.find('.king-addons-pricing-slider__price'); |
| 646 |
if (priceElement.length) { |
| 647 |
if (response.success) { |
| 648 |
// console.log('[KA Slider] Product added to cart:', response.data); |
| 649 |
// Trigger WooCommerce added_to_cart event for themes/plugins to hook into |
| 650 |
$(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, $button]); |
| 651 |
|
| 652 |
var successMsg = $('<span class="king-addons-slider-notice success">' + (response.data.message || 'Added to cart!') + '</span>'); |
| 653 |
successMsg.insertAfter(priceElement); |
| 654 |
|
| 655 |
if (response.data.cart_url) { |
| 656 |
var viewCartText = (typeof king_addons_slider_vars !== 'undefined' && king_addons_slider_vars.view_cart_text) |
| 657 |
? king_addons_slider_vars.view_cart_text : 'View Cart'; |
| 658 |
var viewCartLink = $('<a href="' + response.data.cart_url + '" class="king-addons-slider-view-cart">' + viewCartText + '</a>'); |
| 659 |
viewCartLink.insertAfter(successMsg); |
| 660 |
|
| 661 |
setTimeout(function(){ |
| 662 |
successMsg.fadeOut(function(){ $(this).remove(); }); |
| 663 |
viewCartLink.fadeOut(function(){ $(this).remove(); }); |
| 664 |
}, 5000); |
| 665 |
} else { |
| 666 |
setTimeout(function(){ successMsg.fadeOut(function(){ $(this).remove(); }); }, 3000); |
| 667 |
} |
| 668 |
} else { |
| 669 |
var errorMessage = 'Could not add product to cart. Please try again.'; |
| 670 |
if (response.data && response.data.error_code === 'budget_too_low') { |
| 671 |
var templateMessage = priceData.budget_too_low_message || 'Your selected budget is too low. Please increase the budget to at least {product_price}.'; |
| 672 |
var productPrice = response.data.product_price || ''; |
| 673 |
errorMessage = templateMessage.replace('{product_price}', productPrice); |
| 674 |
} else if (response.data && response.data.message) { |
| 675 |
errorMessage = response.data.message; |
| 676 |
} |
| 677 |
|
| 678 |
var errorMsg = $('<span class="king-addons-slider-notice error">' + errorMessage + '</span>'); |
| 679 |
errorMsg.insertAfter(priceElement); |
| 680 |
setTimeout(function(){ errorMsg.fadeOut(function(){ $(this).remove(); }); }, 5000); |
| 681 |
} |
| 682 |
} else { |
| 683 |
// Fallback to after button if price element not found |
| 684 |
notificationPosition = 'after_button'; |
| 685 |
} |
| 686 |
break; |
| 687 |
|
| 688 |
case 'in_container': |
| 689 |
var customContainer = $button.closest('.king-addons-pricing-slider, .king-addons-pricing-sliders') |
| 690 |
.find('.king-addons-notification-container'); |
| 691 |
if (customContainer.length) { |
| 692 |
customContainer.empty(); // Clear previous notifications |
| 693 |
|
| 694 |
if (response.success) { |
| 695 |
// console.log('[KA Slider] Product added to cart:', response.data); |
| 696 |
// Trigger WooCommerce added_to_cart event for themes/plugins to hook into |
| 697 |
$(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, $button]); |
| 698 |
|
| 699 |
var successMsg = $('<span class="king-addons-slider-notice success">' + (response.data.message || 'Added to cart!') + '</span>'); |
| 700 |
customContainer.append(successMsg); |
| 701 |
|
| 702 |
if (response.data.cart_url) { |
| 703 |
var viewCartText = (typeof king_addons_slider_vars !== 'undefined' && king_addons_slider_vars.view_cart_text) |
| 704 |
? king_addons_slider_vars.view_cart_text : 'View Cart'; |
| 705 |
var viewCartLink = $('<a href="' + response.data.cart_url + '" class="king-addons-slider-view-cart">' + viewCartText + '</a>'); |
| 706 |
customContainer.append(viewCartLink); |
| 707 |
|
| 708 |
setTimeout(function(){ |
| 709 |
successMsg.fadeOut(function(){ $(this).remove(); }); |
| 710 |
viewCartLink.fadeOut(function(){ $(this).remove(); }); |
| 711 |
}, 5000); |
| 712 |
} else { |
| 713 |
setTimeout(function(){ successMsg.fadeOut(function(){ $(this).remove(); }); }, 3000); |
| 714 |
} |
| 715 |
} else { |
| 716 |
var errorMessage = 'Could not add product to cart. Please try again.'; |
| 717 |
if (response.data && response.data.error_code === 'budget_too_low') { |
| 718 |
var templateMessage = priceData.budget_too_low_message || 'Your selected budget is too low. Please increase the budget to at least {product_price}.'; |
| 719 |
var productPrice = response.data.product_price || ''; |
| 720 |
errorMessage = templateMessage.replace('{product_price}', productPrice); |
| 721 |
} else if (response.data && response.data.message) { |
| 722 |
errorMessage = response.data.message; |
| 723 |
} |
| 724 |
|
| 725 |
var errorMsg = $('<span class="king-addons-slider-notice error">' + errorMessage + '</span>'); |
| 726 |
customContainer.append(errorMsg); |
| 727 |
setTimeout(function(){ errorMsg.fadeOut(function(){ $(this).remove(); }); }, 5000); |
| 728 |
} |
| 729 |
} else { |
| 730 |
// Fallback to after button if custom container not found |
| 731 |
notificationPosition = 'after_button'; |
| 732 |
} |
| 733 |
break; |
| 734 |
|
| 735 |
case 'after_button': |
| 736 |
default: |
| 737 |
// This is the original behavior - place notifications after the button |
| 738 |
if (response.success) { |
| 739 |
// console.log('[KA Slider] Product added to cart:', response.data); |
| 740 |
// Trigger WooCommerce added_to_cart event for themes/plugins to hook into |
| 741 |
$(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, $button]); |
| 742 |
|
| 743 |
var successMsg = $('<span class="king-addons-slider-notice success">' + (response.data.message || 'Added to cart!') + '</span>'); |
| 744 |
successMsg.insertAfter($button); |
| 745 |
|
| 746 |
if (response.data.cart_url) { |
| 747 |
var viewCartText = (typeof king_addons_slider_vars !== 'undefined' && king_addons_slider_vars.view_cart_text) |
| 748 |
? king_addons_slider_vars.view_cart_text : 'View Cart'; |
| 749 |
var viewCartLink = $('<a href="' + response.data.cart_url + '" class="king-addons-slider-view-cart">' + viewCartText + '</a>'); |
| 750 |
viewCartLink.insertAfter(successMsg); |
| 751 |
|
| 752 |
setTimeout(function(){ |
| 753 |
successMsg.fadeOut(function(){ $(this).remove(); }); |
| 754 |
viewCartLink.fadeOut(function(){ $(this).remove(); }); |
| 755 |
}, 5000); |
| 756 |
} else { |
| 757 |
setTimeout(function(){ successMsg.fadeOut(function(){ $(this).remove(); }); }, 3000); |
| 758 |
} |
| 759 |
} else { |
| 760 |
var errorMessage = 'Could not add product to cart. Please try again.'; |
| 761 |
// console.error('[KA Slider] Error adding to cart:', response.data); |
| 762 |
|
| 763 |
if (response.data && response.data.error_code === 'budget_too_low') { |
| 764 |
var templateMessage = priceData.budget_too_low_message || 'Your selected budget is too low. Please increase the budget to at least {product_price}.'; |
| 765 |
var productPrice = response.data.product_price || ''; |
| 766 |
errorMessage = templateMessage.replace('{product_price}', productPrice); |
| 767 |
} else if (response.data && response.data.message) { |
| 768 |
errorMessage = response.data.message; |
| 769 |
} |
| 770 |
|
| 771 |
var errorMsg = $('<span class="king-addons-slider-notice error">' + errorMessage + '</span>'); |
| 772 |
errorMsg.insertAfter($button); |
| 773 |
setTimeout(function(){ errorMsg.fadeOut(function(){ $(this).remove(); }); }, 5000); |
| 774 |
} |
| 775 |
break; |
| 776 |
} |
| 777 |
}, |
| 778 |
error: function(jqXHR, textStatus, errorThrown) { |
| 779 |
$button.removeClass('loading'); |
| 780 |
// console.error('[KA Slider] AJAX Error:', textStatus, errorThrown); |
| 781 |
// Show generic user-friendly error for AJAX failures |
| 782 |
var errorMsg = $('<span class="king-addons-slider-notice error">An error occurred. Please try again later.</span>').insertAfter($button); |
| 783 |
setTimeout(function(){ errorMsg.fadeOut(function(){ $(this).remove(); }); }, 5000); |
| 784 |
} |
| 785 |
}); |
| 786 |
}); |
| 787 |
} |
| 788 |
} |
| 789 |
|
| 790 |
// --- Elementor Hook --- (Handles both Editor and Frontend) |
| 791 |
$(window).on('elementor/frontend/init', function() { |
| 792 |
var initAction = function($scope) { |
| 793 |
// Use $scope if provided (in editor), otherwise use document context (frontend) |
| 794 |
var context = $scope ? $scope : $(document); |
| 795 |
|
| 796 |
// Initialize Single Sliders |
| 797 |
// Find only direct .king-addons-pricing-slider that are NOT .king-addons-pricing-sliders containers |
| 798 |
context.find('.king-addons-pricing-slider:not(.king-addons-pricing-sliders)').each(function() { |
| 799 |
var sliderInstance = $(this); |
| 800 |
// Check if already initialized (e.g., by multiple init calls in editor) |
| 801 |
if (!sliderInstance.data('ka-slider-initialized')) { |
| 802 |
initSinglePricingSliderRevisited(sliderInstance); |
| 803 |
sliderInstance.data('ka-slider-initialized', true); |
| 804 |
} else { |
| 805 |
// console.log('[KA Slider] Single slider already initialized, skipping:', sliderInstance[0]); |
| 806 |
// Optionally re-trigger UI update if needed in editor on changes |
| 807 |
var rangeInput = sliderInstance.find('.king-addons-pricing-slider__range'); |
| 808 |
if(rangeInput.length) { |
| 809 |
sharedUpdateSliderUI(sliderInstance, parseFloat(rangeInput.val())); |
| 810 |
} |
| 811 |
} |
| 812 |
}); |
| 813 |
|
| 814 |
// Initialize Multiple Sliders Containers |
| 815 |
context.find('.king-addons-pricing-sliders').each(function() { |
| 816 |
var slidersContainer = $(this); |
| 817 |
if (!slidersContainer.data('ka-slider-initialized')) { |
| 818 |
initMultiplePricingSlidersRevisited(slidersContainer); |
| 819 |
slidersContainer.data('ka-slider-initialized', true); |
| 820 |
} else { |
| 821 |
// console.log('[KA Slider] Multi-slider container already initialized, skipping:', slidersContainer[0]); |
| 822 |
// Optionally re-trigger UI update for all children |
| 823 |
slidersContainer.find('.king-addons-single-slider').each(function() { |
| 824 |
var singleSliderWrapper = $(this); |
| 825 |
var rangeInput = singleSliderWrapper.find('.king-addons-pricing-slider__range'); |
| 826 |
if (rangeInput.length) { |
| 827 |
sharedUpdateSliderUI(singleSliderWrapper, parseFloat(rangeInput.val())); |
| 828 |
} |
| 829 |
}); |
| 830 |
// And update combined display |
| 831 |
// Need a way to call updateCombinedDisplayForMulti() here if instance already exists |
| 832 |
// For now, just re-init might be simpler, or store the update function on the element data |
| 833 |
} |
| 834 |
}); |
| 835 |
}; |
| 836 |
|
| 837 |
// --- Elementor Editor Integration --- |
| 838 |
if (typeof elementorFrontend !== 'undefined' && elementorFrontend.isEditMode()) { |
| 839 |
elementorFrontend.hooks.addAction('frontend/element_ready/king-addons-pricing-slider.default', function($scope) { |
| 840 |
// Use timeout to allow elements and data attributes to be fully rendered by Elementor |
| 841 |
// console.log('[KA Slider] Elementor element_ready hook fired for scope:', $scope[0]); |
| 842 |
setTimeout(function() { |
| 843 |
// Clear initialized flag before re-init to handle widget updates |
| 844 |
$scope.find('.king-addons-pricing-slider, .king-addons-pricing-sliders').removeData('ka-slider-initialized'); |
| 845 |
initAction($scope); |
| 846 |
}, 150); // Slightly longer timeout for editor stability |
| 847 |
}); |
| 848 |
} else { |
| 849 |
// --- Frontend Initialization --- |
| 850 |
// Run on document ready for frontend |
| 851 |
$(document).ready(function() { |
| 852 |
initAction(); |
| 853 |
}); |
| 854 |
} |
| 855 |
}); |
| 856 |
|
| 857 |
})(jQuery); |
| 858 |
// --- REMOVE OLD FUNCTIONS --- |
| 859 |
/* |
| 860 |
// Old function, replaced by initSinglePricingSliderRevisited |
| 861 |
function initSinglePricingSlider(sliderWrapper) { |
| 862 |
// ... implementation removed ... |
| 863 |
} |
| 864 |
|
| 865 |
// Old function, replaced by initMultiplePricingSlidersRevisited |
| 866 |
function initMultiplePricingSliders(slidersContainer) { |
| 867 |
// ... implementation removed ... |
| 868 |
} |
| 869 |
*/ |