wc-shipping-classes.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /* global shippingClassesLocalizeScript, ajaxurl */
  2. ( function( $, data, wp, ajaxurl ) {
  3. $( function() {
  4. var $tbody = $( '.wc-shipping-class-rows' ),
  5. $save_button = $( '.wc-shipping-class-save' ),
  6. $row_template = wp.template( 'wc-shipping-class-row' ),
  7. $blank_template = wp.template( 'wc-shipping-class-row-blank' ),
  8. // Backbone model
  9. ShippingClass = Backbone.Model.extend({
  10. changes: {},
  11. logChanges: function( changedRows ) {
  12. var changes = this.changes || {};
  13. _.each( changedRows, function( row, id ) {
  14. changes[ id ] = _.extend( changes[ id ] || { term_id : id }, row );
  15. } );
  16. this.changes = changes;
  17. this.trigger( 'change:classes' );
  18. },
  19. save: function() {
  20. if ( _.size( this.changes ) ) {
  21. $.post( ajaxurl + ( ajaxurl.indexOf( '?' ) > 0 ? '&' : '?' ) + 'action=woocommerce_shipping_classes_save_changes', {
  22. wc_shipping_classes_nonce : data.wc_shipping_classes_nonce,
  23. changes : this.changes
  24. }, this.onSaveResponse, 'json' );
  25. } else {
  26. shippingClass.trigger( 'saved:classes' );
  27. }
  28. },
  29. discardChanges: function( id ) {
  30. var changes = this.changes || {};
  31. // Delete all changes
  32. delete changes[ id ];
  33. // No changes? Disable save button.
  34. if ( 0 === _.size( this.changes ) ) {
  35. shippingClassView.clearUnloadConfirmation();
  36. }
  37. },
  38. onSaveResponse: function( response, textStatus ) {
  39. if ( 'success' === textStatus ) {
  40. if ( response.success ) {
  41. shippingClass.set( 'classes', response.data.shipping_classes );
  42. shippingClass.trigger( 'change:classes' );
  43. shippingClass.changes = {};
  44. shippingClass.trigger( 'saved:classes' );
  45. } else if ( response.data ) {
  46. window.alert( response.data );
  47. } else {
  48. window.alert( data.strings.save_failed );
  49. }
  50. }
  51. shippingClassView.unblock();
  52. }
  53. } ),
  54. // Backbone view
  55. ShippingClassView = Backbone.View.extend({
  56. rowTemplate: $row_template,
  57. initialize: function() {
  58. this.listenTo( this.model, 'change:classes', this.setUnloadConfirmation );
  59. this.listenTo( this.model, 'saved:classes', this.clearUnloadConfirmation );
  60. this.listenTo( this.model, 'saved:classes', this.render );
  61. $tbody.on( 'change', { view: this }, this.updateModelOnChange );
  62. $( window ).on( 'beforeunload', { view: this }, this.unloadConfirmation );
  63. $save_button.on( 'click', { view: this }, this.onSubmit );
  64. $( document.body ).on( 'click', '.wc-shipping-class-add', { view: this }, this.onAddNewRow );
  65. $( document.body ).on( 'click', '.wc-shipping-class-save-changes', { view: this }, this.onSubmit );
  66. },
  67. block: function() {
  68. $( this.el ).block({
  69. message: null,
  70. overlayCSS: {
  71. background: '#fff',
  72. opacity: 0.6
  73. }
  74. });
  75. },
  76. unblock: function() {
  77. $( this.el ).unblock();
  78. },
  79. render: function() {
  80. var classes = _.indexBy( this.model.get( 'classes' ), 'term_id' ),
  81. view = this;
  82. this.$el.empty();
  83. this.unblock();
  84. if ( _.size( classes ) ) {
  85. // Sort classes
  86. classes = _.sortBy( classes, function( shipping_class ) {
  87. return shipping_class.name;
  88. } );
  89. // Populate $tbody with the current classes
  90. $.each( classes, function( id, rowData ) {
  91. view.renderRow( rowData );
  92. } );
  93. } else {
  94. view.$el.append( $blank_template );
  95. }
  96. },
  97. renderRow: function( rowData ) {
  98. var view = this;
  99. view.$el.append( view.rowTemplate( rowData ) );
  100. view.initRow( rowData );
  101. },
  102. initRow: function( rowData ) {
  103. var view = this;
  104. var $tr = view.$el.find( 'tr[data-id="' + rowData.term_id + '"]');
  105. // Support select boxes
  106. $tr.find( 'select' ).each( function() {
  107. var attribute = $( this ).data( 'attribute' );
  108. $( this ).find( 'option[value="' + rowData[ attribute ] + '"]' ).prop( 'selected', true );
  109. } );
  110. // Make the rows function
  111. $tr.find( '.view' ).show();
  112. $tr.find( '.edit' ).hide();
  113. $tr.find( '.wc-shipping-class-edit' ).on( 'click', { view: this }, this.onEditRow );
  114. $tr.find( '.wc-shipping-class-delete' ).on( 'click', { view: this }, this.onDeleteRow );
  115. $tr.find( '.editing .wc-shipping-class-edit' ).trigger('click');
  116. $tr.find( '.wc-shipping-class-cancel-edit' ).on( 'click', { view: this }, this.onCancelEditRow );
  117. // Editing?
  118. if ( true === rowData.editing ) {
  119. $tr.addClass( 'editing' );
  120. $tr.find( '.wc-shipping-class-edit' ).trigger( 'click' );
  121. }
  122. },
  123. onSubmit: function( event ) {
  124. event.data.view.block();
  125. event.data.view.model.save();
  126. event.preventDefault();
  127. },
  128. onAddNewRow: function( event ) {
  129. event.preventDefault();
  130. var view = event.data.view,
  131. model = view.model,
  132. classes = _.indexBy( model.get( 'classes' ), 'term_id' ),
  133. changes = {},
  134. size = _.size( classes ),
  135. newRow = _.extend( {}, data.default_shipping_class, {
  136. term_id: 'new-' + size + '-' + Date.now(),
  137. editing: true,
  138. newRow : true
  139. } );
  140. changes[ newRow.term_id ] = newRow;
  141. model.logChanges( changes );
  142. view.renderRow( newRow );
  143. $( '.wc-shipping-classes-blank-state' ).remove();
  144. },
  145. onEditRow: function( event ) {
  146. event.preventDefault();
  147. $( this ).closest('tr').addClass('editing');
  148. $( this ).closest('tr').find('.view').hide();
  149. $( this ).closest('tr').find('.edit').show();
  150. event.data.view.model.trigger( 'change:classes' );
  151. },
  152. onDeleteRow: function( event ) {
  153. var view = event.data.view,
  154. model = view.model,
  155. classes = _.indexBy( model.get( 'classes' ), 'term_id' ),
  156. changes = {},
  157. term_id = $( this ).closest('tr').data('id');
  158. event.preventDefault();
  159. if ( classes[ term_id ] ) {
  160. delete classes[ term_id ];
  161. changes[ term_id ] = _.extend( changes[ term_id ] || {}, { deleted : 'deleted' } );
  162. model.set( 'classes', classes );
  163. model.logChanges( changes );
  164. }
  165. view.render();
  166. },
  167. onCancelEditRow: function( event ) {
  168. var view = event.data.view,
  169. model = view.model,
  170. row = $( this ).closest('tr'),
  171. term_id = $( this ).closest('tr').data('id'),
  172. classes = _.indexBy( model.get( 'classes' ), 'term_id' );
  173. event.preventDefault();
  174. model.discardChanges( term_id );
  175. if ( classes[ term_id ] ) {
  176. classes[ term_id ].editing = false;
  177. row.after( view.rowTemplate( classes[ term_id ] ) );
  178. view.initRow( classes[ term_id ] );
  179. }
  180. row.remove();
  181. },
  182. setUnloadConfirmation: function() {
  183. this.needsUnloadConfirm = true;
  184. $save_button.removeAttr( 'disabled' );
  185. },
  186. clearUnloadConfirmation: function() {
  187. this.needsUnloadConfirm = false;
  188. $save_button.attr( 'disabled', 'disabled' );
  189. },
  190. unloadConfirmation: function( event ) {
  191. if ( event.data.view.needsUnloadConfirm ) {
  192. event.returnValue = data.strings.unload_confirmation_msg;
  193. window.event.returnValue = data.strings.unload_confirmation_msg;
  194. return data.strings.unload_confirmation_msg;
  195. }
  196. },
  197. updateModelOnChange: function( event ) {
  198. var model = event.data.view.model,
  199. $target = $( event.target ),
  200. term_id = $target.closest( 'tr' ).data( 'id' ),
  201. attribute = $target.data( 'attribute' ),
  202. value = $target.val(),
  203. classes = _.indexBy( model.get( 'classes' ), 'term_id' ),
  204. changes = {};
  205. if ( ! classes[ term_id ] || classes[ term_id ][ attribute ] !== value ) {
  206. changes[ term_id ] = {};
  207. changes[ term_id ][ attribute ] = value;
  208. }
  209. model.logChanges( changes );
  210. }
  211. } ),
  212. shippingClass = new ShippingClass({
  213. classes: data.classes
  214. } ),
  215. shippingClassView = new ShippingClassView({
  216. model: shippingClass,
  217. el: $tbody
  218. } );
  219. shippingClassView.render();
  220. });
  221. })( jQuery, shippingClassesLocalizeScript, wp, ajaxurl );