meta-boxes-product-variation.js 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049
  1. /* global wp, woocommerce_admin_meta_boxes_variations, woocommerce_admin, accounting */
  2. jQuery( function( $ ) {
  3. 'use strict';
  4. /**
  5. * Variations actions
  6. */
  7. var wc_meta_boxes_product_variations_actions = {
  8. /**
  9. * Initialize variations actions
  10. */
  11. init: function() {
  12. $( '#variable_product_options' )
  13. .on( 'change', 'input.variable_is_downloadable', this.variable_is_downloadable )
  14. .on( 'change', 'input.variable_is_virtual', this.variable_is_virtual )
  15. .on( 'change', 'input.variable_manage_stock', this.variable_manage_stock )
  16. .on( 'click', 'button.notice-dismiss', this.notice_dismiss )
  17. .on( 'click', 'h3 .sort', this.set_menu_order )
  18. .on( 'reload', this.reload );
  19. $( 'input.variable_is_downloadable, input.variable_is_virtual, input.variable_manage_stock' ).change();
  20. $( '#woocommerce-product-data' ).on( 'woocommerce_variations_loaded', this.variations_loaded );
  21. $( document.body ).on( 'woocommerce_variations_added', this.variation_added );
  22. },
  23. /**
  24. * Reload UI
  25. *
  26. * @param {Object} event
  27. * @param {Int} qty
  28. */
  29. reload: function() {
  30. wc_meta_boxes_product_variations_ajax.load_variations( 1 );
  31. wc_meta_boxes_product_variations_pagenav.set_paginav( 0 );
  32. },
  33. /**
  34. * Check if variation is downloadable and show/hide elements
  35. */
  36. variable_is_downloadable: function() {
  37. $( this ).closest( '.woocommerce_variation' ).find( '.show_if_variation_downloadable' ).hide();
  38. if ( $( this ).is( ':checked' ) ) {
  39. $( this ).closest( '.woocommerce_variation' ).find( '.show_if_variation_downloadable' ).show();
  40. }
  41. },
  42. /**
  43. * Check if variation is virtual and show/hide elements
  44. */
  45. variable_is_virtual: function() {
  46. $( this ).closest( '.woocommerce_variation' ).find( '.hide_if_variation_virtual' ).show();
  47. if ( $( this ).is( ':checked' ) ) {
  48. $( this ).closest( '.woocommerce_variation' ).find( '.hide_if_variation_virtual' ).hide();
  49. }
  50. },
  51. /**
  52. * Check if variation manage stock and show/hide elements
  53. */
  54. variable_manage_stock: function() {
  55. $( this ).closest( '.woocommerce_variation' ).find( '.show_if_variation_manage_stock' ).hide();
  56. $( this ).closest( '.woocommerce_variation' ).find( '.hide_if_variation_manage_stock' ).show();
  57. if ( $( this ).is( ':checked' ) ) {
  58. $( this ).closest( '.woocommerce_variation' ).find( '.show_if_variation_manage_stock' ).show();
  59. $( this ).closest( '.woocommerce_variation' ).find( '.hide_if_variation_manage_stock' ).hide();
  60. }
  61. },
  62. /**
  63. * Notice dismiss
  64. */
  65. notice_dismiss: function() {
  66. $( this ).closest( 'div.notice' ).remove();
  67. },
  68. /**
  69. * Run actions when variations is loaded
  70. *
  71. * @param {Object} event
  72. * @param {Int} needsUpdate
  73. */
  74. variations_loaded: function( event, needsUpdate ) {
  75. needsUpdate = needsUpdate || false;
  76. var wrapper = $( '#woocommerce-product-data' );
  77. if ( ! needsUpdate ) {
  78. // Show/hide downloadable, virtual and stock fields
  79. $( 'input.variable_is_downloadable, input.variable_is_virtual, input.variable_manage_stock', wrapper ).change();
  80. // Open sale schedule fields when have some sale price date
  81. $( '.woocommerce_variation', wrapper ).each( function( index, el ) {
  82. var $el = $( el ),
  83. date_from = $( '.sale_price_dates_from', $el ).val(),
  84. date_to = $( '.sale_price_dates_to', $el ).val();
  85. if ( '' !== date_from || '' !== date_to ) {
  86. $( 'a.sale_schedule', $el ).click();
  87. }
  88. });
  89. // Remove variation-needs-update classes
  90. $( '.woocommerce_variations .variation-needs-update', wrapper ).removeClass( 'variation-needs-update' );
  91. // Disable cancel and save buttons
  92. $( 'button.cancel-variation-changes, button.save-variation-changes', wrapper ).attr( 'disabled', 'disabled' );
  93. }
  94. // Init TipTip
  95. $( '#tiptip_holder' ).removeAttr( 'style' );
  96. $( '#tiptip_arrow' ).removeAttr( 'style' );
  97. $( '.woocommerce_variations .tips, .woocommerce_variations .help_tip, .woocommerce_variations .woocommerce-help-tip', wrapper ).tipTip({
  98. 'attribute': 'data-tip',
  99. 'fadeIn': 50,
  100. 'fadeOut': 50,
  101. 'delay': 200
  102. });
  103. // Datepicker fields
  104. $( '.sale_price_dates_fields', wrapper ).find( 'input' ).datepicker({
  105. defaultDate: '',
  106. dateFormat: 'yy-mm-dd',
  107. numberOfMonths: 1,
  108. showButtonPanel: true,
  109. onSelect: function() {
  110. var option = $( this ).is( '.sale_price_dates_from' ) ? 'minDate' : 'maxDate',
  111. dates = $( this ).closest( '.sale_price_dates_fields' ).find( 'input' ),
  112. date = $( this ).datepicker( 'getDate' );
  113. dates.not( this ).datepicker( 'option', option, date );
  114. $( this ).change();
  115. }
  116. });
  117. // Allow sorting
  118. $( '.woocommerce_variations', wrapper ).sortable({
  119. items: '.woocommerce_variation',
  120. cursor: 'move',
  121. axis: 'y',
  122. handle: '.sort',
  123. scrollSensitivity: 40,
  124. forcePlaceholderSize: true,
  125. helper: 'clone',
  126. opacity: 0.65,
  127. stop: function() {
  128. wc_meta_boxes_product_variations_actions.variation_row_indexes();
  129. }
  130. });
  131. $( document.body ).trigger( 'wc-enhanced-select-init' );
  132. },
  133. /**
  134. * Run actions when added a variation
  135. *
  136. * @param {Object} event
  137. * @param {Int} qty
  138. */
  139. variation_added: function( event, qty ) {
  140. if ( 1 === qty ) {
  141. wc_meta_boxes_product_variations_actions.variations_loaded( null, true );
  142. }
  143. },
  144. /**
  145. * Lets the user manually input menu order to move items around pages
  146. */
  147. set_menu_order: function( event ) {
  148. event.preventDefault();
  149. var $menu_order = $( this ).closest( '.woocommerce_variation' ).find('.variation_menu_order');
  150. var value = window.prompt( woocommerce_admin_meta_boxes_variations.i18n_enter_menu_order, $menu_order.val() );
  151. if ( value != null ) {
  152. // Set value, save changes and reload view
  153. $menu_order.val( parseInt( value, 10 ) ).change();
  154. wc_meta_boxes_product_variations_ajax.save_variations();
  155. }
  156. },
  157. /**
  158. * Set menu order
  159. */
  160. variation_row_indexes: function() {
  161. var wrapper = $( '#variable_product_options' ).find( '.woocommerce_variations' ),
  162. current_page = parseInt( wrapper.attr( 'data-page' ), 10 ),
  163. offset = parseInt( ( current_page - 1 ) * woocommerce_admin_meta_boxes_variations.variations_per_page, 10 );
  164. $( '.woocommerce_variations .woocommerce_variation' ).each( function ( index, el ) {
  165. $( '.variation_menu_order', el ).val( parseInt( $( el ).index( '.woocommerce_variations .woocommerce_variation' ), 10 ) + 1 + offset ).change();
  166. });
  167. }
  168. };
  169. /**
  170. * Variations media actions
  171. */
  172. var wc_meta_boxes_product_variations_media = {
  173. /**
  174. * wp.media frame object
  175. *
  176. * @type {Object}
  177. */
  178. variable_image_frame: null,
  179. /**
  180. * Variation image ID
  181. *
  182. * @type {Int}
  183. */
  184. setting_variation_image_id: null,
  185. /**
  186. * Variation image object
  187. *
  188. * @type {Object}
  189. */
  190. setting_variation_image: null,
  191. /**
  192. * wp.media post ID
  193. *
  194. * @type {Int}
  195. */
  196. wp_media_post_id: wp.media.model.settings.post.id,
  197. /**
  198. * Initialize media actions
  199. */
  200. init: function() {
  201. $( '#variable_product_options' ).on( 'click', '.upload_image_button', this.add_image );
  202. $( 'a.add_media' ).on( 'click', this.restore_wp_media_post_id );
  203. },
  204. /**
  205. * Added new image
  206. *
  207. * @param {Object} event
  208. */
  209. add_image: function( event ) {
  210. var $button = $( this ),
  211. post_id = $button.attr( 'rel' ),
  212. $parent = $button.closest( '.upload_image' );
  213. wc_meta_boxes_product_variations_media.setting_variation_image = $parent;
  214. wc_meta_boxes_product_variations_media.setting_variation_image_id = post_id;
  215. event.preventDefault();
  216. if ( $button.is( '.remove' ) ) {
  217. $( '.upload_image_id', wc_meta_boxes_product_variations_media.setting_variation_image ).val( '' ).change();
  218. wc_meta_boxes_product_variations_media.setting_variation_image.find( 'img' ).eq( 0 ).attr( 'src', woocommerce_admin_meta_boxes_variations.woocommerce_placeholder_img_src );
  219. wc_meta_boxes_product_variations_media.setting_variation_image.find( '.upload_image_button' ).removeClass( 'remove' );
  220. } else {
  221. // If the media frame already exists, reopen it.
  222. if ( wc_meta_boxes_product_variations_media.variable_image_frame ) {
  223. wc_meta_boxes_product_variations_media.variable_image_frame.uploader.uploader.param( 'post_id', wc_meta_boxes_product_variations_media.setting_variation_image_id );
  224. wc_meta_boxes_product_variations_media.variable_image_frame.open();
  225. return;
  226. } else {
  227. wp.media.model.settings.post.id = wc_meta_boxes_product_variations_media.setting_variation_image_id;
  228. }
  229. // Create the media frame.
  230. wc_meta_boxes_product_variations_media.variable_image_frame = wp.media.frames.variable_image = wp.media({
  231. // Set the title of the modal.
  232. title: woocommerce_admin_meta_boxes_variations.i18n_choose_image,
  233. button: {
  234. text: woocommerce_admin_meta_boxes_variations.i18n_set_image
  235. },
  236. states: [
  237. new wp.media.controller.Library({
  238. title: woocommerce_admin_meta_boxes_variations.i18n_choose_image,
  239. filterable: 'all'
  240. })
  241. ]
  242. });
  243. // When an image is selected, run a callback.
  244. wc_meta_boxes_product_variations_media.variable_image_frame.on( 'select', function () {
  245. var attachment = wc_meta_boxes_product_variations_media.variable_image_frame.state().get( 'selection' ).first().toJSON(),
  246. url = attachment.sizes && attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.url;
  247. $( '.upload_image_id', wc_meta_boxes_product_variations_media.setting_variation_image ).val( attachment.id ).change();
  248. wc_meta_boxes_product_variations_media.setting_variation_image.find( '.upload_image_button' ).addClass( 'remove' );
  249. wc_meta_boxes_product_variations_media.setting_variation_image.find( 'img' ).eq( 0 ).attr( 'src', url );
  250. wp.media.model.settings.post.id = wc_meta_boxes_product_variations_media.wp_media_post_id;
  251. });
  252. // Finally, open the modal.
  253. wc_meta_boxes_product_variations_media.variable_image_frame.open();
  254. }
  255. },
  256. /**
  257. * Restore wp.media post ID.
  258. */
  259. restore_wp_media_post_id: function() {
  260. wp.media.model.settings.post.id = wc_meta_boxes_product_variations_media.wp_media_post_id;
  261. }
  262. };
  263. /**
  264. * Product variations metabox ajax methods
  265. */
  266. var wc_meta_boxes_product_variations_ajax = {
  267. /**
  268. * Initialize variations ajax methods
  269. */
  270. init: function() {
  271. $( 'li.variations_tab a' ).on( 'click', this.initial_load );
  272. $( '#variable_product_options' )
  273. .on( 'click', 'button.save-variation-changes', this.save_variations )
  274. .on( 'click', 'button.cancel-variation-changes', this.cancel_variations )
  275. .on( 'click', '.remove_variation', this.remove_variation );
  276. $( document.body )
  277. .on( 'change', '#variable_product_options .woocommerce_variations :input', this.input_changed )
  278. .on( 'change', '.variations-defaults select', this.defaults_changed );
  279. $( 'form#post' ).on( 'submit', this.save_on_submit );
  280. $( '.wc-metaboxes-wrapper' ).on( 'click', 'a.do_variation_action', this.do_variation_action );
  281. },
  282. /**
  283. * Check if have some changes before leave the page
  284. *
  285. * @return {Bool}
  286. */
  287. check_for_changes: function() {
  288. var need_update = $( '#variable_product_options' ).find( '.woocommerce_variations .variation-needs-update' );
  289. if ( 0 < need_update.length ) {
  290. if ( window.confirm( woocommerce_admin_meta_boxes_variations.i18n_edited_variations ) ) {
  291. wc_meta_boxes_product_variations_ajax.save_changes();
  292. } else {
  293. need_update.removeClass( 'variation-needs-update' );
  294. return false;
  295. }
  296. }
  297. return true;
  298. },
  299. /**
  300. * Block edit screen
  301. */
  302. block: function() {
  303. $( '#woocommerce-product-data' ).block({
  304. message: null,
  305. overlayCSS: {
  306. background: '#fff',
  307. opacity: 0.6
  308. }
  309. });
  310. },
  311. /**
  312. * Unblock edit screen
  313. */
  314. unblock: function() {
  315. $( '#woocommerce-product-data' ).unblock();
  316. },
  317. /**
  318. * Initial load variations
  319. *
  320. * @return {Bool}
  321. */
  322. initial_load: function() {
  323. if ( 0 === $( '#variable_product_options' ).find( '.woocommerce_variations .woocommerce_variation' ).length ) {
  324. wc_meta_boxes_product_variations_pagenav.go_to_page();
  325. }
  326. },
  327. /**
  328. * Load variations via Ajax
  329. *
  330. * @param {Int} page (default: 1)
  331. * @param {Int} per_page (default: 10)
  332. */
  333. load_variations: function( page, per_page ) {
  334. page = page || 1;
  335. per_page = per_page || woocommerce_admin_meta_boxes_variations.variations_per_page;
  336. var wrapper = $( '#variable_product_options' ).find( '.woocommerce_variations' );
  337. wc_meta_boxes_product_variations_ajax.block();
  338. $.ajax({
  339. url: woocommerce_admin_meta_boxes_variations.ajax_url,
  340. data: {
  341. action: 'woocommerce_load_variations',
  342. security: woocommerce_admin_meta_boxes_variations.load_variations_nonce,
  343. product_id: woocommerce_admin_meta_boxes_variations.post_id,
  344. attributes: wrapper.data( 'attributes' ),
  345. page: page,
  346. per_page: per_page
  347. },
  348. type: 'POST',
  349. success: function( response ) {
  350. wrapper.empty().append( response ).attr( 'data-page', page );
  351. $( '#woocommerce-product-data' ).trigger( 'woocommerce_variations_loaded' );
  352. wc_meta_boxes_product_variations_ajax.unblock();
  353. }
  354. });
  355. },
  356. /**
  357. * Ger variations fields and convert to object
  358. *
  359. * @param {Object} fields
  360. *
  361. * @return {Object}
  362. */
  363. get_variations_fields: function( fields ) {
  364. var data = $( ':input', fields ).serializeJSON();
  365. $( '.variations-defaults select' ).each( function( index, element ) {
  366. var select = $( element );
  367. data[ select.attr( 'name' ) ] = select.val();
  368. });
  369. return data;
  370. },
  371. /**
  372. * Save variations changes
  373. *
  374. * @param {Function} callback Called once saving is complete
  375. */
  376. save_changes: function( callback ) {
  377. var wrapper = $( '#variable_product_options' ).find( '.woocommerce_variations' ),
  378. need_update = $( '.variation-needs-update', wrapper ),
  379. data = {};
  380. // Save only with products need update.
  381. if ( 0 < need_update.length ) {
  382. wc_meta_boxes_product_variations_ajax.block();
  383. data = wc_meta_boxes_product_variations_ajax.get_variations_fields( need_update );
  384. data.action = 'woocommerce_save_variations';
  385. data.security = woocommerce_admin_meta_boxes_variations.save_variations_nonce;
  386. data.product_id = woocommerce_admin_meta_boxes_variations.post_id;
  387. data['product-type'] = $( '#product-type' ).val();
  388. $.ajax({
  389. url: woocommerce_admin_meta_boxes_variations.ajax_url,
  390. data: data,
  391. type: 'POST',
  392. success: function( response ) {
  393. // Allow change page, delete and add new variations
  394. need_update.removeClass( 'variation-needs-update' );
  395. $( 'button.cancel-variation-changes, button.save-variation-changes' ).attr( 'disabled', 'disabled' );
  396. $( '#woocommerce-product-data' ).trigger( 'woocommerce_variations_saved' );
  397. if ( typeof callback === 'function' ) {
  398. callback( response );
  399. }
  400. wc_meta_boxes_product_variations_ajax.unblock();
  401. }
  402. });
  403. }
  404. },
  405. /**
  406. * Save variations
  407. *
  408. * @return {Bool}
  409. */
  410. save_variations: function() {
  411. $( '#variable_product_options' ).trigger( 'woocommerce_variations_save_variations_button' );
  412. wc_meta_boxes_product_variations_ajax.save_changes( function( error ) {
  413. var wrapper = $( '#variable_product_options' ).find( '.woocommerce_variations' ),
  414. current = wrapper.attr( 'data-page' );
  415. $( '#variable_product_options' ).find( '#woocommerce_errors' ).remove();
  416. if ( error ) {
  417. wrapper.before( error );
  418. }
  419. $( '.variations-defaults select' ).each( function() {
  420. $( this ).attr( 'data-current', $( this ).val() );
  421. });
  422. wc_meta_boxes_product_variations_pagenav.go_to_page( current );
  423. });
  424. return false;
  425. },
  426. /**
  427. * Save on post form submit
  428. */
  429. save_on_submit: function( e ) {
  430. var need_update = $( '#variable_product_options' ).find( '.woocommerce_variations .variation-needs-update' );
  431. if ( 0 < need_update.length ) {
  432. e.preventDefault();
  433. $( '#variable_product_options' ).trigger( 'woocommerce_variations_save_variations_on_submit' );
  434. wc_meta_boxes_product_variations_ajax.save_changes( wc_meta_boxes_product_variations_ajax.save_on_submit_done );
  435. }
  436. },
  437. /**
  438. * After saved, continue with form submission
  439. */
  440. save_on_submit_done: function() {
  441. $( 'form#post' ).submit();
  442. },
  443. /**
  444. * Discart changes.
  445. *
  446. * @return {Bool}
  447. */
  448. cancel_variations: function() {
  449. var current = parseInt( $( '#variable_product_options' ).find( '.woocommerce_variations' ).attr( 'data-page' ), 10 );
  450. $( '#variable_product_options' ).find( '.woocommerce_variations .variation-needs-update' ).removeClass( 'variation-needs-update' );
  451. $( '.variations-defaults select' ).each( function() {
  452. $( this ).val( $( this ).attr( 'data-current' ) );
  453. });
  454. wc_meta_boxes_product_variations_pagenav.go_to_page( current );
  455. return false;
  456. },
  457. /**
  458. * Add variation
  459. *
  460. * @return {Bool}
  461. */
  462. add_variation: function() {
  463. wc_meta_boxes_product_variations_ajax.block();
  464. var data = {
  465. action: 'woocommerce_add_variation',
  466. post_id: woocommerce_admin_meta_boxes_variations.post_id,
  467. loop: $( '.woocommerce_variation' ).length,
  468. security: woocommerce_admin_meta_boxes_variations.add_variation_nonce
  469. };
  470. $.post( woocommerce_admin_meta_boxes_variations.ajax_url, data, function( response ) {
  471. var variation = $( response );
  472. variation.addClass( 'variation-needs-update' );
  473. $( '#variable_product_options' ).find( '.woocommerce_variations' ).prepend( variation );
  474. $( 'button.cancel-variation-changes, button.save-variation-changes' ).removeAttr( 'disabled' );
  475. $( '#variable_product_options' ).trigger( 'woocommerce_variations_added', 1 );
  476. wc_meta_boxes_product_variations_ajax.unblock();
  477. });
  478. return false;
  479. },
  480. /**
  481. * Remove variation
  482. *
  483. * @return {Bool}
  484. */
  485. remove_variation: function() {
  486. wc_meta_boxes_product_variations_ajax.check_for_changes();
  487. if ( window.confirm( woocommerce_admin_meta_boxes_variations.i18n_remove_variation ) ) {
  488. var variation = $( this ).attr( 'rel' ),
  489. variation_ids = [],
  490. data = {
  491. action: 'woocommerce_remove_variations'
  492. };
  493. wc_meta_boxes_product_variations_ajax.block();
  494. if ( 0 < variation ) {
  495. variation_ids.push( variation );
  496. data.variation_ids = variation_ids;
  497. data.security = woocommerce_admin_meta_boxes_variations.delete_variations_nonce;
  498. $.post( woocommerce_admin_meta_boxes_variations.ajax_url, data, function() {
  499. var wrapper = $( '#variable_product_options' ).find( '.woocommerce_variations' ),
  500. current_page = parseInt( wrapper.attr( 'data-page' ), 10 ),
  501. total_pages = Math.ceil( ( parseInt( wrapper.attr( 'data-total' ), 10 ) - 1 ) / woocommerce_admin_meta_boxes_variations.variations_per_page ),
  502. page = 1;
  503. $( '#woocommerce-product-data' ).trigger( 'woocommerce_variations_removed' );
  504. if ( current_page === total_pages || current_page <= total_pages ) {
  505. page = current_page;
  506. } else if ( current_page > total_pages && 0 !== total_pages ) {
  507. page = total_pages;
  508. }
  509. wc_meta_boxes_product_variations_pagenav.go_to_page( page, -1 );
  510. });
  511. } else {
  512. wc_meta_boxes_product_variations_ajax.unblock();
  513. }
  514. }
  515. return false;
  516. },
  517. /**
  518. * Link all variations (or at least try :p)
  519. *
  520. * @return {Bool}
  521. */
  522. link_all_variations: function() {
  523. wc_meta_boxes_product_variations_ajax.check_for_changes();
  524. if ( window.confirm( woocommerce_admin_meta_boxes_variations.i18n_link_all_variations ) ) {
  525. wc_meta_boxes_product_variations_ajax.block();
  526. var data = {
  527. action: 'woocommerce_link_all_variations',
  528. post_id: woocommerce_admin_meta_boxes_variations.post_id,
  529. security: woocommerce_admin_meta_boxes_variations.link_variation_nonce
  530. };
  531. $.post( woocommerce_admin_meta_boxes_variations.ajax_url, data, function( response ) {
  532. var count = parseInt( response, 10 );
  533. if ( 1 === count ) {
  534. window.alert( count + ' ' + woocommerce_admin_meta_boxes_variations.i18n_variation_added );
  535. } else if ( 0 === count || count > 1 ) {
  536. window.alert( count + ' ' + woocommerce_admin_meta_boxes_variations.i18n_variations_added );
  537. } else {
  538. window.alert( woocommerce_admin_meta_boxes_variations.i18n_no_variations_added );
  539. }
  540. if ( count > 0 ) {
  541. wc_meta_boxes_product_variations_pagenav.go_to_page( 1, count );
  542. $( '#variable_product_options' ).trigger( 'woocommerce_variations_added', count );
  543. } else {
  544. wc_meta_boxes_product_variations_ajax.unblock();
  545. }
  546. });
  547. }
  548. return false;
  549. },
  550. /**
  551. * Add new class when have changes in some input
  552. */
  553. input_changed: function() {
  554. $( this )
  555. .closest( '.woocommerce_variation' )
  556. .addClass( 'variation-needs-update' );
  557. $( 'button.cancel-variation-changes, button.save-variation-changes' ).removeAttr( 'disabled' );
  558. $( '#variable_product_options' ).trigger( 'woocommerce_variations_input_changed' );
  559. },
  560. /**
  561. * Added new .variation-needs-update class when defaults is changed
  562. */
  563. defaults_changed: function() {
  564. $( this )
  565. .closest( '#variable_product_options' )
  566. .find( '.woocommerce_variation:first' )
  567. .addClass( 'variation-needs-update' );
  568. $( 'button.cancel-variation-changes, button.save-variation-changes' ).removeAttr( 'disabled' );
  569. $( '#variable_product_options' ).trigger( 'woocommerce_variations_defaults_changed' );
  570. },
  571. /**
  572. * Actions
  573. */
  574. do_variation_action: function() {
  575. var do_variation_action = $( 'select.variation_actions' ).val(),
  576. data = {},
  577. changes = 0,
  578. value;
  579. switch ( do_variation_action ) {
  580. case 'add_variation' :
  581. wc_meta_boxes_product_variations_ajax.add_variation();
  582. return;
  583. case 'link_all_variations' :
  584. wc_meta_boxes_product_variations_ajax.link_all_variations();
  585. return;
  586. case 'delete_all' :
  587. if ( window.confirm( woocommerce_admin_meta_boxes_variations.i18n_delete_all_variations ) ) {
  588. if ( window.confirm( woocommerce_admin_meta_boxes_variations.i18n_last_warning ) ) {
  589. data.allowed = true;
  590. changes = parseInt( $( '#variable_product_options' ).find( '.woocommerce_variations' ).attr( 'data-total' ), 10 ) * -1;
  591. }
  592. }
  593. break;
  594. case 'variable_regular_price_increase' :
  595. case 'variable_regular_price_decrease' :
  596. case 'variable_sale_price_increase' :
  597. case 'variable_sale_price_decrease' :
  598. value = window.prompt( woocommerce_admin_meta_boxes_variations.i18n_enter_a_value_fixed_or_percent );
  599. if ( value != null ) {
  600. if ( value.indexOf( '%' ) >= 0 ) {
  601. data.value = accounting.unformat( value.replace( /\%/, '' ), woocommerce_admin.mon_decimal_point ) + '%';
  602. } else {
  603. data.value = accounting.unformat( value, woocommerce_admin.mon_decimal_point );
  604. }
  605. } else {
  606. return;
  607. }
  608. break;
  609. case 'variable_regular_price' :
  610. case 'variable_sale_price' :
  611. case 'variable_stock' :
  612. case 'variable_weight' :
  613. case 'variable_length' :
  614. case 'variable_width' :
  615. case 'variable_height' :
  616. case 'variable_download_limit' :
  617. case 'variable_download_expiry' :
  618. value = window.prompt( woocommerce_admin_meta_boxes_variations.i18n_enter_a_value );
  619. if ( value != null ) {
  620. data.value = value;
  621. } else {
  622. return;
  623. }
  624. break;
  625. case 'variable_sale_schedule' :
  626. data.date_from = window.prompt( woocommerce_admin_meta_boxes_variations.i18n_scheduled_sale_start );
  627. data.date_to = window.prompt( woocommerce_admin_meta_boxes_variations.i18n_scheduled_sale_end );
  628. if ( null === data.date_from ) {
  629. data.date_from = false;
  630. }
  631. if ( null === data.date_to ) {
  632. data.date_to = false;
  633. }
  634. if ( false === data.date_to && false === data.date_from ) {
  635. return;
  636. }
  637. break;
  638. default :
  639. $( 'select.variation_actions' ).trigger( do_variation_action );
  640. data = $( 'select.variation_actions' ).triggerHandler( do_variation_action + '_ajax_data', data );
  641. break;
  642. }
  643. if ( 'delete_all' === do_variation_action && data.allowed ) {
  644. $( '#variable_product_options' ).find( '.variation-needs-update' ).removeClass( 'variation-needs-update' );
  645. } else {
  646. wc_meta_boxes_product_variations_ajax.check_for_changes();
  647. }
  648. wc_meta_boxes_product_variations_ajax.block();
  649. $.ajax({
  650. url: woocommerce_admin_meta_boxes_variations.ajax_url,
  651. data: {
  652. action: 'woocommerce_bulk_edit_variations',
  653. security: woocommerce_admin_meta_boxes_variations.bulk_edit_variations_nonce,
  654. product_id: woocommerce_admin_meta_boxes_variations.post_id,
  655. product_type: $( '#product-type' ).val(),
  656. bulk_action: do_variation_action,
  657. data: data
  658. },
  659. type: 'POST',
  660. success: function() {
  661. wc_meta_boxes_product_variations_pagenav.go_to_page( 1, changes );
  662. }
  663. });
  664. }
  665. };
  666. /**
  667. * Product variations pagenav
  668. */
  669. var wc_meta_boxes_product_variations_pagenav = {
  670. /**
  671. * Initialize products variations meta box
  672. */
  673. init: function() {
  674. $( document.body )
  675. .on( 'woocommerce_variations_added', this.update_single_quantity )
  676. .on( 'change', '.variations-pagenav .page-selector', this.page_selector )
  677. .on( 'click', '.variations-pagenav .first-page', this.first_page )
  678. .on( 'click', '.variations-pagenav .prev-page', this.prev_page )
  679. .on( 'click', '.variations-pagenav .next-page', this.next_page )
  680. .on( 'click', '.variations-pagenav .last-page', this.last_page );
  681. },
  682. /**
  683. * Set variations count
  684. *
  685. * @param {Int} qty
  686. *
  687. * @return {Int}
  688. */
  689. update_variations_count: function( qty ) {
  690. var wrapper = $( '#variable_product_options' ).find( '.woocommerce_variations' ),
  691. total = parseInt( wrapper.attr( 'data-total' ), 10 ) + qty,
  692. displaying_num = $( '.variations-pagenav .displaying-num' );
  693. // Set the new total of variations
  694. wrapper.attr( 'data-total', total );
  695. if ( 1 === total ) {
  696. displaying_num.text( woocommerce_admin_meta_boxes_variations.i18n_variation_count_single.replace( '%qty%', total ) );
  697. } else {
  698. displaying_num.text( woocommerce_admin_meta_boxes_variations.i18n_variation_count_plural.replace( '%qty%', total ) );
  699. }
  700. return total;
  701. },
  702. /**
  703. * Update variations quantity when add a new variation
  704. *
  705. * @param {Object} event
  706. * @param {Int} qty
  707. */
  708. update_single_quantity: function( event, qty ) {
  709. if ( 1 === qty ) {
  710. var page_nav = $( '.variations-pagenav' );
  711. wc_meta_boxes_product_variations_pagenav.update_variations_count( qty );
  712. if ( page_nav.is( ':hidden' ) ) {
  713. $( 'option, optgroup', '.variation_actions' ).show();
  714. $( '.variation_actions' ).val( 'add_variation' );
  715. $( '#variable_product_options' ).find( '.toolbar' ).show();
  716. page_nav.show();
  717. $( '.pagination-links', page_nav ).hide();
  718. }
  719. }
  720. },
  721. /**
  722. * Set the pagenav fields
  723. *
  724. * @param {Int} qty
  725. */
  726. set_paginav: function( qty ) {
  727. var wrapper = $( '#variable_product_options' ).find( '.woocommerce_variations' ),
  728. new_qty = wc_meta_boxes_product_variations_pagenav.update_variations_count( qty ),
  729. toolbar = $( '#variable_product_options' ).find( '.toolbar' ),
  730. variation_action = $( '.variation_actions' ),
  731. page_nav = $( '.variations-pagenav' ),
  732. displaying_links = $( '.pagination-links', page_nav ),
  733. total_pages = Math.ceil( new_qty / woocommerce_admin_meta_boxes_variations.variations_per_page ),
  734. options = '';
  735. // Set the new total of pages
  736. wrapper.attr( 'data-total_pages', total_pages );
  737. $( '.total-pages', page_nav ).text( total_pages );
  738. // Set the new pagenav options
  739. for ( var i = 1; i <= total_pages; i++ ) {
  740. options += '<option value="' + i + '">' + i + '</option>';
  741. }
  742. $( '.page-selector', page_nav ).empty().html( options );
  743. // Show/hide pagenav
  744. if ( 0 === new_qty ) {
  745. toolbar.not( '.toolbar-top, .toolbar-buttons' ).hide();
  746. page_nav.hide();
  747. $( 'option, optgroup', variation_action ).hide();
  748. $( '.variation_actions' ).val( 'add_variation' );
  749. $( 'option[data-global="true"]', variation_action ).show();
  750. } else {
  751. toolbar.show();
  752. page_nav.show();
  753. $( 'option, optgroup', variation_action ).show();
  754. $( '.variation_actions' ).val( 'add_variation' );
  755. // Show/hide links
  756. if ( 1 === total_pages ) {
  757. displaying_links.hide();
  758. } else {
  759. displaying_links.show();
  760. }
  761. }
  762. },
  763. /**
  764. * Check button if enabled and if don't have changes
  765. *
  766. * @return {Bool}
  767. */
  768. check_is_enabled: function( current ) {
  769. return ! $( current ).hasClass( 'disabled' );
  770. },
  771. /**
  772. * Change "disabled" class on pagenav
  773. */
  774. change_classes: function( selected, total ) {
  775. var first_page = $( '.variations-pagenav .first-page' ),
  776. prev_page = $( '.variations-pagenav .prev-page' ),
  777. next_page = $( '.variations-pagenav .next-page' ),
  778. last_page = $( '.variations-pagenav .last-page' );
  779. if ( 1 === selected ) {
  780. first_page.addClass( 'disabled' );
  781. prev_page.addClass( 'disabled' );
  782. } else {
  783. first_page.removeClass( 'disabled' );
  784. prev_page.removeClass( 'disabled' );
  785. }
  786. if ( total === selected ) {
  787. next_page.addClass( 'disabled' );
  788. last_page.addClass( 'disabled' );
  789. } else {
  790. next_page.removeClass( 'disabled' );
  791. last_page.removeClass( 'disabled' );
  792. }
  793. },
  794. /**
  795. * Set page
  796. */
  797. set_page: function( page ) {
  798. $( '.variations-pagenav .page-selector' ).val( page ).first().change();
  799. },
  800. /**
  801. * Navigate on variations pages
  802. *
  803. * @param {Int} page
  804. * @param {Int} qty
  805. */
  806. go_to_page: function( page, qty ) {
  807. page = page || 1;
  808. qty = qty || 0;
  809. wc_meta_boxes_product_variations_pagenav.set_paginav( qty );
  810. wc_meta_boxes_product_variations_pagenav.set_page( page );
  811. },
  812. /**
  813. * Paginav pagination selector
  814. */
  815. page_selector: function() {
  816. var selected = parseInt( $( this ).val(), 10 ),
  817. wrapper = $( '#variable_product_options' ).find( '.woocommerce_variations' );
  818. $( '.variations-pagenav .page-selector' ).val( selected );
  819. wc_meta_boxes_product_variations_ajax.check_for_changes();
  820. wc_meta_boxes_product_variations_pagenav.change_classes( selected, parseInt( wrapper.attr( 'data-total_pages' ), 10 ) );
  821. wc_meta_boxes_product_variations_ajax.load_variations( selected );
  822. },
  823. /**
  824. * Go to first page
  825. *
  826. * @return {Bool}
  827. */
  828. first_page: function() {
  829. if ( wc_meta_boxes_product_variations_pagenav.check_is_enabled( this ) ) {
  830. wc_meta_boxes_product_variations_pagenav.set_page( 1 );
  831. }
  832. return false;
  833. },
  834. /**
  835. * Go to previous page
  836. *
  837. * @return {Bool}
  838. */
  839. prev_page: function() {
  840. if ( wc_meta_boxes_product_variations_pagenav.check_is_enabled( this ) ) {
  841. var wrapper = $( '#variable_product_options' ).find( '.woocommerce_variations' ),
  842. prev_page = parseInt( wrapper.attr( 'data-page' ), 10 ) - 1,
  843. new_page = ( 0 < prev_page ) ? prev_page : 1;
  844. wc_meta_boxes_product_variations_pagenav.set_page( new_page );
  845. }
  846. return false;
  847. },
  848. /**
  849. * Go to next page
  850. *
  851. * @return {Bool}
  852. */
  853. next_page: function() {
  854. if ( wc_meta_boxes_product_variations_pagenav.check_is_enabled( this ) ) {
  855. var wrapper = $( '#variable_product_options' ).find( '.woocommerce_variations' ),
  856. total_pages = parseInt( wrapper.attr( 'data-total_pages' ), 10 ),
  857. next_page = parseInt( wrapper.attr( 'data-page' ), 10 ) + 1,
  858. new_page = ( total_pages >= next_page ) ? next_page : total_pages;
  859. wc_meta_boxes_product_variations_pagenav.set_page( new_page );
  860. }
  861. return false;
  862. },
  863. /**
  864. * Go to last page
  865. *
  866. * @return {Bool}
  867. */
  868. last_page: function() {
  869. if ( wc_meta_boxes_product_variations_pagenav.check_is_enabled( this ) ) {
  870. var last_page = $( '#variable_product_options' ).find( '.woocommerce_variations' ).attr( 'data-total_pages' );
  871. wc_meta_boxes_product_variations_pagenav.set_page( last_page );
  872. }
  873. return false;
  874. }
  875. };
  876. wc_meta_boxes_product_variations_actions.init();
  877. wc_meta_boxes_product_variations_media.init();
  878. wc_meta_boxes_product_variations_ajax.init();
  879. wc_meta_boxes_product_variations_pagenav.init();
  880. });