customizer.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /* global jQuery, jpSimplePaymentsStrings, confirm, _ */
  2. /* eslint no-var: 0, quote-props: 0 */
  3. ( function( api, wp, $ ) {
  4. var $document = $( document );
  5. $document.ready( function() {
  6. $document.on( 'widget-added', function( event, widgetContainer ) {
  7. if ( widgetContainer.is( '[id*="jetpack_simple_payments_widget"]' ) ) {
  8. initWidget( widgetContainer );
  9. }
  10. } );
  11. $document.on( 'widget-synced widget-updated', function( event, widgetContainer ) {
  12. //this fires for all widgets, this prevent errors for non SP widgets
  13. if ( ! widgetContainer.is( '[id*="jetpack_simple_payments_widget"]' ) ) {
  14. return;
  15. }
  16. event.preventDefault();
  17. syncProductLists();
  18. var widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' );
  19. enableFormActions( widgetForm );
  20. updateProductImage( widgetForm );
  21. } );
  22. } );
  23. function initWidget( widgetContainer ) {
  24. var widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' );
  25. //Add New Button
  26. widgetForm.find( '.jetpack-simple-payments-add-product' ).on( 'click', showAddNewForm( widgetForm ) );
  27. //Edit Button
  28. widgetForm.find( '.jetpack-simple-payments-edit-product' ).on( 'click', showEditForm( widgetForm ) );
  29. //Select an Image
  30. widgetForm.find( '.jetpack-simple-payments-image-fieldset .placeholder, .jetpack-simple-payments-image > img' ).on( 'click', selectImage( widgetForm ) );
  31. //Remove Image Button
  32. widgetForm.find( '.jetpack-simple-payments-remove-image' ).on( 'click', removeImage( widgetForm ) );
  33. //Save Product button
  34. widgetForm.find( '.jetpack-simple-payments-save-product' ).on( 'click', saveChanges( widgetForm ) );
  35. //Cancel Button
  36. widgetForm.find( '.jetpack-simple-payments-cancel-form' ).on( 'click', clearForm( widgetForm ) );
  37. //Delete Selected Product
  38. widgetForm.find( '.jetpack-simple-payments-delete-product' ).on( 'click', deleteProduct( widgetForm ) );
  39. //Input, Select and Checkbox change
  40. widgetForm.find( 'select, input, textarea, checkbox' ).on( 'change input propertychange', _.debounce( function() {
  41. disableFormActions( widgetForm );
  42. }, 250 ) );
  43. }
  44. function syncProductLists() {
  45. var request = wp.ajax.post( 'customize-jetpack-simple-payments-buttons-get', {
  46. 'customize-jetpack-simple-payments-nonce': api.settings.nonce[ 'customize-jetpack-simple-payments' ],
  47. 'customize_changeset_uuid': api.settings.changeset.uuid
  48. } );
  49. request.done( function( data ) {
  50. var selectedProduct = 0;
  51. $( document ).find( 'select.jetpack-simple-payments-products' ).each( function( index, select ) {
  52. var $select = $( select );
  53. selectedProduct = $select.val();
  54. $select.find( 'option' ).remove();
  55. $select.append( $.map( data, function( product ) {
  56. return $( '<option>', { value: product.ID, text: product.post_title } );
  57. } ) );
  58. $select.val( selectedProduct );
  59. } );
  60. } );
  61. }
  62. function showForm( widgetForm ) {
  63. //reset validations
  64. widgetForm.find( '.invalid' ).removeClass( 'invalid' );
  65. //disable widget title and product selector
  66. widgetForm.find( '.jetpack-simple-payments-widget-title' )
  67. .add( '.jetpack-simple-payments-products' )
  68. //disable add and edit buttons
  69. .add( '.jetpack-simple-payments-add-product' )
  70. .add( '.jetpack-simple-payments-edit-product' )
  71. //disable save, delete and cancel until the widget update event is fired
  72. .add( '.jetpack-simple-payments-save-product' )
  73. .add( '.jetpack-simple-payments-cancel-form' )
  74. .add( '.jetpack-simple-payments-delete-product' )
  75. .attr( 'disabled', 'disabled' );
  76. //show form
  77. widgetForm.find( '.jetpack-simple-payments-form' ).show();
  78. }
  79. function hideForm( widgetForm ) {
  80. //enable widget title and product selector
  81. widgetForm.find( '.jetpack-simple-payments-widget-title' )
  82. .add( '.jetpack-simple-payments-products' )
  83. .removeAttr( 'disabled' );
  84. //hide the form
  85. widgetForm.find( '.jetpack-simple-payments-form' ).hide();
  86. }
  87. function changeFormAction( widgetForm, action ) {
  88. widgetForm.find( '.jetpack-simple-payments-form-action' ).val( action ).change();
  89. }
  90. function showAddNewForm( widgetForm ) {
  91. return function( event ) {
  92. event.preventDefault();
  93. showForm( widgetForm );
  94. changeFormAction( widgetForm, 'add' );
  95. };
  96. }
  97. function showEditForm( widgetForm ) {
  98. return function( event ) {
  99. event.preventDefault();
  100. showForm( widgetForm );
  101. changeFormAction( widgetForm, 'edit' );
  102. };
  103. }
  104. function clearForm( widgetForm ) {
  105. return function( event ) {
  106. event.preventDefault();
  107. hideForm( widgetForm );
  108. widgetForm.find( '.jetpack-simple-payments-add-product, .jetpack-simple-payments-edit-product' ).attr( 'disabled', 'disabled' );
  109. changeFormAction( widgetForm, 'clear' );
  110. };
  111. }
  112. function enableFormActions( widgetForm ) {
  113. var isFormVisible = widgetForm.find( '.jetpack-simple-payments-form' ).is( ':visible' );
  114. var isProductSelectVisible = widgetForm.find( '.jetpack-simple-payments-products' ).is( ':visible' ); //areProductsVisible ?
  115. var isEdit = widgetForm.find( '.jetpack-simple-payments-form-action' ).val() === 'edit';
  116. if ( isFormVisible ) {
  117. widgetForm.find( '.jetpack-simple-payments-save-product' )
  118. .add( '.jetpack-simple-payments-cancel-form' )
  119. .removeAttr( 'disabled' );
  120. } else {
  121. widgetForm.find( '.jetpack-simple-payments-add-product' ).removeAttr( 'disabled' );
  122. }
  123. if ( isFormVisible && isEdit ) {
  124. widgetForm.find( '.jetpack-simple-payments-delete-product' ).removeAttr( 'disabled' );
  125. }
  126. if ( isProductSelectVisible && ! isFormVisible ) {
  127. widgetForm.find( '.jetpack-simple-payments-edit-product' ).removeAttr( 'disabled' );
  128. }
  129. }
  130. function disableFormActions( widgetForm ) {
  131. widgetForm.find( '.jetpack-simple-payments-add-product' )
  132. .add( '.jetpack-simple-payments-edit-product' )
  133. .add( '.jetpack-simple-payments-save-product' )
  134. .add( '.jetpack-simple-payments-cancel-form' )
  135. .add( '.jetpack-simple-payments-delete-product' )
  136. .attr( 'disabled', 'disabled' );
  137. }
  138. function selectImage( widgetForm ) {
  139. return function( event ) {
  140. event.preventDefault();
  141. var imageContainer = widgetForm.find( '.jetpack-simple-payments-image' );
  142. var mediaFrame = new wp.media.view.MediaFrame.Select( {
  143. title: 'Choose Product Image',
  144. multiple: false,
  145. library: { type: 'image' },
  146. button: { text: 'Choose Image' }
  147. } );
  148. mediaFrame.on( 'select', function() {
  149. var selection = mediaFrame.state().get( 'selection' ).first().toJSON();
  150. //hide placeholder
  151. widgetForm.find( '.jetpack-simple-payments-image-fieldset .placeholder' ).hide();
  152. //load image from media library
  153. imageContainer.find( 'img' )
  154. .attr( 'src', selection.url )
  155. .show();
  156. //show image and remove button
  157. widgetForm.find( '.jetpack-simple-payments-image' ).show();
  158. //set hidden field for the selective refresh
  159. widgetForm.find( '.jetpack-simple-payments-form-image-id' ).val( selection.id ).change();
  160. } );
  161. mediaFrame.open();
  162. };
  163. }
  164. function removeImage( widgetForm ) {
  165. return function( event ) {
  166. event.preventDefault();
  167. //show placeholder
  168. widgetForm.find( '.jetpack-simple-payments-image-fieldset .placeholder' ).show();
  169. //hide image and remove button
  170. widgetForm.find( '.jetpack-simple-payments-image' ).hide();
  171. //set hidden field for the selective refresh
  172. widgetForm.find( '.jetpack-simple-payments-form-image-id' ).val( '' ).change();
  173. };
  174. }
  175. function updateProductImage( widgetForm ) {
  176. var newImageId = parseInt( widgetForm.find( '.jetpack-simple-payments-form-image-id' ).val(), 10 );
  177. var newImageSrc = widgetForm.find( '.jetpack-simple-payments-form-image-src' ).val();
  178. var placeholder = widgetForm.find( '.jetpack-simple-payments-image-fieldset .placeholder' );
  179. var image = widgetForm.find( '.jetpack-simple-payments-image > img' );
  180. var imageControls = widgetForm.find( '.jetpack-simple-payments-image' );
  181. if ( newImageId && newImageSrc ) {
  182. image.attr( 'src', newImageSrc );
  183. placeholder.hide();
  184. imageControls.show();
  185. } else {
  186. placeholder.show();
  187. image.removeAttr( 'src' );
  188. imageControls.hide();
  189. }
  190. }
  191. function decimalPlaces( number ) {
  192. var parts = number.split( '.' );
  193. if ( parts.length > 2 ) {
  194. return null;
  195. }
  196. return parts[ 1 ] ? parts[ 1 ].length : 0;
  197. }
  198. function isFormValid( widgetForm ) {
  199. widgetForm.find( '.invalid' ).removeClass( 'invalid' );
  200. var errors = false;
  201. var postTitle = widgetForm.find( '.jetpack-simple-payments-form-product-title' ).val();
  202. if ( ! postTitle ) {
  203. widgetForm.find( '.jetpack-simple-payments-form-product-title' ).addClass( 'invalid' );
  204. errors = true;
  205. }
  206. var productPrice = widgetForm.find( '.jetpack-simple-payments-form-product-price' ).val();
  207. if ( ! productPrice || isNaN( productPrice ) || parseFloat( productPrice ) <= 0 ) {
  208. widgetForm.find( '.jetpack-simple-payments-form-product-price' ).addClass( 'invalid' );
  209. errors = true;
  210. }
  211. // Japan's Yen is the only supported currency with a zero decimal precision.
  212. var precision = widgetForm.find( '.jetpack-simple-payments-form-product-currency' ).val() === 'JPY' ? 0 : 2;
  213. var priceDecimalPlaces = decimalPlaces( productPrice );
  214. if ( priceDecimalPlaces === null || priceDecimalPlaces > precision ) {
  215. widgetForm.find( '.jetpack-simple-payments-form-product-price' ).addClass( 'invalid' );
  216. errors = true;
  217. }
  218. var productEmail = widgetForm.find( '.jetpack-simple-payments-form-product-email' ).val();
  219. var isProductEmailValid = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test( productEmail );
  220. if ( ! productEmail || ! isProductEmailValid ) {
  221. widgetForm.find( '.jetpack-simple-payments-form-product-email' ).addClass( 'invalid' );
  222. errors = true;
  223. }
  224. return ! errors;
  225. }
  226. function saveChanges( widgetForm ) {
  227. return function( event ) {
  228. event.preventDefault();
  229. var productPostId = widgetForm.find( '.jetpack-simple-payments-form-product-id' ).val();
  230. if ( ! isFormValid( widgetForm ) ) {
  231. return;
  232. }
  233. disableFormActions( widgetForm );
  234. widgetForm.find( '.spinner' ).show();
  235. var request = wp.ajax.post( 'customize-jetpack-simple-payments-button-save', {
  236. 'customize-jetpack-simple-payments-nonce': api.settings.nonce[ 'customize-jetpack-simple-payments' ],
  237. 'customize_changeset_uuid': api.settings.changeset.uuid,
  238. 'params': {
  239. 'product_post_id': productPostId,
  240. 'post_title': widgetForm.find( '.jetpack-simple-payments-form-product-title' ).val(),
  241. 'post_content': widgetForm.find( '.jetpack-simple-payments-form-product-description' ).val(),
  242. 'image_id': widgetForm.find( '.jetpack-simple-payments-form-image-id' ).val(),
  243. 'currency': widgetForm.find( '.jetpack-simple-payments-form-product-currency' ).val(),
  244. 'price': widgetForm.find( '.jetpack-simple-payments-form-product-price' ).val(),
  245. 'multiple': widgetForm.find( '.jetpack-simple-payments-form-product-multiple' ).is( ':checked' ) ? 1 : 0,
  246. 'email': widgetForm.find( '.jetpack-simple-payments-form-product-email' ).val()
  247. }
  248. } );
  249. request.done( function( data ) {
  250. var select = widgetForm.find( 'select.jetpack-simple-payments-products' );
  251. var productOption = select.find( 'option[value="' + productPostId + '"]' );
  252. if ( productOption.length > 0 ) {
  253. productOption.text( data.product_post_title );
  254. } else {
  255. select.append(
  256. $( '<option>', {
  257. value: data.product_post_id,
  258. text: data.product_post_title
  259. } )
  260. );
  261. select.val( data.product_post_id ).change();
  262. }
  263. widgetForm.find( '.jetpack-simple-payments-products-fieldset' ).show();
  264. widgetForm.find( '.jetpack-simple-payments-products-warning' ).hide();
  265. changeFormAction( widgetForm, 'clear' );
  266. hideForm( widgetForm );
  267. } );
  268. request.fail( function( data ) {
  269. var validCodes = {
  270. 'post_title': 'product-title',
  271. 'price': 'product-price',
  272. 'email': 'product-email'
  273. };
  274. data.forEach( function( item ) {
  275. if ( validCodes.hasOwnProperty( item.code ) ) {
  276. widgetForm.find( '.jetpack-simple-payments-form-' + validCodes[ item.code ] ).addClass( 'invalid' );
  277. }
  278. } );
  279. enableFormActions( widgetForm );
  280. } );
  281. };
  282. }
  283. function deleteProduct( widgetForm ) {
  284. return function( event ) {
  285. event.preventDefault();
  286. if ( ! confirm( jpSimplePaymentsStrings.deleteConfirmation ) ) {
  287. return;
  288. }
  289. var formProductId = parseInt( widgetForm.find( '.jetpack-simple-payments-form-product-id' ).val(), 10 );
  290. if ( ! formProductId ) {
  291. return;
  292. }
  293. disableFormActions( widgetForm );
  294. widgetForm.find( '.spinner' ).show();
  295. var request = wp.ajax.post( 'customize-jetpack-simple-payments-button-delete', {
  296. 'customize-jetpack-simple-payments-nonce': api.settings.nonce[ 'customize-jetpack-simple-payments' ],
  297. 'customize_changeset_uuid': api.settings.changeset.uuid,
  298. 'params': {
  299. 'product_post_id': formProductId
  300. }
  301. } );
  302. request.done( function() {
  303. var productList = widgetForm.find( 'select.jetpack-simple-payments-products' )[ 0 ];
  304. productList.remove( productList.selectedIndex );
  305. productList.dispatchEvent( new Event( 'change' ) );
  306. if ( $( productList ).has( 'option' ).length === 0 ) {
  307. //hide products select and label
  308. widgetForm.find( '.jetpack-simple-payments-products-fieldset' ).hide();
  309. //show empty products list warning
  310. widgetForm.find( '.jetpack-simple-payments-products-warning' ).show();
  311. }
  312. changeFormAction( widgetForm, 'clear' );
  313. hideForm( widgetForm );
  314. } );
  315. };
  316. }
  317. }( wp.customize, wp, jQuery ) );