ajax.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. export class Ajax {
  2. constructor() {
  3. this._cookieName = null
  4. this._csrfToken = null
  5. this._locks = {}
  6. }
  7. init(cookieName) {
  8. this._cookieName = cookieName
  9. }
  10. getCsrfToken() {
  11. if (document.cookie.indexOf(this._cookieName) !== -1) {
  12. let cookieRegex = new RegExp(this._cookieName + "=([^;]*)")
  13. let cookie = document.cookie.match(cookieRegex)[0]
  14. return cookie ? cookie.split("=")[1] : null
  15. } else {
  16. return null
  17. }
  18. }
  19. request(method, url, data) {
  20. let self = this
  21. return new Promise(function(resolve, reject) {
  22. let xhr = {
  23. url: url,
  24. method: method,
  25. headers: {
  26. "X-CSRFToken": self.getCsrfToken()
  27. },
  28. data: data ? JSON.stringify(data) : null,
  29. contentType: "application/json; charset=utf-8",
  30. dataType: "json",
  31. success: function(data) {
  32. resolve(data)
  33. },
  34. error: function(jqXHR) {
  35. let rejection = jqXHR.responseJSON || {}
  36. rejection.status = jqXHR.status
  37. if (rejection.status === 0) {
  38. rejection.detail = gettext("Lost connection with application.")
  39. }
  40. if (rejection.status === 404) {
  41. if (!rejection.detail || rejection.detail === "NOT FOUND") {
  42. rejection.detail = gettext("Action link is invalid.")
  43. }
  44. }
  45. if (rejection.status === 500 && !rejection.detail) {
  46. rejection.detail = gettext("Unknown error has occured.")
  47. }
  48. rejection.statusText = jqXHR.statusText
  49. reject(rejection)
  50. }
  51. }
  52. $.ajax(xhr)
  53. })
  54. }
  55. get(url, params, lock) {
  56. if (params) {
  57. url += "?" + $.param(params)
  58. }
  59. if (lock) {
  60. let self = this
  61. // update url in existing lock?
  62. if (this._locks[lock]) {
  63. this._locks[lock].url = url
  64. }
  65. // immediately dereference promise handlers without doing anything
  66. // we are already waiting for existing response to resolve
  67. if (this._locks[lock] && this._locks[lock].waiter) {
  68. return {
  69. then: function() {
  70. return
  71. }
  72. }
  73. // return promise that will begin when original one resolves
  74. } else if (this._locks[lock] && this._locks[lock].wait) {
  75. this._locks[lock].waiter = true
  76. return new Promise(function(resolve, reject) {
  77. let wait = function(url) {
  78. // keep waiting on promise
  79. if (self._locks[lock].wait) {
  80. window.setTimeout(function() {
  81. wait(url)
  82. }, 300)
  83. // poll for new url
  84. } else if (self._locks[lock].url !== url) {
  85. wait(self._locks[lock].url)
  86. // ajax backend for response
  87. } else {
  88. self._locks[lock].waiter = false
  89. self.request("GET", self._locks[lock].url).then(
  90. function(data) {
  91. if (self._locks[lock].url === url) {
  92. resolve(data)
  93. } else {
  94. self._locks[lock].waiter = true
  95. wait(self._locks[lock].url)
  96. }
  97. },
  98. function(rejection) {
  99. if (self._locks[lock].url === url) {
  100. reject(rejection)
  101. } else {
  102. self._locks[lock].waiter = true
  103. wait(self._locks[lock].url)
  104. }
  105. }
  106. )
  107. }
  108. }
  109. window.setTimeout(function() {
  110. wait(url)
  111. }, 300)
  112. })
  113. // setup new lock without waiter
  114. } else {
  115. this._locks[lock] = {
  116. url,
  117. wait: true,
  118. waiter: false
  119. }
  120. return new Promise(function(resolve, reject) {
  121. self.request("GET", url).then(
  122. function(data) {
  123. self._locks[lock].wait = false
  124. if (self._locks[lock].url === url) {
  125. resolve(data)
  126. }
  127. },
  128. function(rejection) {
  129. self._locks[lock].wait = false
  130. if (self._locks[lock].url === url) {
  131. reject(rejection)
  132. }
  133. }
  134. )
  135. })
  136. }
  137. } else {
  138. return this.request("GET", url)
  139. }
  140. }
  141. post(url, data) {
  142. return this.request("POST", url, data)
  143. }
  144. patch(url, data) {
  145. return this.request("PATCH", url, data)
  146. }
  147. put(url, data) {
  148. return this.request("PUT", url, data)
  149. }
  150. delete(url, data) {
  151. return this.request("DELETE", url, data)
  152. }
  153. upload(url, data, progress) {
  154. let self = this
  155. return new Promise(function(resolve, reject) {
  156. let xhr = {
  157. url: url,
  158. method: "POST",
  159. headers: {
  160. "X-CSRFToken": self.getCsrfToken()
  161. },
  162. data: data,
  163. contentType: false,
  164. processData: false,
  165. xhr: function() {
  166. let xhr = new window.XMLHttpRequest()
  167. xhr.upload.addEventListener(
  168. "progress",
  169. function(evt) {
  170. if (evt.lengthComputable) {
  171. progress(Math.round((evt.loaded / evt.total) * 100))
  172. }
  173. },
  174. false
  175. )
  176. return xhr
  177. },
  178. success: function(response) {
  179. resolve(response)
  180. },
  181. error: function(jqXHR) {
  182. let rejection = jqXHR.responseJSON || {}
  183. rejection.status = jqXHR.status
  184. if (rejection.status === 0) {
  185. rejection.detail = gettext("Lost connection with application.")
  186. }
  187. if (rejection.status === 413 && !rejection.detail) {
  188. rejection.detail = gettext(
  189. "Upload was rejected by server as too large."
  190. )
  191. }
  192. if (rejection.status === 404) {
  193. if (!rejection.detail || rejection.detail === "NOT FOUND") {
  194. rejection.detail = gettext("Action link is invalid.")
  195. }
  196. }
  197. if (rejection.status === 500 && !rejection.detail) {
  198. rejection.detail = gettext("Unknown error has occured.")
  199. }
  200. rejection.statusText = jqXHR.statusText
  201. reject(rejection)
  202. }
  203. }
  204. $.ajax(xhr)
  205. })
  206. }
  207. }
  208. export default new Ajax()