Geen omschrijving

wc-shipping-zone-methods.js 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. /* global shippingZoneMethodsLocalizeScript, ajaxurl */
  2. ( function( $, data, wp, ajaxurl ) {
  3. $( function() {
  4. var $table = $( '.wc-shipping-zone-methods' ),
  5. $tbody = $( '.wc-shipping-zone-method-rows' ),
  6. $save_button = $( '.wc-shipping-zone-method-save' ),
  7. $row_template = wp.template( 'wc-shipping-zone-method-row' ),
  8. $blank_template = wp.template( 'wc-shipping-zone-method-row-blank' ),
  9. // Backbone model
  10. ShippingMethod = Backbone.Model.extend({
  11. changes: {},
  12. logChanges: function( changedRows ) {
  13. var changes = this.changes || {};
  14. _.each( changedRows.methods, function( row, id ) {
  15. changes.methods = changes.methods || { methods : {} };
  16. changes.methods[ id ] = _.extend( changes.methods[ id ] || { instance_id : id }, row );
  17. } );
  18. if ( typeof changedRows.zone_name !== 'undefined' ) {
  19. changes.zone_name = changedRows.zone_name;
  20. }
  21. if ( typeof changedRows.zone_locations !== 'undefined' ) {
  22. changes.zone_locations = changedRows.zone_locations;
  23. }
  24. if ( typeof changedRows.zone_postcodes !== 'undefined' ) {
  25. changes.zone_postcodes = changedRows.zone_postcodes;
  26. }
  27. this.changes = changes;
  28. this.trigger( 'change:methods' );
  29. },
  30. save: function() {
  31. $.post(
  32. ajaxurl + ( ajaxurl.indexOf( '?' ) > 0 ? '&' : '?' ) + 'action=woocommerce_shipping_zone_methods_save_changes',
  33. {
  34. wc_shipping_zones_nonce : data.wc_shipping_zones_nonce,
  35. changes : this.changes,
  36. zone_id : data.zone_id
  37. },
  38. this.onSaveResponse,
  39. 'json'
  40. );
  41. },
  42. onSaveResponse: function( response, textStatus ) {
  43. if ( 'success' === textStatus ) {
  44. if ( response.success ) {
  45. if ( response.data.zone_id !== data.zone_id ) {
  46. data.zone_id = response.data.zone_id;
  47. if ( window.history.pushState ) {
  48. window.history.pushState(
  49. {},
  50. '',
  51. 'admin.php?page=wc-settings&tab=shipping&zone_id=' + response.data.zone_id
  52. );
  53. }
  54. }
  55. shippingMethod.set( 'methods', response.data.methods );
  56. shippingMethod.trigger( 'change:methods' );
  57. shippingMethod.changes = {};
  58. shippingMethod.trigger( 'saved:methods' );
  59. // Overrides the onbeforeunload callback added by settings.js.
  60. window.onbeforeunload = null;
  61. } else {
  62. window.alert( data.strings.save_failed );
  63. }
  64. }
  65. }
  66. } ),
  67. // Backbone view
  68. ShippingMethodView = Backbone.View.extend({
  69. rowTemplate: $row_template,
  70. initialize: function() {
  71. this.listenTo( this.model, 'change:methods', this.setUnloadConfirmation );
  72. this.listenTo( this.model, 'saved:methods', this.clearUnloadConfirmation );
  73. this.listenTo( this.model, 'saved:methods', this.render );
  74. $tbody.on( 'change', { view: this }, this.updateModelOnChange );
  75. $tbody.on( 'sortupdate', { view: this }, this.updateModelOnSort );
  76. $( window ).on( 'beforeunload', { view: this }, this.unloadConfirmation );
  77. $save_button.on( 'click', { view: this }, this.onSubmit );
  78. $( document.body ).on(
  79. 'input change',
  80. '#zone_name, #zone_locations, #zone_postcodes',
  81. { view: this },
  82. this.onUpdateZone
  83. );
  84. $( document.body ).on( 'click', '.wc-shipping-zone-method-settings', { view: this }, this.onConfigureShippingMethod );
  85. $( document.body ).on( 'click', '.wc-shipping-zone-add-method', { view: this }, this.onAddShippingMethod );
  86. $( document.body ).on( 'wc_backbone_modal_response', this.onConfigureShippingMethodSubmitted );
  87. $( document.body ).on( 'wc_backbone_modal_response', this.onAddShippingMethodSubmitted );
  88. $( document.body ).on( 'change', '.wc-shipping-zone-method-selector select', this.onChangeShippingMethodSelector );
  89. $( document.body ).on( 'click', '.wc-shipping-zone-postcodes-toggle', this.onTogglePostcodes );
  90. },
  91. onUpdateZone: function( event ) {
  92. var view = event.data.view,
  93. model = view.model,
  94. value = $( this ).val(),
  95. $target = $( event.target ),
  96. attribute = $target.data( 'attribute' ),
  97. changes = {};
  98. event.preventDefault();
  99. changes[ attribute ] = value;
  100. model.set( attribute, value );
  101. model.logChanges( changes );
  102. view.render();
  103. },
  104. block: function() {
  105. $( this.el ).block({
  106. message: null,
  107. overlayCSS: {
  108. background: '#fff',
  109. opacity: 0.6
  110. }
  111. });
  112. },
  113. unblock: function() {
  114. $( this.el ).unblock();
  115. },
  116. render: function() {
  117. var methods = _.indexBy( this.model.get( 'methods' ), 'instance_id' ),
  118. zone_name = this.model.get( 'zone_name' ),
  119. view = this;
  120. // Set name.
  121. $('.wc-shipping-zone-name').text( zone_name ? zone_name : data.strings.default_zone_name );
  122. // Blank out the contents.
  123. this.$el.empty();
  124. this.unblock();
  125. if ( _.size( methods ) ) {
  126. // Sort methods
  127. methods = _.sortBy( methods, function( method ) {
  128. return parseInt( method.method_order, 10 );
  129. } );
  130. // Populate $tbody with the current methods
  131. $.each( methods, function( id, rowData ) {
  132. if ( 'yes' === rowData.enabled ) {
  133. rowData.enabled_icon = '<span class="woocommerce-input-toggle woocommerce-input-toggle--enabled">' +
  134. data.strings.yes +
  135. '</span>';
  136. } else {
  137. rowData.enabled_icon = '<span class="woocommerce-input-toggle woocommerce-input-toggle--disabled">' +
  138. data.strings.no +
  139. '</span>';
  140. }
  141. view.$el.append( view.rowTemplate( rowData ) );
  142. var $tr = view.$el.find( 'tr[data-id="' + rowData.instance_id + '"]');
  143. if ( ! rowData.has_settings ) {
  144. $tr
  145. .find( '.wc-shipping-zone-method-title > a' )
  146. .replaceWith('<span>' + $tr.find( '.wc-shipping-zone-method-title > a' ).text() + '</span>' );
  147. var $del = $tr.find( '.wc-shipping-zone-method-delete' );
  148. $tr.find( '.wc-shipping-zone-method-title .row-actions' ).empty().html($del);
  149. }
  150. } );
  151. // Make the rows function
  152. this.$el.find( '.wc-shipping-zone-method-delete' ).on( 'click', { view: this }, this.onDeleteRow );
  153. this.$el.find( '.wc-shipping-zone-method-enabled a').on( 'click', { view: this }, this.onToggleEnabled );
  154. } else {
  155. view.$el.append( $blank_template );
  156. }
  157. this.initTooltips();
  158. },
  159. initTooltips: function() {
  160. $( '#tiptip_holder' ).removeAttr( 'style' );
  161. $( '#tiptip_arrow' ).removeAttr( 'style' );
  162. $( '.tips' ).tipTip({ 'attribute': 'data-tip', 'fadeIn': 50, 'fadeOut': 50, 'delay': 50 });
  163. },
  164. onSubmit: function( event ) {
  165. event.data.view.block();
  166. event.data.view.model.save();
  167. event.preventDefault();
  168. },
  169. onDeleteRow: function( event ) {
  170. var view = event.data.view,
  171. model = view.model,
  172. methods = _.indexBy( model.get( 'methods' ), 'instance_id' ),
  173. changes = {},
  174. instance_id = $( this ).closest('tr').data('id');
  175. event.preventDefault();
  176. delete methods[ instance_id ];
  177. changes.methods = changes.methods || { methods : {} };
  178. changes.methods[ instance_id ] = _.extend( changes.methods[ instance_id ] || {}, { deleted : 'deleted' } );
  179. model.set( 'methods', methods );
  180. model.logChanges( changes );
  181. view.render();
  182. },
  183. onToggleEnabled: function( event ) {
  184. var view = event.data.view,
  185. $target = $( event.target ),
  186. model = view.model,
  187. methods = _.indexBy( model.get( 'methods' ), 'instance_id' ),
  188. instance_id = $target.closest( 'tr' ).data( 'id' ),
  189. enabled = $target.closest( 'tr' ).data( 'enabled' ) === 'yes' ? 'no' : 'yes',
  190. changes = {};
  191. event.preventDefault();
  192. methods[ instance_id ].enabled = enabled;
  193. changes.methods = changes.methods || { methods : {} };
  194. changes.methods[ instance_id ] = _.extend( changes.methods[ instance_id ] || {}, { enabled : enabled } );
  195. model.set( 'methods', methods );
  196. model.logChanges( changes );
  197. view.render();
  198. },
  199. setUnloadConfirmation: function() {
  200. this.needsUnloadConfirm = true;
  201. $save_button.prop( 'disabled', false );
  202. },
  203. clearUnloadConfirmation: function() {
  204. this.needsUnloadConfirm = false;
  205. $save_button.attr( 'disabled', 'disabled' );
  206. },
  207. unloadConfirmation: function( event ) {
  208. if ( event.data.view.needsUnloadConfirm ) {
  209. event.returnValue = data.strings.unload_confirmation_msg;
  210. window.event.returnValue = data.strings.unload_confirmation_msg;
  211. return data.strings.unload_confirmation_msg;
  212. }
  213. },
  214. updateModelOnChange: function( event ) {
  215. var model = event.data.view.model,
  216. $target = $( event.target ),
  217. instance_id = $target.closest( 'tr' ).data( 'id' ),
  218. attribute = $target.data( 'attribute' ),
  219. value = $target.val(),
  220. methods = _.indexBy( model.get( 'methods' ), 'instance_id' ),
  221. changes = {};
  222. if ( methods[ instance_id ][ attribute ] !== value ) {
  223. changes.methods[ instance_id ] = {};
  224. changes.methods[ instance_id ][ attribute ] = value;
  225. methods[ instance_id ][ attribute ] = value;
  226. }
  227. model.logChanges( changes );
  228. },
  229. updateModelOnSort: function( event ) {
  230. var view = event.data.view,
  231. model = view.model,
  232. methods = _.indexBy( model.get( 'methods' ), 'instance_id' ),
  233. changes = {};
  234. _.each( methods, function( method ) {
  235. var old_position = parseInt( method.method_order, 10 );
  236. var new_position = parseInt( $table.find( 'tr[data-id="' + method.instance_id + '"]').index() + 1, 10 );
  237. if ( old_position !== new_position ) {
  238. methods[ method.instance_id ].method_order = new_position;
  239. changes.methods = changes.methods || { methods : {} };
  240. changes.methods[ method.instance_id ] = _.extend(
  241. changes.methods[ method.instance_id ] || {}, { method_order : new_position }
  242. );
  243. }
  244. } );
  245. if ( _.size( changes ) ) {
  246. model.logChanges( changes );
  247. }
  248. },
  249. onConfigureShippingMethod: function( event ) {
  250. var instance_id = $( this ).closest( 'tr' ).data( 'id' ),
  251. model = event.data.view.model,
  252. methods = _.indexBy( model.get( 'methods' ), 'instance_id' ),
  253. method = methods[ instance_id ];
  254. // Only load modal if supported
  255. if ( ! method.settings_html ) {
  256. return true;
  257. }
  258. event.preventDefault();
  259. $( this ).WCBackboneModal({
  260. template : 'wc-modal-shipping-method-settings',
  261. variable : {
  262. instance_id : instance_id,
  263. method : method
  264. },
  265. data : {
  266. instance_id : instance_id,
  267. method : method
  268. }
  269. });
  270. $( document.body ).trigger( 'init_tooltips' );
  271. },
  272. onConfigureShippingMethodSubmitted: function( event, target, posted_data ) {
  273. if ( 'wc-modal-shipping-method-settings' === target ) {
  274. shippingMethodView.block();
  275. // Save method settings via ajax call
  276. $.post(
  277. ajaxurl + ( ajaxurl.indexOf( '?' ) > 0 ? '&' : '?' ) + 'action=woocommerce_shipping_zone_methods_save_settings',
  278. {
  279. wc_shipping_zones_nonce : data.wc_shipping_zones_nonce,
  280. instance_id : posted_data.instance_id,
  281. data : posted_data
  282. },
  283. function( response, textStatus ) {
  284. if ( 'success' === textStatus && response.success ) {
  285. $( 'table.wc-shipping-zone-methods' ).parent().find( '#woocommerce_errors' ).remove();
  286. // If there were errors, prepend the form.
  287. if ( response.data.errors.length > 0 ) {
  288. shippingMethodView.showErrors( response.data.errors );
  289. }
  290. // Method was saved. Re-render.
  291. if ( _.size( shippingMethodView.model.changes ) ) {
  292. shippingMethodView.model.save();
  293. } else {
  294. shippingMethodView.model.onSaveResponse( response, textStatus );
  295. }
  296. } else {
  297. window.alert( data.strings.save_failed );
  298. shippingMethodView.unblock();
  299. }
  300. },
  301. 'json'
  302. );
  303. }
  304. },
  305. showErrors: function( errors ) {
  306. var error_html = '<div id="woocommerce_errors" class="error notice is-dismissible">';
  307. $( errors ).each( function( index, value ) {
  308. error_html = error_html + '<p>' + value + '</p>';
  309. } );
  310. error_html = error_html + '</div>';
  311. $( 'table.wc-shipping-zone-methods' ).before( error_html );
  312. },
  313. onAddShippingMethod: function( event ) {
  314. event.preventDefault();
  315. $( this ).WCBackboneModal({
  316. template : 'wc-modal-add-shipping-method',
  317. variable : {
  318. zone_id : data.zone_id
  319. }
  320. });
  321. $( '.wc-shipping-zone-method-selector select' ).trigger( 'change' );
  322. },
  323. onAddShippingMethodSubmitted: function( event, target, posted_data ) {
  324. if ( 'wc-modal-add-shipping-method' === target ) {
  325. shippingMethodView.block();
  326. // Add method to zone via ajax call
  327. $.post( ajaxurl + ( ajaxurl.indexOf( '?' ) > 0 ? '&' : '?' ) + 'action=woocommerce_shipping_zone_add_method', {
  328. wc_shipping_zones_nonce : data.wc_shipping_zones_nonce,
  329. method_id : posted_data.add_method_id,
  330. zone_id : data.zone_id
  331. }, function( response, textStatus ) {
  332. if ( 'success' === textStatus && response.success ) {
  333. if ( response.data.zone_id !== data.zone_id ) {
  334. data.zone_id = response.data.zone_id;
  335. if ( window.history.pushState ) {
  336. window.history.pushState(
  337. {},
  338. '',
  339. 'admin.php?page=wc-settings&tab=shipping&zone_id=' + response.data.zone_id
  340. );
  341. }
  342. }
  343. // Trigger save if there are changes, or just re-render
  344. if ( _.size( shippingMethodView.model.changes ) ) {
  345. shippingMethodView.model.save();
  346. } else {
  347. shippingMethodView.model.set( 'methods', response.data.methods );
  348. shippingMethodView.model.trigger( 'change:methods' );
  349. shippingMethodView.model.changes = {};
  350. shippingMethodView.model.trigger( 'saved:methods' );
  351. }
  352. }
  353. shippingMethodView.unblock();
  354. }, 'json' );
  355. }
  356. },
  357. onChangeShippingMethodSelector: function() {
  358. var description = $( this ).find( 'option:selected' ).data( 'description' );
  359. $( this ).parent().find( '.wc-shipping-zone-method-description' ).remove();
  360. $( this ).after( '<div class="wc-shipping-zone-method-description">' + description + '</div>' );
  361. $( this ).closest( 'article' ).height( $( this ).parent().height() );
  362. },
  363. onTogglePostcodes: function( event ) {
  364. event.preventDefault();
  365. var $tr = $( this ).closest( 'tr');
  366. $tr.find( '.wc-shipping-zone-postcodes' ).show();
  367. $tr.find( '.wc-shipping-zone-postcodes-toggle' ).hide();
  368. }
  369. } ),
  370. shippingMethod = new ShippingMethod({
  371. methods: data.methods,
  372. zone_name: data.zone_name
  373. } ),
  374. shippingMethodView = new ShippingMethodView({
  375. model: shippingMethod,
  376. el: $tbody
  377. } );
  378. shippingMethodView.render();
  379. $tbody.sortable({
  380. items: 'tr',
  381. cursor: 'move',
  382. axis: 'y',
  383. handle: 'td.wc-shipping-zone-method-sort',
  384. scrollSensitivity: 40
  385. });
  386. });
  387. })( jQuery, shippingZoneMethodsLocalizeScript, wp, ajaxurl );