add-to-cart-variation.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  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. self.$form = $form;
  9. self.$attributeFields = $form.find( '.variations select' );
  10. self.$singleVariation = $form.find( '.single_variation' );
  11. self.$singleVariationWrap = $form.find( '.single_variation_wrap' );
  12. self.$resetVariations = $form.find( '.reset_variations' );
  13. self.$product = $form.closest( '.product' );
  14. self.variationData = $form.data( 'product_variations' );
  15. self.useAjax = false === self.variationData;
  16. self.xhr = false;
  17. self.loading = true;
  18. // Initial state.
  19. self.$singleVariationWrap.show();
  20. self.$form.off( '.wc-variation-form' );
  21. // Methods.
  22. self.getChosenAttributes = self.getChosenAttributes.bind( self );
  23. self.findMatchingVariations = self.findMatchingVariations.bind( self );
  24. self.isMatch = self.isMatch.bind( self );
  25. self.toggleResetLink = self.toggleResetLink.bind( self );
  26. // Events.
  27. $form.on( 'click.wc-variation-form', '.reset_variations', { variationForm: self }, self.onReset );
  28. $form.on( 'reload_product_variations', { variationForm: self }, self.onReload );
  29. $form.on( 'hide_variation', { variationForm: self }, self.onHide );
  30. $form.on( 'show_variation', { variationForm: self }, self.onShow );
  31. $form.on( 'click', '.single_add_to_cart_button', { variationForm: self }, self.onAddToCart );
  32. $form.on( 'reset_data', { variationForm: self }, self.onResetDisplayedVariation );
  33. $form.on( 'reset_image', { variationForm: self }, self.onResetImage );
  34. $form.on( 'change.wc-variation-form', '.variations select', { variationForm: self }, self.onChange );
  35. $form.on( 'found_variation.wc-variation-form', { variationForm: self }, self.onFoundVariation );
  36. $form.on( 'check_variations.wc-variation-form', { variationForm: self }, self.onFindVariation );
  37. $form.on( 'update_variation_values.wc-variation-form', { variationForm: self }, self.onUpdateAttributes );
  38. // Init after gallery.
  39. setTimeout( function() {
  40. $form.trigger( 'check_variations' );
  41. $form.trigger( 'wc_variation_form' );
  42. self.loading = false;
  43. }, 100 );
  44. };
  45. /**
  46. * Reset all fields.
  47. */
  48. VariationForm.prototype.onReset = function( event ) {
  49. event.preventDefault();
  50. event.data.variationForm.$attributeFields.val( '' ).change();
  51. event.data.variationForm.$form.trigger( 'reset_data' );
  52. };
  53. /**
  54. * Reload variation data from the DOM.
  55. */
  56. VariationForm.prototype.onReload = function( event ) {
  57. var form = event.data.variationForm;
  58. form.variationData = form.$form.data( 'product_variations' );
  59. form.useAjax = false === form.variationData;
  60. form.$form.trigger( 'check_variations' );
  61. };
  62. /**
  63. * When a variation is hidden.
  64. */
  65. VariationForm.prototype.onHide = function( event ) {
  66. event.preventDefault();
  67. event.data.variationForm.$form.find( '.single_add_to_cart_button' ).removeClass( 'wc-variation-is-unavailable' ).addClass( 'disabled wc-variation-selection-needed' );
  68. event.data.variationForm.$form.find( '.woocommerce-variation-add-to-cart' ).removeClass( 'woocommerce-variation-add-to-cart-enabled' ).addClass( 'woocommerce-variation-add-to-cart-disabled' );
  69. };
  70. /**
  71. * When a variation is shown.
  72. */
  73. VariationForm.prototype.onShow = function( event, variation, purchasable ) {
  74. event.preventDefault();
  75. if ( purchasable ) {
  76. event.data.variationForm.$form.find( '.single_add_to_cart_button' ).removeClass( 'disabled wc-variation-selection-needed wc-variation-is-unavailable' );
  77. event.data.variationForm.$form.find( '.woocommerce-variation-add-to-cart' ).removeClass( 'woocommerce-variation-add-to-cart-disabled' ).addClass( 'woocommerce-variation-add-to-cart-enabled' );
  78. } else {
  79. event.data.variationForm.$form.find( '.single_add_to_cart_button' ).removeClass( 'wc-variation-selection-needed' ).addClass( 'disabled wc-variation-is-unavailable' );
  80. event.data.variationForm.$form.find( '.woocommerce-variation-add-to-cart' ).removeClass( 'woocommerce-variation-add-to-cart-enabled' ).addClass( 'woocommerce-variation-add-to-cart-disabled' );
  81. }
  82. };
  83. /**
  84. * When the cart button is pressed.
  85. */
  86. VariationForm.prototype.onAddToCart = function( event ) {
  87. if ( $( this ).is('.disabled') ) {
  88. event.preventDefault();
  89. if ( $( this ).is('.wc-variation-is-unavailable') ) {
  90. window.alert( wc_add_to_cart_variation_params.i18n_unavailable_text );
  91. } else if ( $( this ).is('.wc-variation-selection-needed') ) {
  92. window.alert( wc_add_to_cart_variation_params.i18n_make_a_selection_text );
  93. }
  94. }
  95. };
  96. /**
  97. * When displayed variation data is reset.
  98. */
  99. VariationForm.prototype.onResetDisplayedVariation = function( event ) {
  100. var form = event.data.variationForm;
  101. form.$product.find( '.product_meta' ).find( '.sku' ).wc_reset_content();
  102. form.$product.find( '.product_weight' ).wc_reset_content();
  103. form.$product.find( '.product_dimensions' ).wc_reset_content();
  104. form.$form.trigger( 'reset_image' );
  105. form.$singleVariation.slideUp( 200 ).trigger( 'hide_variation' );
  106. };
  107. /**
  108. * When the product image is reset.
  109. */
  110. VariationForm.prototype.onResetImage = function( event ) {
  111. event.data.variationForm.$form.wc_variations_image_update( false );
  112. };
  113. /**
  114. * Looks for matching variations for current selected attributes.
  115. */
  116. VariationForm.prototype.onFindVariation = function( event ) {
  117. var form = event.data.variationForm,
  118. attributes = form.getChosenAttributes(),
  119. currentAttributes = attributes.data;
  120. if ( attributes.count === attributes.chosenCount ) {
  121. if ( form.useAjax ) {
  122. if ( form.xhr ) {
  123. form.xhr.abort();
  124. }
  125. form.$form.block( { message: null, overlayCSS: { background: '#fff', opacity: 0.6 } } );
  126. currentAttributes.product_id = parseInt( form.$form.data( 'product_id' ), 10 );
  127. currentAttributes.custom_data = form.$form.data( 'custom_data' );
  128. form.xhr = $.ajax( {
  129. url: wc_add_to_cart_variation_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'get_variation' ),
  130. type: 'POST',
  131. data: currentAttributes,
  132. success: function( variation ) {
  133. if ( variation ) {
  134. form.$form.trigger( 'found_variation', [ variation ] );
  135. } else {
  136. form.$form.trigger( 'reset_data' );
  137. attributes.chosenCount = 0;
  138. if ( ! form.loading ) {
  139. 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>' );
  140. form.$form.find( '.wc-no-matching-variations' ).slideDown( 200 );
  141. }
  142. }
  143. },
  144. complete: function() {
  145. form.$form.unblock();
  146. }
  147. } );
  148. } else {
  149. form.$form.trigger( 'update_variation_values' );
  150. var matching_variations = form.findMatchingVariations( form.variationData, currentAttributes ),
  151. variation = matching_variations.shift();
  152. if ( variation ) {
  153. form.$form.trigger( 'found_variation', [ variation ] );
  154. } else {
  155. form.$form.trigger( 'reset_data' );
  156. attributes.chosenCount = 0;
  157. if ( ! form.loading ) {
  158. 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>' );
  159. form.$form.find( '.wc-no-matching-variations' ).slideDown( 200 );
  160. }
  161. }
  162. }
  163. } else {
  164. form.$form.trigger( 'update_variation_values' );
  165. form.$form.trigger( 'reset_data' );
  166. }
  167. // Show reset link.
  168. form.toggleResetLink( attributes.chosenCount > 0 );
  169. };
  170. /**
  171. * Triggered when a variation has been found which matches all attributes.
  172. */
  173. VariationForm.prototype.onFoundVariation = function( event, variation ) {
  174. var form = event.data.variationForm,
  175. $sku = form.$product.find( '.product_meta' ).find( '.sku' ),
  176. $weight = form.$product.find( '.product_weight' ),
  177. $dimensions = form.$product.find( '.product_dimensions' ),
  178. $qty = form.$singleVariationWrap.find( '.quantity' ),
  179. purchasable = true,
  180. variation_id = '',
  181. template = false,
  182. $template_html = '';
  183. if ( variation.sku ) {
  184. $sku.wc_set_content( variation.sku );
  185. } else {
  186. $sku.wc_reset_content();
  187. }
  188. if ( variation.weight ) {
  189. $weight.wc_set_content( variation.weight_html );
  190. } else {
  191. $weight.wc_reset_content();
  192. }
  193. if ( variation.dimensions ) {
  194. $dimensions.wc_set_content( variation.dimensions_html );
  195. } else {
  196. $dimensions.wc_reset_content();
  197. }
  198. form.$form.wc_variations_image_update( variation );
  199. if ( ! variation.variation_is_visible ) {
  200. template = wp.template( 'unavailable-variation-template' );
  201. } else {
  202. template = wp.template( 'variation-template' );
  203. variation_id = variation.variation_id;
  204. }
  205. $template_html = template( {
  206. variation: variation
  207. } );
  208. $template_html = $template_html.replace( '/*<![CDATA[*/', '' );
  209. $template_html = $template_html.replace( '/*]]>*/', '' );
  210. form.$singleVariation.html( $template_html );
  211. form.$form.find( 'input[name="variation_id"], input.variation_id' ).val( variation.variation_id ).change();
  212. // Hide or show qty input
  213. if ( variation.is_sold_individually === 'yes' ) {
  214. $qty.find( 'input.qty' ).val( '1' ).attr( 'min', '1' ).attr( 'max', '' );
  215. $qty.hide();
  216. } else {
  217. $qty.find( 'input.qty' ).attr( 'min', variation.min_qty ).attr( 'max', variation.max_qty );
  218. $qty.show();
  219. }
  220. // Enable or disable the add to cart button
  221. if ( ! variation.is_purchasable || ! variation.is_in_stock || ! variation.variation_is_visible ) {
  222. purchasable = false;
  223. }
  224. // Reveal
  225. if ( $.trim( form.$singleVariation.text() ) ) {
  226. form.$singleVariation.slideDown( 200 ).trigger( 'show_variation', [ variation, purchasable ] );
  227. } else {
  228. form.$singleVariation.show().trigger( 'show_variation', [ variation, purchasable ] );
  229. }
  230. };
  231. /**
  232. * Triggered when an attribute field changes.
  233. */
  234. VariationForm.prototype.onChange = function( event ) {
  235. var form = event.data.variationForm;
  236. form.$form.find( 'input[name="variation_id"], input.variation_id' ).val( '' ).change();
  237. form.$form.find( '.wc-no-matching-variations' ).remove();
  238. if ( form.useAjax ) {
  239. form.$form.trigger( 'check_variations' );
  240. } else {
  241. form.$form.trigger( 'woocommerce_variation_select_change' );
  242. form.$form.trigger( 'check_variations' );
  243. $( this ).blur();
  244. }
  245. // Custom event for when variation selection has been changed
  246. form.$form.trigger( 'woocommerce_variation_has_changed' );
  247. };
  248. /**
  249. * Escape quotes in a string.
  250. * @param {string} string
  251. * @return {string}
  252. */
  253. VariationForm.prototype.addSlashes = function( string ) {
  254. string = string.replace( /'/g, '\\\'' );
  255. string = string.replace( /"/g, '\\\"' );
  256. return string;
  257. };
  258. /**
  259. * Updates attributes in the DOM to show valid values.
  260. */
  261. VariationForm.prototype.onUpdateAttributes = function( event ) {
  262. var form = event.data.variationForm,
  263. attributes = form.getChosenAttributes(),
  264. currentAttributes = attributes.data;
  265. if ( form.useAjax ) {
  266. return;
  267. }
  268. // Loop through selects and disable/enable options based on selections.
  269. form.$attributeFields.each( function( index, el ) {
  270. var current_attr_select = $( el ),
  271. current_attr_name = current_attr_select.data( 'attribute_name' ) || current_attr_select.attr( 'name' ),
  272. show_option_none = $( el ).data( 'show_option_none' ),
  273. option_gt_filter = ':gt(0)',
  274. attached_options_count = 0,
  275. new_attr_select = $( '<select/>' ),
  276. selected_attr_val = current_attr_select.val() || '',
  277. selected_attr_val_valid = true;
  278. // Reference options set at first.
  279. if ( ! current_attr_select.data( 'attribute_html' ) ) {
  280. var refSelect = current_attr_select.clone();
  281. refSelect.find( 'option' ).removeAttr( 'disabled attached' ).removeAttr( 'selected' );
  282. current_attr_select.data( 'attribute_options', refSelect.find( 'option' + option_gt_filter ).get() ); // Legacy data attribute.
  283. current_attr_select.data( 'attribute_html', refSelect.html() );
  284. }
  285. new_attr_select.html( current_attr_select.data( 'attribute_html' ) );
  286. // The attribute of this select field should not be taken into account when calculating its matching variations:
  287. // The constraints of this attribute are shaped by the values of the other attributes.
  288. var checkAttributes = $.extend( true, {}, currentAttributes );
  289. checkAttributes[ current_attr_name ] = '';
  290. var variations = form.findMatchingVariations( form.variationData, checkAttributes );
  291. // Loop through variations.
  292. for ( var num in variations ) {
  293. if ( typeof( variations[ num ] ) !== 'undefined' ) {
  294. var variationAttributes = variations[ num ].attributes;
  295. for ( var attr_name in variationAttributes ) {
  296. if ( variationAttributes.hasOwnProperty( attr_name ) ) {
  297. var attr_val = variationAttributes[ attr_name ],
  298. variation_active = '';
  299. if ( attr_name === current_attr_name ) {
  300. if ( variations[ num ].variation_is_active ) {
  301. variation_active = 'enabled';
  302. }
  303. if ( attr_val ) {
  304. // Decode entities and add slashes.
  305. attr_val = $( '<div/>' ).html( attr_val ).text();
  306. // Attach.
  307. new_attr_select.find( 'option[value="' + form.addSlashes( attr_val ) + '"]' ).addClass( 'attached ' + variation_active );
  308. } else {
  309. // Attach all apart from placeholder.
  310. new_attr_select.find( 'option:gt(0)' ).addClass( 'attached ' + variation_active );
  311. }
  312. }
  313. }
  314. }
  315. }
  316. }
  317. // Count available options.
  318. attached_options_count = new_attr_select.find( 'option.attached' ).length;
  319. // Check if current selection is in attached options.
  320. if ( selected_attr_val && ( attached_options_count === 0 || new_attr_select.find( 'option.attached.enabled[value="' + form.addSlashes( selected_attr_val ) + '"]' ).length === 0 ) ) {
  321. selected_attr_val_valid = false;
  322. }
  323. // Detach the placeholder if:
  324. // - Valid options exist.
  325. // - The current selection is non-empty.
  326. // - The current selection is valid.
  327. // - Placeholders are not set to be permanently visible.
  328. if ( attached_options_count > 0 && selected_attr_val && selected_attr_val_valid && ( 'no' === show_option_none ) ) {
  329. new_attr_select.find( 'option:first' ).remove();
  330. option_gt_filter = '';
  331. }
  332. // Detach unattached.
  333. new_attr_select.find( 'option' + option_gt_filter + ':not(.attached)' ).remove();
  334. // Finally, copy to DOM and set value.
  335. current_attr_select.html( new_attr_select.html() );
  336. current_attr_select.find( 'option' + option_gt_filter + ':not(.enabled)' ).prop( 'disabled', true );
  337. // Choose selected value.
  338. if ( selected_attr_val ) {
  339. // If the previously selected value is no longer available, fall back to the placeholder (it's going to be there).
  340. if ( selected_attr_val_valid ) {
  341. current_attr_select.val( selected_attr_val );
  342. } else {
  343. current_attr_select.val( '' ).change();
  344. }
  345. } else {
  346. current_attr_select.val( '' ); // No change event to prevent infinite loop.
  347. }
  348. });
  349. // Custom event for when variations have been updated.
  350. form.$form.trigger( 'woocommerce_update_variation_values' );
  351. };
  352. /**
  353. * Get chosen attributes from form.
  354. * @return array
  355. */
  356. VariationForm.prototype.getChosenAttributes = function() {
  357. var data = {};
  358. var count = 0;
  359. var chosen = 0;
  360. this.$attributeFields.each( function() {
  361. var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' );
  362. var value = $( this ).val() || '';
  363. if ( value.length > 0 ) {
  364. chosen ++;
  365. }
  366. count ++;
  367. data[ attribute_name ] = value;
  368. });
  369. return {
  370. 'count' : count,
  371. 'chosenCount': chosen,
  372. 'data' : data
  373. };
  374. };
  375. /**
  376. * Find matching variations for attributes.
  377. */
  378. VariationForm.prototype.findMatchingVariations = function( variations, attributes ) {
  379. var matching = [];
  380. for ( var i = 0; i < variations.length; i++ ) {
  381. var variation = variations[i];
  382. if ( this.isMatch( variation.attributes, attributes ) ) {
  383. matching.push( variation );
  384. }
  385. }
  386. return matching;
  387. };
  388. /**
  389. * See if attributes match.
  390. * @return {Boolean}
  391. */
  392. VariationForm.prototype.isMatch = function( variation_attributes, attributes ) {
  393. var match = true;
  394. for ( var attr_name in variation_attributes ) {
  395. if ( variation_attributes.hasOwnProperty( attr_name ) ) {
  396. var val1 = variation_attributes[ attr_name ];
  397. var val2 = attributes[ attr_name ];
  398. if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) {
  399. match = false;
  400. }
  401. }
  402. }
  403. return match;
  404. };
  405. /**
  406. * Show or hide the reset link.
  407. */
  408. VariationForm.prototype.toggleResetLink = function( on ) {
  409. if ( on ) {
  410. if ( this.$resetVariations.css( 'visibility' ) === 'hidden' ) {
  411. this.$resetVariations.css( 'visibility', 'visible' ).hide().fadeIn();
  412. }
  413. } else {
  414. this.$resetVariations.css( 'visibility', 'hidden' );
  415. }
  416. };
  417. /**
  418. * Function to call wc_variation_form on jquery selector.
  419. */
  420. $.fn.wc_variation_form = function() {
  421. new VariationForm( this );
  422. return this;
  423. };
  424. /**
  425. * Stores the default text for an element so it can be reset later
  426. */
  427. $.fn.wc_set_content = function( content ) {
  428. if ( undefined === this.attr( 'data-o_content' ) ) {
  429. this.attr( 'data-o_content', this.text() );
  430. }
  431. this.text( content );
  432. };
  433. /**
  434. * Stores the default text for an element so it can be reset later
  435. */
  436. $.fn.wc_reset_content = function() {
  437. if ( undefined !== this.attr( 'data-o_content' ) ) {
  438. this.text( this.attr( 'data-o_content' ) );
  439. }
  440. };
  441. /**
  442. * Stores a default attribute for an element so it can be reset later
  443. */
  444. $.fn.wc_set_variation_attr = function( attr, value ) {
  445. if ( undefined === this.attr( 'data-o_' + attr ) ) {
  446. this.attr( 'data-o_' + attr, ( ! this.attr( attr ) ) ? '' : this.attr( attr ) );
  447. }
  448. if ( false === value ) {
  449. this.removeAttr( attr );
  450. } else {
  451. this.attr( attr, value );
  452. }
  453. };
  454. /**
  455. * Reset a default attribute for an element so it can be reset later
  456. */
  457. $.fn.wc_reset_variation_attr = function( attr ) {
  458. if ( undefined !== this.attr( 'data-o_' + attr ) ) {
  459. this.attr( attr, this.attr( 'data-o_' + attr ) );
  460. }
  461. };
  462. /**
  463. * Reset the slide position if the variation has a different image than the current one
  464. */
  465. $.fn.wc_maybe_trigger_slide_position_reset = function( variation ) {
  466. var $form = $( this ),
  467. $product = $form.closest( '.product' ),
  468. $product_gallery = $product.find( '.images' ),
  469. reset_slide_position = false,
  470. new_image_id = ( variation && variation.image_id ) ? variation.image_id : '';
  471. if ( $form.attr( 'current-image' ) !== new_image_id ) {
  472. reset_slide_position = true;
  473. }
  474. $form.attr( 'current-image', new_image_id );
  475. if ( reset_slide_position ) {
  476. $product_gallery.trigger( 'woocommerce_gallery_reset_slide_position' );
  477. }
  478. };
  479. /**
  480. * Sets product images for the chosen variation
  481. */
  482. $.fn.wc_variations_image_update = function( variation ) {
  483. var $form = this,
  484. $product = $form.closest( '.product' ),
  485. $product_gallery = $product.find( '.images' ),
  486. $gallery_nav = $product.find( '.flex-control-nav' ),
  487. $gallery_img = $gallery_nav.find( 'li:eq(0) img' ),
  488. $product_img_wrap = $product_gallery.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ),
  489. $product_img = $product_img_wrap.find( '.wp-post-image' ),
  490. $product_link = $product_img_wrap.find( 'a' ).eq( 0 );
  491. if ( variation && variation.image && variation.image.src && variation.image.src.length > 1 ) {
  492. // See if the gallery has an image with the same original src as the image we want to switch to.
  493. var galleryHasImage = $gallery_nav.find( 'li img[data-o_src="' + variation.image.gallery_thumbnail_src + '"]' ).length > 0;
  494. // If the gallery has the image, reset the images. We'll scroll to the correct one.
  495. if ( galleryHasImage ) {
  496. $form.wc_variations_image_reset();
  497. }
  498. // See if gallery has a matching image we can slide to.
  499. var slideToImage = $gallery_nav.find( 'li img[src="' + variation.image.gallery_thumbnail_src + '"]' );
  500. if ( slideToImage.length > 0 ) {
  501. slideToImage.trigger( 'click' );
  502. $form.attr( 'current-image', variation.image_id );
  503. window.setTimeout( function() {
  504. $( window ).trigger( 'resize' );
  505. $product_gallery.trigger( 'woocommerce_gallery_init_zoom' );
  506. }, 20 );
  507. return;
  508. }
  509. $product_img.wc_set_variation_attr( 'src', variation.image.src );
  510. $product_img.wc_set_variation_attr( 'height', variation.image.src_h );
  511. $product_img.wc_set_variation_attr( 'width', variation.image.src_w );
  512. $product_img.wc_set_variation_attr( 'srcset', variation.image.srcset );
  513. $product_img.wc_set_variation_attr( 'sizes', variation.image.sizes );
  514. $product_img.wc_set_variation_attr( 'title', variation.image.title );
  515. $product_img.wc_set_variation_attr( 'data-caption', variation.image.caption );
  516. $product_img.wc_set_variation_attr( 'alt', variation.image.alt );
  517. $product_img.wc_set_variation_attr( 'data-src', variation.image.full_src );
  518. $product_img.wc_set_variation_attr( 'data-large_image', variation.image.full_src );
  519. $product_img.wc_set_variation_attr( 'data-large_image_width', variation.image.full_src_w );
  520. $product_img.wc_set_variation_attr( 'data-large_image_height', variation.image.full_src_h );
  521. $product_img_wrap.wc_set_variation_attr( 'data-thumb', variation.image.src );
  522. $gallery_img.wc_set_variation_attr( 'src', variation.image.gallery_thumbnail_src );
  523. $product_link.wc_set_variation_attr( 'href', variation.image.full_src );
  524. } else {
  525. $form.wc_variations_image_reset();
  526. }
  527. window.setTimeout( function() {
  528. $( window ).trigger( 'resize' );
  529. $form.wc_maybe_trigger_slide_position_reset( variation );
  530. $product_gallery.trigger( 'woocommerce_gallery_init_zoom' );
  531. }, 20 );
  532. };
  533. /**
  534. * Reset main image to defaults.
  535. */
  536. $.fn.wc_variations_image_reset = function() {
  537. var $form = this,
  538. $product = $form.closest( '.product' ),
  539. $product_gallery = $product.find( '.images' ),
  540. $gallery_nav = $product.find( '.flex-control-nav' ),
  541. $gallery_img = $gallery_nav.find( 'li:eq(0) img' ),
  542. $product_img_wrap = $product_gallery.find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ).eq( 0 ),
  543. $product_img = $product_img_wrap.find( '.wp-post-image' ),
  544. $product_link = $product_img_wrap.find( 'a' ).eq( 0 );
  545. $product_img.wc_reset_variation_attr( 'src' );
  546. $product_img.wc_reset_variation_attr( 'width' );
  547. $product_img.wc_reset_variation_attr( 'height' );
  548. $product_img.wc_reset_variation_attr( 'srcset' );
  549. $product_img.wc_reset_variation_attr( 'sizes' );
  550. $product_img.wc_reset_variation_attr( 'title' );
  551. $product_img.wc_reset_variation_attr( 'data-caption' );
  552. $product_img.wc_reset_variation_attr( 'alt' );
  553. $product_img.wc_reset_variation_attr( 'data-src' );
  554. $product_img.wc_reset_variation_attr( 'data-large_image' );
  555. $product_img.wc_reset_variation_attr( 'data-large_image_width' );
  556. $product_img.wc_reset_variation_attr( 'data-large_image_height' );
  557. $product_img_wrap.wc_reset_variation_attr( 'data-thumb' );
  558. $gallery_img.wc_reset_variation_attr( 'src' );
  559. $product_link.wc_reset_variation_attr( 'href' );
  560. };
  561. $(function() {
  562. if ( typeof wc_add_to_cart_variation_params !== 'undefined' ) {
  563. $( '.variations_form' ).each( function() {
  564. $( this ).wc_variation_form();
  565. });
  566. }
  567. });
  568. /**
  569. * Matches inline variation objects to chosen attributes
  570. * @deprecated 2.6.9
  571. * @type {Object}
  572. */
  573. var wc_variation_form_matcher = {
  574. find_matching_variations: function( product_variations, settings ) {
  575. var matching = [];
  576. for ( var i = 0; i < product_variations.length; i++ ) {
  577. var variation = product_variations[i];
  578. if ( wc_variation_form_matcher.variations_match( variation.attributes, settings ) ) {
  579. matching.push( variation );
  580. }
  581. }
  582. return matching;
  583. },
  584. variations_match: function( attrs1, attrs2 ) {
  585. var match = true;
  586. for ( var attr_name in attrs1 ) {
  587. if ( attrs1.hasOwnProperty( attr_name ) ) {
  588. var val1 = attrs1[ attr_name ];
  589. var val2 = attrs2[ attr_name ];
  590. if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) {
  591. match = false;
  592. }
  593. }
  594. }
  595. return match;
  596. }
  597. };
  598. })( jQuery, window, document );