ajax.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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(function(data) {
  90. if (self._locks[lock].url === url) {
  91. resolve(data);
  92. } else {
  93. self._locks[lock].waiter = true;
  94. wait(self._locks[lock].url);
  95. }
  96. }, function(rejection) {
  97. if (self._locks[lock].url === url) {
  98. reject(rejection);
  99. } else {
  100. self._locks[lock].waiter = true;
  101. wait(self._locks[lock].url);
  102. }
  103. });
  104. }
  105. };
  106. window.setTimeout(function() {
  107. wait(url);
  108. }, 300);
  109. });
  110. // setup new lock without waiter
  111. } else {
  112. this._locks[lock] = {
  113. url,
  114. wait: true,
  115. waiter: false
  116. };
  117. return new Promise(function(resolve, reject) {
  118. self.request('GET', url).then(function(data) {
  119. self._locks[lock].wait = false;
  120. if (self._locks[lock].url === url) {
  121. resolve(data);
  122. }
  123. }, function(rejection) {
  124. self._locks[lock].wait = false;
  125. if (self._locks[lock].url === url) {
  126. reject(rejection);
  127. }
  128. });
  129. });
  130. }
  131. } else {
  132. return this.request('GET', url);
  133. }
  134. }
  135. post(url, data) {
  136. return this.request('POST', url, data);
  137. }
  138. patch(url, data) {
  139. return this.request('PATCH', url, data);
  140. }
  141. put(url, data) {
  142. return this.request('PUT', url, data);
  143. }
  144. delete(url, data) {
  145. return this.request('DELETE', url, data);
  146. }
  147. upload(url, data, progress) {
  148. let self = this;
  149. return new Promise(function(resolve, reject) {
  150. let xhr = {
  151. url: url,
  152. method: 'POST',
  153. headers: {
  154. 'X-CSRFToken': self.getCsrfToken()
  155. },
  156. data: data,
  157. contentType: false,
  158. processData: false,
  159. xhr: function() {
  160. let xhr = new window.XMLHttpRequest();
  161. xhr.upload.addEventListener("progress", function(evt) {
  162. if (evt.lengthComputable) {
  163. progress(Math.round(evt.loaded / evt.total * 100));
  164. }
  165. }, false);
  166. return xhr;
  167. },
  168. success: function(response) {
  169. resolve(response);
  170. },
  171. error: function(jqXHR) {
  172. let rejection = jqXHR.responseJSON || {};
  173. rejection.status = jqXHR.status;
  174. if (rejection.status === 0) {
  175. rejection.detail = gettext("Lost connection with application.");
  176. }
  177. if (rejection.status === 413 && !rejection.detail) {
  178. rejection.detail = gettext("Upload was rejected by server as too large.");
  179. }
  180. if (rejection.status === 404) {
  181. if (!rejection.detail || rejection.detail === 'NOT FOUND') {
  182. rejection.detail = gettext("Action link is invalid.");
  183. }
  184. }
  185. if (rejection.status === 500 && !rejection.detail) {
  186. rejection.detail = gettext("Unknown error has occured.");
  187. }
  188. rejection.statusText = jqXHR.statusText;
  189. reject(rejection);
  190. }
  191. };
  192. $.ajax(xhr);
  193. });
  194. }
  195. }
  196. export default new Ajax();