1/*global wc_add_to_cart_variation_params */ 2;(function ( $, window, document, undefined ) { 3 /** 4 * VariationForm class which handles variation forms and attributes. 5 */ 6 var VariationForm = function( $form ) { 7 var self = this; 8 9 self.$form = $form; 10 self.$attributeFields = $form.find( '.variations select' ); 11 self.$singleVariation = $form.find( '.single_variation' ); 12 self.$singleVariationWrap = $form.find( '.single_variation_wrap' ); 13 self.$resetVariations = $form.find( '.reset_variations' ); 14 self.$product = $form.closest( '.product' ); 15 self.variationData = $form.data( 'product_variations' ); 16 self.useAjax = false === self.variationData; 17 self.xhr = false; 18 self.loading = true; 19 20 // Initial state. 21 self.$singleVariationWrap.show(); 22 self.$form.off( '.wc-variation-form' ); 23 24 // Methods. 25 self.getChosenAttributes = self.getChosenAttributes.bind( self ); 26 self.findMatchingVariations = self.findMatchingVariations.bind( self ); 27 self.isMatch = self.isMatch.bind( self ); 28 self.toggleResetLink = self.toggleResetLink.bind( self ); 29 30 // Events. 31 $form.on( 'click.wc-variation-form', '.reset_variations', { variationForm: self }, self.onReset ); 32 $form.on( 'reload_product_variations', { variationForm: self }, self.onReload ); 33 $form.on( 'hide_variation', { variationForm: self }, self.onHide ); 34 $form.on( 'show_variation', { variationForm: self }, self.onShow ); 35 $form.on( 'click', '.single_add_to_cart_button', { variationForm: self }, self.onAddToCart ); 36 $form.on( 'reset_data', { variationForm: self }, self.onResetDisplayedVariation ); 37 $form.on( 'reset_image', { variationForm: self }, self.onResetImage ); 38 $form.on( 'change.wc-variation-form', '.variations select', { variationForm: self }, self.onChange ); 39 $form.on( 'found_variation.wc-variation-form', { variationForm: self }, self.onFoundVariation ); 40 $form.on( 'check_variations.wc-variation-form', { variationForm: self }, self.onFindVariation ); 41 $form.on( 'update_variation_values.wc-variation-form', { variationForm: self }, self.onUpdateAttributes ); 42 43 // Init after gallery. 44 setTimeout( function() { 45 $form.trigger( 'check_variations' ); 46 $form.trigger( 'wc_variation_form' ); 47 self.loading = false; 48 }, 100 ); 49 }; 50 51 /** 52 * Reset all fields. 53 */ 54 VariationForm.prototype.onReset = function( event ) { 55 event.preventDefault(); 56 event.data.variationForm.$attributeFields.val( '' ).change(); 57 event.data.variationForm.$form.trigger( 'reset_data' ); 58 }; 59 60 /** 61 * Reload variation data from the DOM. 62 */ 63 VariationForm.prototype.onReload = function( event ) { 64 var form = event.data.variationForm; 65 form.variationData = form.$form.data( 'product_variations' ); 66 form.useAjax = false === form.variationData; 67 form.$form.trigger( 'check_variations' ); 68 }; 69 70 /** 71 * When a variation is hidden. 72 */ 73 VariationForm.prototype.onHide = function( event ) { 74 event.preventDefault(); 75 event.data.variationForm.$form.find( '.single_add_to_cart_button' ).removeClass( 'wc-variation-is-unavailable' ).addClass( 'disabled-variation-needed wc-variation-selection-needed' ); 76 event.data.variationForm.$form.find( '.woocommerce-variation-add-to-cart' ).removeClass( 'woocommerce-variation-add-to-cart-enabled' ).addClass( 'woocommerce-variation-add-to-cart-disabled' ); 77 }; 78 79 /** 80 * When a variation is shown.
81 */ 82 VariationForm.prototype.onShow = function( event, variation, purchasable ) { 83 event.preventDefault(); 84 if ( purchasable ) { 85 event.data.variationForm.$form.find( '.single_add_to_cart_button' ).removeClass( 'disabled-variation-needed wc-variation-selection-needed wc-variation-is-unavailable' ); 86 event.data.variationForm.$form.find( '.woocommerce-variation-add-to-cart' ).removeClass( 'woocommerce-variation-add-to-cart-disabled' ).addClass( 'woocommerce-variation-add-to-cart-enabled' ); 87 } else { 88 event.data.variationForm.$form.find( '.single_add_to_cart_button' ).removeClass( 'wc-variation-selection-needed' ).addClass( 'disabled wc-variation-is-unavailable' ); 89 event.data.variationForm.$form.find( '.woocommerce-variation-add-to-cart' ).removeClass( 'woocommerce-variation-add-to-cart-enabled' ).addClass( 'woocommerce-variation-add-to-cart-disabled' ); 90 } 91 92 // If present, the media element library needs initialized on the variation description. 93 if ( wp.mediaelement ) { 94 event.data.variationForm.$form.find( '.wp-audio-shortcode, .wp-video-shortcode' ) 95 .not( '.mejs-container' ) 96 .filter( 97 function () { 98 return ! $( this ).parent().hasClass( 'mejs-mediaelement' ); 99 } 100 ) 101 .mediaelementplayer( wp.mediaelement.settings ); 102 } 103 }; 104 105 /** 106 * When the cart button is pressed. 107 */ 108 VariationForm.prototype.onAddToCart = function( event ) { 109 if ( $( this ).is('.disabled') ) { 110 event.preventDefault(); 111 112 if ( $( this ).is('.wc-variation-is-unavailable') ) { 113 window.alert( wc_add_to_cart_variation_params.i18n_unavailable_text ); 114 } else if ( $( this ).is('.wc-variation-selection-needed') ) { 115 window.alert( wc_add_to_cart_variation_params.i18n_make_a_selection_text ); 116 } 117 } 118 119 if ( $( this ).is('.disabled-variation-needed') ) { 120 event.preventDefault(); 121 var variation = $( 'table.variations select' ); 122 123 if ( $( this ).is('.wc-variation-selection-needed') ) { 124 if ( variation.val() == '' ) { 125 $( '.variations select' ).addClass( 'empty-variation-field' ) 126 $(".empty-variation-wrap").css('display', 'block') 127 } else { 128 $(".empty-variation-wrap").css('display', 'none') 129 $( '.variations select' ).removeClass( 'empty-variation-field' ) 130 } 131 132 variation.prop('required',true); 133 } else { 134 variation.prop('required',false); 135 } 136 } 137 }; 138 139 /** 140 * When displayed variation data is reset. 141 */ 142 VariationForm.prototype.onResetDisplayedVariation = function( event ) { 143 var form = event.data.variationForm; 144 form.$product.find( '.product_meta' ).find( '.sku' ).wc_reset_content(); 145 form.$product.find( '.product_weight, .woocommerce-product-attributes-item--weight .woocommerce-product-attributes-item__value' ).wc_reset_content(); 146 form.$product.find( '.product_dimensions, .woocommerce-product-attributes-item--dimensions .woocommerce-product-attributes-item__value' ).wc_reset_content(); 147 form.$form.trigger( 'reset_image' ); 148 form.$singleVariation.slideUp( 200 ).trigger( 'hide_variation' ); 149 }; 150 151 /** 152 * When the product image is reset. 153 */ 154 VariationForm.prototype.onResetImage = function( event ) { 155 event.data.variationForm.$form.wc_variations_image_update( false ); 156 }; 157 158 /** 159 * Looks for matching variations for current selected attributes. 160 */ 161 VariationForm.prototype.onFindVariation = function( event ) { 162 var form = event.data.variationForm, 163 attributes = form.getChosenAttributes(), 164 currentAttributes = attributes.data; 165 166 if ( attributes.count === attributes.chosenCount ) { 167 if ( form.useAjax ) { 168 if ( form.xhr ) { 169 form.xhr.abort(); 170 } 171 form.$form.block( { message: null, overlayCSS: { background: '#fff', opacity: 0.6 } } ); 172 currentAttributes.product_id = parseInt( form.$form.data( 'product_id' ), 10 ); 173 currentAttributes.custom_data = form.$form.data( 'custom_data' ); 174 form.xhr = $.ajax( { 175 url: wc_add_to_cart_variation_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'get_variation' ), 176 type: 'POST', 177 data: currentAttributes, 178 success: function( variation ) { 179 if ( variation ) {
180 form.$form.trigger( 'found_variation', [ variation ] ); 181 } else { 182 form.$form.trigger( 'reset_data' ); 183 attributes.chosenCount = 0; 184 185 if ( ! form.loading ) { 186 form.$form.find( '.single_variation' ).after( '<p class="wc-no-matching-variations woocommerce-info">' + wc_add_to_cart_variation_params.i18n_no_matching_variations_text + '</p>' ); 187 form.$form.find( '.wc-no-matching-variations' ).slideDown( 200 ); 188 } 189 } 190 }, 191 complete: function() { 192 form.$form.unblock(); 193 } 194 } ); 195 } else { 196 form.$form.trigger( 'update_variation_values' ); 197 198 var matching_variations = form.findMatchingVariations( form.variationData, currentAttributes ), 199 variation = matching_variations.shift(); 200 201 if ( variation ) { 202 form.$form.trigger( 'found_variation', [ variation ] ); 203 } else { 204 form.$form.trigger( 'reset_data' ); 205 attributes.chosenCount = 0; 206 207 if ( ! form.loading ) { 208 form.$form.find( '.single_variation' ).after( '<p class="wc-no-matching-variations woocommerce-info">' + wc_add_to_cart_variation_params.i18n_no_matching_variations_text + '</p>' ); 209 form.$form.find( '.wc-no-matching-variations' ).slideDown( 200 ); 210 } 211 } 212 } 213 } else { 214 form.$form.trigger( 'update_variation_values' ); 215 form.$form.trigger( 'reset_data' ); 216 } 217 218 // Show reset link. 219 form.toggleResetLink( attributes.chosenCount > 0 ); 220 }; 221 222 /** 223 * Triggered when a variation has been found which matches all attributes. 224 */ 225 VariationForm.prototype.onFoundVariation = function( event, variation ) { 226 var form = event.data.variationForm, 227 $sku = form.$product.find( '.product_meta' ).find( '.sku' ), 228 $weight = form.$product.find( '.product_weight, .woocommerce-product-attributes-item--weight .woocommerce-product-attributes-item__value' ), 229 $dimensions = form.$product.find( '.product_dimensions, .woocommerce-product-attributes-item--dimensions .woocommerce-product-attributes-item__value' ), 230 $qty = form.$singleVariationWrap.find( '.quantity' ), 231 purchasable = true, 232 variation_id = '', 233 template = false, 234 $template_html = ''; 235 236 if ( variation.sku ) { 237 $sku.wc_set_content( variation.sku ); 238 } else { 239 $sku.wc_reset_content(); 240 } 241 242 if ( variation.weight ) { 243 $weight.wc_set_content( variation.weight_html ); 244 } else { 245 $weight.wc_reset_content(); 246 } 247 248 if ( variation.dimensions ) { 249 // Decode HTML entities. 250 $dimensions.wc_set_content( $.parseHTML( variation.dimensions_html )[0].data ); 251 } else { 252 $dimensions.wc_reset_content(); 253 } 254 255 form.$form.wc_variations_image_update( variation ); 256 257 if ( ! variation.variation_is_visible ) { 258 template = wp_template( 'unavailable-variation-template' ); 259 } else { 260 template = wp_template( 'variation-template' ); 261 variation_id = variation.variation_id; 262 } 263 264 $template_html = template( { 265 variation: variation 266 } ); 267 $template_html = $template_html.replace( '/*<![CDATA[*/', '' ); 268 $template_html = $template_html.replace( '/*]]>*/', '' ); 269 270 form.$singleVariation.html( $template_html );
271 form.$form.find( 'input[name="variation_id"], input.variation_id' ).val( variation.variation_id ).change(); 272 273 // Hide or show qty input 274 if ( variation.is_sold_individually === 'yes' ) { 275 $qty.find( 'input.qty' ).val( '1' ).attr( 'min', '1' ).attr( 'max', '' ); 276 $qty.hide(); 277 } else { 278 $qty.find( 'input.qty' ).attr( 'min', variation.min_qty ).attr( 'max', variation.max_qty ); 279 $qty.show(); 280 } 281 282 // Enable or disable the add to cart button 283 if ( ! variation.is_purchasable || ! variation.is_in_stock || ! variation.variation_is_visible ) { 284 purchasable = false; 285 } 286 287 // Reveal 288 if ( $.trim( form.$singleVariation.text() ) ) { 289 form.$singleVariation.slideDown( 200 ).trigger( 'show_variation', [ variation, purchasable ] ); 290 } else { 291 form.$singleVariation.show().trigger( 'show_variation', [ variation, purchasable ] ); 292 } 293 }; 294 295 /** 296 * Triggered when an attribute field changes. 297 */ 298 VariationForm.prototype.onChange = function( event ) { 299 var form = event.data.variationForm; 300 301 form.$form.find( 'input[name="variation_id"], input.variation_id' ).val( '' ).change(); 302 form.$form.find( '.wc-no-matching-variations' ).remove(); 303 304 if ( form.useAjax ) { 305 form.$form.trigger( 'check_variations' ); 306 } else { 307 form.$form.trigger( 'woocommerce_variation_select_change' ); 308 form.$form.trigger( 'check_variations' ); 309 } 310 311 // Custom event for when variation selection has been changed 312 form.$form.trigger( 'woocommerce_variation_has_changed' ); 313 }; 314 315 /** 316 * Escape quotes in a string. 317 * @param {string} string 318 * @return {string} 319 */ 320 VariationForm.prototype.addSlashes = function( string ) { 321 string = string.replace( /'/g, '\\\'' ); 322 string = string.replace( /"/g, '\\\"' ); 323 return string; 324 }; 325 326 /** 327 * Updates attributes in the DOM to show valid values. 328 */ 329 VariationForm.prototype.onUpdateAttributes = function( event ) { 330 var form = event.data.variationForm, 331 attributes = form.getChosenAttributes(), 332 currentAttributes = attributes.data; 333 334 if ( form.useAjax ) { 335 return; 336 } 337 338 // Loop through selects and disable/enable options based on selections. 339 form.$attributeFields.each( function( index, el ) { 340 var current_attr_select = $( el ), 341 current_attr_name = current_attr_select.data( 'attribute_name' ) || current_attr_select.attr( 'name' ), 342 show_option_none = $( el ).data( 'show_option_none' ), 343 option_gt_filter = ':gt(0)', 344 attached_options_count = 0, 345 new_attr_select = $( '<select/>' ), 346 selected_attr_val = current_attr_select.val() || '', 347 selected_attr_val_valid = true; 348 349 // Reference options set at first. 350 if ( ! current_attr_select.data( 'attribute_html' ) ) { 351 var refSelect = current_attr_select.clone(); 352 353 refSelect.find( 'option' ).removeAttr( 'disabled attached' ).removeAttr( 'selected' ); 354 355 current_attr_select.data( 'attribute_options', refSelect.find( 'option' + option_gt_filter ).get() ); // Legacy data attribute. 356 current_attr_select.data( 'attribute_html', refSelect.html() ); 357 } 358 359 new_attr_select.html( current_attr_select.data( 'attribute_html' ) ); 360 361 // The attribute of this select field should not be taken into account when calculating its matching variations: 362 // The constraints of this attribute are shaped by the values of the other attributes. 363 var checkAttributes = $.extend( true, {}, currentAttributes ); 364 365 checkAttributes[ current_attr_name ] = ''; 366 367 var variations = form.findMatchingVariations( form.variationData, checkAttributes ); 368 369 // Loop through variations. 370 for ( var num in variations ) { 371 if ( typeof( variations[ num ] ) !== 'undefined' ) { 372 var variationAttributes = variations[ num ].attributes; 373 374 for ( var attr_name in variationAttributes ) { 375 if ( variationAttributes.hasOwnProperty( attr_name ) ) { 376 var attr_val = variationAttributes[ attr_name ], 377 variation_active = ''; 378 379 if ( attr_name === current_attr_name ) { 380 if ( variations[ num ].variation_is_active ) { 381 variation_active = 'enabled'; 382 } 383 384 if ( attr_val ) { 385 // Decode entities. 386 attr_val = $( '<div/>' ).html( attr_val ).text(); 387 388 // Attach to matching options by value. This is done to compare 389 // TEXT values rather than any HTML entities. 390 var $option_elements = new_attr_select.find( 'option' ); 391 if ( $option_elements.length ) { 392 for (var i = 0, len = $option_elements.length; i < len; i++) { 393 var $option_element = $( $option_elements[i] ), 394 option_value = $option_element.val(); 395 396 if ( attr_val === option_value ) { 397 $option_element.addClass( 'attached ' + variation_active ); 398 break; 399 } 400 } 401 } 402 } else { 403 // Attach all apart from placeholder. 404 new_attr_select.find( 'option:gt(0)' ).addClass( 'attached ' + variation_active ); 405 } 406 } 407 } 408 } 409 } 410 } 411 412 // Count available options. 413 attached_options_count = new_attr_select.find( 'option.attached' ).length; 414 415 // Check if current selection is in attached options. 416 if ( selected_attr_val ) { 417 selected_attr_val_valid = false;
418 419 if ( 0 !== attached_options_count ) { 420 new_attr_select.find( 'option.attached.enabled' ).each( function() { 421 var option_value = $( this ).val(); 422 423 if ( selected_attr_val === option_value ) { 424 selected_attr_val_valid = true; 425 return false; // break. 426 } 427 }); 428 } 429 } 430 431 // Detach the placeholder if: 432 // - Valid options exist. 433 // - The current selection is non-empty. 434 // - The current selection is valid. 435 // - Placeholders are not set to be permanently visible. 436 if ( attached_options_count > 0 && selected_attr_val && selected_attr_val_valid && ( 'no' === show_option_none ) ) { 437 new_attr_select.find( 'option:first' ).remove(); 438 option_gt_filter = ''; 439 } 440 441 // Detach unattached. 442 new_attr_select.find( 'option' + option_gt_filter + ':not(.attached)' ).remove(); 443 444 // Finally, copy to DOM and set value. 445 current_attr_select.html( new_attr_select.html() ); 446 current_attr_select.find( 'option' + option_gt_filter + ':not(.enabled)' ).prop( 'disabled', true ); 447 448 // Choose selected value. 449 if ( selected_attr_val ) { 450 // If the previously selected value is no longer available, fall back to the placeholder (it's going to be there). 451 if ( selected_attr_val_valid ) { 452 current_attr_select.val( selected_attr_val ); 453 } else { 454 current_attr_select.val( '' ).change(); 455 } 456 } else { 457 current_attr_select.val( '' ); // No change event to prevent infinite loop. 458 } 459 }); 460 461 // Custom event for when variations have been updated. 462 form.$form.trigger( 'woocommerce_update_variation_values' ); 463 }; 464 465 /** 466 * Get chosen attributes from form. 467 * @return array 468 */ 469 VariationForm.prototype.getChosenAttributes = function() { 470 var data = {}; 471 var count = 0; 472 var chosen = 0; 473 474 this.$attributeFields.each( function() { 475 var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' ); 476 var value = $( this ).val() || ''; 477 478 if ( value.length > 0 ) { 479 chosen ++; 480 } 481 482 count ++; 483 data[ attribute_name ] = value; 484 }); 485 486 return { 487 'count' : count, 488 'chosenCount': chosen, 489 'data' : data 490 }; 491 }; 492 493 /** 494 * Find matching variations for attributes. 495 */ 496 VariationForm.prototype.findMatchingVariations = function( variations, attributes ) { 497 var matching = []; 498 for ( var i = 0; i < variations.length; i++ ) { 499 var variation = variations[i]; 500 501 if ( this.isMatch( variation.attributes, attributes ) ) { 502 matching.push( variation ); 503 } 504 } 505 return matching; 506 }; 507 508 /** 509 * See if attributes match. 510 * @return {Boolean} 511 */ 512 VariationForm.prototype.isMatch = function( variation_attributes, attributes ) { 513 var match = true; 514 for ( var attr_name in variation_attributes ) { 515 if ( variation_attributes.hasOwnProperty( attr_name ) ) { 516 var val1 = variation_attributes[ attr_name ]; 517 var val2 = attributes[ attr_name ]; 518 if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) { 519 match = false; 520 } 521 } 522 } 523 return match; 524 }; 525 526 /** 527 * Show or hide the reset link. 528 */ 529 VariationForm.prototype.toggleResetLink = function( on ) { 530 if ( on ) { 531 if ( this.$resetVariations.css( 'visibility' ) === 'hidden' ) { 532 this.$resetVariations.css( 'visibility', 'visible' ).hide().fadeIn(); 533 } 534 } else { 535 this.$resetVariations.css( 'visibility', 'hidden' ); 536 } 537 }; 538 539 /** 540 * Function to call wc_variation_form on jquery selector. 541 */ 542 $.fn.wc_variation_form = function() { 543 new VariationForm( this ); 544 return this; 545 }; 546 547 /** 548 * Stores the default text for an element so it can be reset later 549 */ 550 $.fn.wc_set_content = function( content ) { 551 if ( undefined === this.attr( 'data-o_content' ) ) { 552 this.attr( 'data-o_content', this.text() ); 553 } 554 this.text( content ); 555 }; 556 557 /** 558 * Stores the default text for an element so it can be reset later 559 */ 560 $.fn.wc_reset_content = function() { 561 if ( undefined !== this.attr( 'data-o_content' ) ) { 562 this.text( this.attr( 'data-o_content' ) ); 563 } 564 }; 565 566 /** 567 * Stores a default attribute for an element so it can be reset later 568 */ 569 $.fn.wc_set_variation_attr = function( attr, value ) { 570 if ( undefined === this.attr( 'data-o_' + attr ) ) { 571 this.attr( 'data-o_' + attr, ( ! this.attr( attr ) ) ? '' : this.attr( attr ) ); 572 } 573 if ( false === value ) { 574 this.removeAttr( attr ); 575 } else { 576 this.attr( attr, value ); 577 } 578 }; 579 580 /** 581 * Reset a default attribute for an element so it can be reset later 582 */ 583 $.fn.wc_reset_variation_attr = function( attr ) { 584 if ( undefined !== this.attr( 'data-o_' + attr ) ) { 585 this.attr( attr, this.attr( 'data-o_' + attr ) ); 586 } 587 }; 588 589 /** 590 * Reset the slide position if the variation has a different image than the current one 591 */ 592 $.fn.wc_maybe_trigger_slide_position_reset = function( variation ) { 593 var $form = $( this ), 594 $product = $form.closest( '.product' ), 595 $product_gallery = $product.find( '.images' ), 596 reset_slide_position = false, 597 new_image_id = ( variation && variation.image_id ) ? variation.image_id : ''; 598 599 if ( $form.attr( 'current-image' ) !== new_image_id ) { 600 reset_slide_position = true; 601 } 602 603 $form.attr( 'current-image', new_image_id ); 604 605 if ( reset_slide_position ) { 606 $product_gallery.trigger( 'woocommerce_gallery_reset_slide_position' ); 607 } 608 }; 609 610 /** 611 * Sets product images for the chosen variation 612 */ 613 $.fn.wc_variations_image_update = function( variation ) { 614 var $form = this, 615 $product = $form.closest( '.product' ), 616 $product_gallery = $product.find( '.images' ), 617 $gallery_nav = $product.find( '.flex-control-nav' ), 618 $gallery_img = $gallery_nav.find( 'li:eq(0) img' ), 619 $product_img_wrap = $product_gallery.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ), 620 $product_img = $product_img_wrap.find( '.wp-post-image' ), 621 $product_link = $product_img_wrap.find( 'a' ).eq( 0 ); 622 623 if ( variation && variation.image && variation.image.src && variation.image.src.length > 1 ) { 624 // See if the gallery has an image with the same original src as the image we want to switch to. 625 var galleryHasImage = $gallery_nav.find( 'li img[data-o_src="' + variation.image.gallery_thumbnail_src + '"]' ).length > 0; 626 627 // If the gallery has the image, reset the images. We'll scroll to the correct one. 628 if ( galleryHasImage ) { 629 $form.wc_variations_image_reset(); 630 } 631 632 // See if gallery has a matching image we can slide to.
633 var slideToImage = $gallery_nav.find( 'li img[src="' + variation.image.gallery_thumbnail_src + '"]' ); 634 635 if ( slideToImage.length > 0 ) { 636 slideToImage.trigger( 'click' ); 637 $form.attr( 'current-image', variation.image_id ); 638 window.setTimeout( function() { 639 $( window ).trigger( 'resize' ); 640 $product_gallery.trigger( 'woocommerce_gallery_init_zoom' ); 641 }, 20 ); 642 return; 643 } 644 645 $product_img.wc_set_variation_attr( 'src', variation.image.src ); 646 $product_img.wc_set_variation_attr( 'height', variation.image.src_h ); 647 $product_img.wc_set_variation_attr( 'width', variation.image.src_w ); 648 $product_img.wc_set_variation_attr( 'srcset', variation.image.srcset ); 649 $product_img.wc_set_variation_attr( 'sizes', variation.image.sizes ); 650 $product_img.wc_set_variation_attr( 'title', variation.image.title ); 651 $product_img.wc_set_variation_attr( 'data-caption', variation.image.caption ); 652 $product_img.wc_set_variation_attr( 'alt', variation.image.alt ); 653 $product_img.wc_set_variation_attr( 'data-src', variation.image.full_src ); 654 $product_img.wc_set_variation_attr( 'data-large_image', variation.image.full_src ); 655 $product_img.wc_set_variation_attr( 'data-large_image_width', variation.image.full_src_w ); 656 $product_img.wc_set_variation_attr( 'data-large_image_height', variation.image.full_src_h ); 657 $product_img_wrap.wc_set_variation_attr( 'data-thumb', variation.image.src ); 658 $gallery_img.wc_set_variation_attr( 'src', variation.image.gallery_thumbnail_src ); 659 $product_link.wc_set_variation_attr( 'href', variation.image.full_src ); 660 } else { 661 $form.wc_variations_image_reset(); 662 } 663 664 window.setTimeout( function() { 665 $( window ).trigger( 'resize' ); 666 $form.wc_maybe_trigger_slide_position_reset( variation ); 667 $product_gallery.trigger( 'woocommerce_gallery_init_zoom' ); 668 }, 20 ); 669 }; 670 671 /** 672 * Reset main image to defaults. 673 */ 674 $.fn.wc_variations_image_reset = function() { 675 var $form = this, 676 $product = $form.closest( '.product' ), 677 $product_gallery = $product.find( '.images' ), 678 $gallery_nav = $product.find( '.flex-control-nav' ), 679 $gallery_img = $gallery_nav.find( 'li:eq(0) img' ), 680 $product_img_wrap = $product_gallery.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ), 681 $product_img = $product_img_wrap.find( '.wp-post-image' ), 682 $product_link = $product_img_wrap.find( 'a' ).eq( 0 ); 683 684 $product_img.wc_reset_variation_attr( 'src' ); 685 $product_img.wc_reset_variation_attr( 'width' ); 686 $product_img.wc_reset_variation_attr( 'height' ); 687 $product_img.wc_reset_variation_attr( 'srcset' ); 688 $product_img.wc_reset_variation_attr( 'sizes' ); 689 $product_img.wc_reset_variation_attr( 'title' ); 690 $product_img.wc_reset_variation_attr( 'data-caption' ); 691 $product_img.wc_reset_variation_attr( 'alt' ); 692 $product_img.wc_reset_variation_attr( 'data-src' ); 693 $product_img.wc_reset_variation_attr( 'data-large_image' ); 694 $product_img.wc_reset_variation_attr( 'data-large_image_width' ); 695 $product_img.wc_reset_variation_attr( 'data-large_image_height' ); 696 $product_img_wrap.wc_reset_variation_attr( 'data-thumb' ); 697 $gallery_img.wc_reset_variation_attr( 'src' ); 698 $product_link.wc_reset_variation_attr( 'href' ); 699 }; 700 701 $(function() { 702 if ( typeof wc_add_to_cart_variation_params !== 'undefined' ) { 703 $( '.variations_form' ).each( function() { 704 $( this ).wc_variation_form(); 705 }); 706 } 707 }); 708 709 /** 710 * Matches inline variation objects to chosen attributes 711 * @deprecated 2.6.9 712 * @type {Object} 713 */ 714 var wc_variation_form_matcher = { 715 find_matching_variations: function( product_variations, settings ) { 716 var matching = []; 717 for ( var i = 0; i < product_variations.length; i++ ) { 718 var variation = product_variations[i]; 719 720 if ( wc_variation_form_matcher.variations_match( variation.attributes, settings ) ) { 721 matching.push( variation ); 722 } 723 } 724 return matching; 725 }, 726 variations_match: function( attrs1, attrs2 ) { 727 var match = true; 728 for ( var attr_name in attrs1 ) { 729 if ( attrs1.hasOwnProperty( attr_name ) ) { 730 var val1 = attrs1[ attr_name ]; 731 var val2 = attrs2[ attr_name ]; 732 if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) { 733 match = false;
734 } 735 } 736 } 737 return match; 738 } 739 }; 740 741 /** 742 * Avoids using wp.template where possible in order to be CSP compliant. 743 * wp.template uses internally eval(). 744 * @param {string} templateId 745 * @return {Function} 746 */ 747 var wp_template = function( templateId ) { 748 var html = document.getElementById( 'tmpl-' + templateId ).textContent; 749 var hard = false; 750 // any <# #> interpolate (evaluate). 751 hard = hard || /<#\s?data\./.test( html ); 752 // any data that is NOT data.variation. 753 hard = hard || /{{{?\s?data\.(?!variation\.).+}}}?/.test( html ); 754 // any data access deeper than 1 level e.g. 755 // data.variation.object.item 756 // data.variation.object['item'] 757 // data.variation.array[0] 758 hard = hard || /{{{?\s?data\.variation\.[\w-]*[^\s}]/.test ( html ); 759 if ( hard ) { 760 return wp.template( templateId ); 761 } 762 return function template ( data ) { 763 var variation = data.variation || {}; 764 return html.replace( /({{{?)\s?data\.variation\.([\w-]*)\s?(}}}?)/g, function( _, open, key, close ) { 765 // Error in the format, ignore. 766 if ( open.length !== close.length ) { 767 return ''; 768 } 769 var replacement = variation[ key ] || ''; 770 // {{{ }}} => interpolate (unescaped). 771 // {{ }} => interpolate (escaped). 772 // https://codex.wordpress.org/Javascript_Reference/wp.template 773 if ( open.length === 2 ) { 774 return window.escape( replacement ); 775 } 776 return replacement; 777 }); 778 }; 779 }; 780 781})( jQuery, window, document );
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.