asyncForm.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import App from '../base'
  2. import 'libs/passfield'
  3. App.directive('asyncForm', ($http, validateCaptcha, validateCaptchaV3) => ({
  4. controller: [
  5. '$scope',
  6. function($scope) {
  7. this.getEmail = () => $scope.email
  8. return this
  9. }
  10. ],
  11. link(scope, element, attrs) {
  12. let response
  13. const formName = attrs.asyncForm
  14. scope[attrs.name].response = response = {}
  15. scope[attrs.name].inflight = false
  16. const validateCaptchaIfEnabled = function(callback) {
  17. if (attrs.captchaActionName) {
  18. validateCaptchaV3(attrs.captchaActionName)
  19. }
  20. if (attrs.captcha != null) {
  21. validateCaptcha(callback)
  22. } else {
  23. callback()
  24. }
  25. }
  26. const submitRequest = function(grecaptchaResponse) {
  27. const formData = {}
  28. for (let data of Array.from(element.serializeArray())) {
  29. formData[data.name] = data.value
  30. }
  31. if (grecaptchaResponse) {
  32. formData['g-recaptcha-response'] = grecaptchaResponse
  33. }
  34. // clear the response object which may be referenced downstream
  35. Object.keys(response).forEach(field => delete response[field])
  36. scope[attrs.name].inflight = true
  37. // for asyncForm prevent automatic redirect to /login if
  38. // authentication fails, we will handle it ourselves
  39. const httpRequestFn = _httpRequestFn(element.attr('method'))
  40. return httpRequestFn(element.attr('action'), formData, {
  41. disableAutoLoginRedirect: true
  42. })
  43. .then(function(httpResponse) {
  44. const { data, headers } = httpResponse
  45. scope[attrs.name].inflight = false
  46. response.success = true
  47. response.error = false
  48. const onSuccessHandler = scope[attrs.onSuccess]
  49. if (onSuccessHandler) {
  50. onSuccessHandler(httpResponse)
  51. return
  52. }
  53. if (data.redir) {
  54. ga('send', 'event', formName, 'success')
  55. return (window.location = data.redir)
  56. } else if (data.message) {
  57. response.message = data.message
  58. if (data.message.type === 'error') {
  59. response.success = false
  60. response.error = true
  61. return ga('send', 'event', formName, 'failure', data.message)
  62. } else {
  63. return ga('send', 'event', formName, 'success')
  64. }
  65. } else if (scope.$eval(attrs.asyncFormDownloadResponse)) {
  66. const blob = new Blob([data], {
  67. type: headers('Content-Type')
  68. })
  69. location.href = URL.createObjectURL(blob) // Trigger file save
  70. }
  71. })
  72. .catch(function(httpResponse) {
  73. const { data, status } = httpResponse
  74. scope[attrs.name].inflight = false
  75. response.success = false
  76. response.error = true
  77. response.status = status
  78. response.data = data
  79. const onErrorHandler = scope[attrs.onError]
  80. if (onErrorHandler) {
  81. onErrorHandler(httpResponse)
  82. return
  83. }
  84. let responseMessage
  85. if (data.message && data.message.text) {
  86. responseMessage = data.message.text
  87. } else {
  88. responseMessage = data.message
  89. }
  90. if (status === 400) {
  91. // Bad Request
  92. response.message = {
  93. text:
  94. responseMessage ||
  95. 'Invalid Request. Please correct the data and try again.',
  96. type: 'error'
  97. }
  98. } else if (status === 403) {
  99. // Forbidden
  100. response.message = {
  101. text:
  102. responseMessage ||
  103. 'Session error. Please check you have cookies enabled. If the problem persists, try clearing your cache and cookies.',
  104. type: 'error'
  105. }
  106. } else if (status === 429) {
  107. response.message = {
  108. text:
  109. responseMessage ||
  110. 'Too many attempts. Please wait for a while and try again.',
  111. type: 'error'
  112. }
  113. } else {
  114. response.message = {
  115. text:
  116. responseMessage ||
  117. 'Something went wrong talking to the server :(. Please try again.',
  118. type: 'error'
  119. }
  120. }
  121. ga('send', 'event', formName, 'failure', data.message)
  122. })
  123. }
  124. const submit = () =>
  125. validateCaptchaIfEnabled(response => submitRequest(response))
  126. const _httpRequestFn = (method = 'post') => {
  127. const $HTTP_FNS = {
  128. post: $http.post,
  129. get: $http.get
  130. }
  131. return $HTTP_FNS[method.toLowerCase()]
  132. }
  133. element.on('submit', function(e) {
  134. e.preventDefault()
  135. submit()
  136. })
  137. if (attrs.autoSubmit) {
  138. submit()
  139. }
  140. }
  141. }))
  142. App.directive('formMessages', () => ({
  143. restrict: 'E',
  144. template: `\
  145. <div class="alert" ng-class="{
  146. 'alert-danger': form.response.message.type == 'error',
  147. 'alert-success': form.response.message.type != 'error'
  148. }" ng-show="!!form.response.message" ng-bind-html="form.response.message.text">
  149. </div>
  150. <div ng-transclude></div>\
  151. `,
  152. transclude: true,
  153. scope: {
  154. form: '=for'
  155. }
  156. }))