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