wc-shipping-zones.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /* global shippingZonesLocalizeScript, ajaxurl */
  2. ( function( $, data, wp, ajaxurl ) {
  3. $( function() {
  4. var $table = $( '.wc-shipping-zones' ),
  5. $tbody = $( '.wc-shipping-zone-rows' ),
  6. $save_button = $( '.wc-shipping-zone-save' ),
  7. $row_template = wp.template( 'wc-shipping-zone-row' ),
  8. $blank_template = wp.template( 'wc-shipping-zone-row-blank' ),
  9. // Backbone model
  10. ShippingZone = Backbone.Model.extend({
  11. changes: {},
  12. logChanges: function( changedRows ) {
  13. var changes = this.changes || {};
  14. _.each( changedRows, function( row, id ) {
  15. changes[ id ] = _.extend( changes[ id ] || { zone_id : id }, row );
  16. } );
  17. this.changes = changes;
  18. this.trigger( 'change:zones' );
  19. },
  20. discardChanges: function( id ) {
  21. var changes = this.changes || {},
  22. set_position = null,
  23. zones = _.indexBy( this.get( 'zones' ), 'zone_id' );
  24. // Find current set position if it has moved since last save
  25. if ( changes[ id ] && changes[ id ].zone_order !== undefined ) {
  26. set_position = changes[ id ].zone_order;
  27. }
  28. // Delete all changes
  29. delete changes[ id ];
  30. // If the position was set, and this zone does exist in DB, set the position again so the changes are not lost.
  31. if ( set_position !== null && zones[ id ] && zones[ id ].zone_order !== set_position ) {
  32. changes[ id ] = _.extend( changes[ id ] || {}, { zone_id : id, zone_order : set_position } );
  33. }
  34. this.changes = changes;
  35. // No changes? Disable save button.
  36. if ( 0 === _.size( this.changes ) ) {
  37. shippingZoneView.clearUnloadConfirmation();
  38. }
  39. },
  40. save: function() {
  41. if ( _.size( this.changes ) ) {
  42. $.post( ajaxurl + ( ajaxurl.indexOf( '?' ) > 0 ? '&' : '?' ) + 'action=woocommerce_shipping_zones_save_changes', {
  43. wc_shipping_zones_nonce : data.wc_shipping_zones_nonce,
  44. changes : this.changes
  45. }, this.onSaveResponse, 'json' );
  46. } else {
  47. shippingZone.trigger( 'saved:zones' );
  48. }
  49. },
  50. onSaveResponse: function( response, textStatus ) {
  51. if ( 'success' === textStatus ) {
  52. if ( response.success ) {
  53. shippingZone.set( 'zones', response.data.zones );
  54. shippingZone.trigger( 'change:zones' );
  55. shippingZone.changes = {};
  56. shippingZone.trigger( 'saved:zones' );
  57. } else {
  58. window.alert( data.strings.save_failed );
  59. }
  60. }
  61. }
  62. } ),
  63. // Backbone view
  64. ShippingZoneView = Backbone.View.extend({
  65. rowTemplate: $row_template,
  66. initialize: function() {
  67. this.listenTo( this.model, 'change:zones', this.setUnloadConfirmation );
  68. this.listenTo( this.model, 'saved:zones', this.clearUnloadConfirmation );
  69. this.listenTo( this.model, 'saved:zones', this.render );
  70. $tbody.on( 'change', { view: this }, this.updateModelOnChange );
  71. $tbody.on( 'sortupdate', { view: this }, this.updateModelOnSort );
  72. $( window ).on( 'beforeunload', { view: this }, this.unloadConfirmation );
  73. $( document.body ).on( 'click', '.wc-shipping-zone-add', { view: this }, this.onAddNewRow );
  74. },
  75. block: function() {
  76. $( this.el ).block({
  77. message: null,
  78. overlayCSS: {
  79. background: '#fff',
  80. opacity: 0.6
  81. }
  82. });
  83. },
  84. unblock: function() {
  85. $( this.el ).unblock();
  86. },
  87. render: function() {
  88. var zones = _.indexBy( this.model.get( 'zones' ), 'zone_id' ),
  89. view = this;
  90. view.$el.empty();
  91. view.unblock();
  92. if ( _.size( zones ) ) {
  93. // Sort zones
  94. zones = _( zones )
  95. .chain()
  96. .sortBy( function ( zone ) { return parseInt( zone.zone_id, 10 ); } )
  97. .sortBy( function ( zone ) { return parseInt( zone.zone_order, 10 ); } )
  98. .value();
  99. // Populate $tbody with the current zones
  100. $.each( zones, function( id, rowData ) {
  101. view.renderRow( rowData );
  102. } );
  103. } else {
  104. view.$el.append( $blank_template );
  105. }
  106. view.initRows();
  107. },
  108. renderRow: function( rowData ) {
  109. var view = this;
  110. view.$el.append( view.rowTemplate( rowData ) );
  111. view.initRow( rowData );
  112. },
  113. initRow: function( rowData ) {
  114. var view = this;
  115. var $tr = view.$el.find( 'tr[data-id="' + rowData.zone_id + '"]');
  116. // List shipping methods
  117. view.renderShippingMethods( rowData.zone_id, rowData.shipping_methods );
  118. $tr.find( '.wc-shipping-zone-delete' ).on( 'click', { view: this }, this.onDeleteRow );
  119. },
  120. initRows: function() {
  121. // Stripe
  122. if ( 0 === ( $( 'tbody.wc-shipping-zone-rows tr' ).length % 2 ) ) {
  123. $table.find( 'tbody.wc-shipping-zone-rows' ).next( 'tbody' ).find( 'tr' ).addClass( 'odd' );
  124. } else {
  125. $table.find( 'tbody.wc-shipping-zone-rows' ).next( 'tbody' ).find( 'tr' ).removeClass( 'odd' );
  126. }
  127. // Tooltips
  128. $( '#tiptip_holder' ).removeAttr( 'style' );
  129. $( '#tiptip_arrow' ).removeAttr( 'style' );
  130. $( '.tips' ).tipTip({ 'attribute': 'data-tip', 'fadeIn': 50, 'fadeOut': 50, 'delay': 50 });
  131. },
  132. renderShippingMethods: function( zone_id, shipping_methods ) {
  133. var $tr = $( '.wc-shipping-zones tr[data-id="' + zone_id + '"]');
  134. var $method_list = $tr.find('.wc-shipping-zone-methods ul');
  135. $method_list.find( '.wc-shipping-zone-method' ).remove();
  136. if ( _.size( shipping_methods ) ) {
  137. shipping_methods = _.sortBy( shipping_methods, function( method ) {
  138. return parseInt( method.method_order, 10 );
  139. } );
  140. _.each( shipping_methods, function( shipping_method ) {
  141. var class_name = 'method_disabled';
  142. if ( 'yes' === shipping_method.enabled ) {
  143. class_name = 'method_enabled';
  144. }
  145. $method_list.append( '<li class="wc-shipping-zone-method ' + class_name + '">' + shipping_method.title + '</li>' );
  146. } );
  147. } else {
  148. $method_list.append( '<li class="wc-shipping-zone-method">' + data.strings.no_shipping_methods_offered + '</li>' );
  149. }
  150. },
  151. onDeleteRow: function( event ) {
  152. var view = event.data.view,
  153. model = view.model,
  154. zones = _.indexBy( model.get( 'zones' ), 'zone_id' ),
  155. changes = {},
  156. row = $( this ).closest('tr'),
  157. zone_id = row.data('id');
  158. event.preventDefault();
  159. if ( window.confirm( data.strings.delete_confirmation_msg ) ) {
  160. if ( zones[ zone_id ] ) {
  161. delete zones[ zone_id ];
  162. changes[ zone_id ] = _.extend( changes[ zone_id ] || {}, { deleted : 'deleted' } );
  163. model.set( 'zones', zones );
  164. model.logChanges( changes );
  165. event.data.view.block();
  166. event.data.view.model.save();
  167. }
  168. }
  169. },
  170. setUnloadConfirmation: function() {
  171. this.needsUnloadConfirm = true;
  172. $save_button.prop( 'disabled', false );
  173. },
  174. clearUnloadConfirmation: function() {
  175. this.needsUnloadConfirm = false;
  176. $save_button.prop( 'disabled', true );
  177. },
  178. unloadConfirmation: function( event ) {
  179. if ( event.data.view.needsUnloadConfirm ) {
  180. event.returnValue = data.strings.unload_confirmation_msg;
  181. window.event.returnValue = data.strings.unload_confirmation_msg;
  182. return data.strings.unload_confirmation_msg;
  183. }
  184. },
  185. updateModelOnChange: function( event ) {
  186. var model = event.data.view.model,
  187. $target = $( event.target ),
  188. zone_id = $target.closest( 'tr' ).data( 'id' ),
  189. attribute = $target.data( 'attribute' ),
  190. value = $target.val(),
  191. zones = _.indexBy( model.get( 'zones' ), 'zone_id' ),
  192. changes = {};
  193. if ( ! zones[ zone_id ] || zones[ zone_id ][ attribute ] !== value ) {
  194. changes[ zone_id ] = {};
  195. changes[ zone_id ][ attribute ] = value;
  196. }
  197. model.logChanges( changes );
  198. },
  199. updateModelOnSort: function( event ) {
  200. var view = event.data.view,
  201. model = view.model,
  202. zones = _.indexBy( model.get( 'zones' ), 'zone_id' ),
  203. rows = $( 'tbody.wc-shipping-zone-rows tr' ),
  204. changes = {};
  205. // Update sorted row position
  206. _.each( rows, function( row ) {
  207. var zone_id = $( row ).data( 'id' ),
  208. old_position = null,
  209. new_position = parseInt( $( row ).index(), 10 );
  210. if ( zones[ zone_id ] ) {
  211. old_position = parseInt( zones[ zone_id ].zone_order, 10 );
  212. }
  213. if ( old_position !== new_position ) {
  214. changes[ zone_id ] = _.extend( changes[ zone_id ] || {}, { zone_order : new_position } );
  215. }
  216. } );
  217. if ( _.size( changes ) ) {
  218. model.logChanges( changes );
  219. event.data.view.block();
  220. event.data.view.model.save();
  221. }
  222. }
  223. } ),
  224. shippingZone = new ShippingZone({
  225. zones: data.zones
  226. } ),
  227. shippingZoneView = new ShippingZoneView({
  228. model: shippingZone,
  229. el: $tbody
  230. } );
  231. shippingZoneView.render();
  232. $tbody.sortable({
  233. items: 'tr',
  234. cursor: 'move',
  235. axis: 'y',
  236. handle: 'td.wc-shipping-zone-sort',
  237. scrollSensitivity: 40
  238. });
  239. });
  240. })( jQuery, shippingZonesLocalizeScript, wp, ajaxurl );