ajax.js 6.1 KB

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