diff --git a/django_jinja_knockout/static/djk/js/ajaxform.js b/django_jinja_knockout/static/djk/js/ajaxform.js index eb632f1..75f0ca3 100644 --- a/django_jinja_knockout/static/djk/js/ajaxform.js +++ b/django_jinja_knockout/static/djk/js/ajaxform.js @@ -1,3 +1,4 @@ +import { default as axios } from './lib/axios.js'; import { create as laddaCreate } from './lib/ladda.js'; import { showAjaxError } from './errors.js'; @@ -71,14 +72,6 @@ function AjaxForms($selector) { AjaxForms.submitSelector = 'button[type="submit"], input[type="submit"], input[type="image"]'; AjaxForms.formSubmitSelector = AjaxForms.formSelector + ', ' + AjaxForms.submitSelector; - AjaxForms.has = function() { - var result = (typeof $.fn.ajaxForm !== 'undefined'); - if (!result) { - console.log('@note: jQuery AJAX form plugin is disabled.'); - } - return result; - }; - AjaxForms.create = function($selector) { this.$forms = $selector.findSelf(this.formSelector); this.$cancelButtons = this.$forms.find('.btn-cancel-compose'); @@ -110,10 +103,6 @@ function AjaxForms($selector) { }; AjaxForms.init = function() { - if (!this.has()) { - return; - } - this.$forms.ajaxForm(); this.$cancelButtons.on('click', AjaxForms.onCancelButtonClick); // Do not use ajaxForm plugin submit event, otherwise form will be double-POSTed. this.$submitButtons.on('click', AjaxForms.onSubmitButtonClick); @@ -121,12 +110,8 @@ function AjaxForms($selector) { }; AjaxForms.destroy = function() { - if (!this.has()) { - return; - } this.$submitButtons.off('click', AjaxForms.onSubmitButtonClick); this.$cancelButtons.off('click', AjaxForms.onCancelButtonClick); - this.$forms.ajaxFormUnbind(); }; }(AjaxForms.prototype); @@ -184,11 +169,14 @@ function AjaxForm($form) { }; AjaxForm.always = function() { + this.hasAlways = true; enableInputs(this.$form); if (this.$form.has(this.$btn).length === 0) { enableInput(this.$btn); } - if (typeof this.options['uploadProgress'] !== 'undefined') { + // the order of calling is important - Ladda should be removed only after the inputs are enabled. + this.ladder.remove(); + if (this.$progressBar !== null) { this.$progressBar.remove(); } this._callbacks.always(); @@ -207,36 +195,26 @@ function AjaxForm($form) { AjaxForm.getOptions = function() { var self = this; - return { - 'url': this.getUrl(), - type: 'post', - dataType: 'json', - beforeSubmit: function() { - self.beforeSubmit(); - }, - error: function(jqXHR, exception) { - self.always(); - showAjaxError(jqXHR, exception); - self._callbacks.error(jqXHR, exception); - }, - success: function(response) { - self.always(); - if (self._callbacks.success(response)) { - /** - * Set current AjaxForm bindContext for response viewmodel handler, - * to read this.$form in the handler body. - */ - vmRouter.respond(response, {context: self}); - } + var options = { + headers: { + // https://github.com/axios/axios/issues/1322#issuecomment-526580627 + // 'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest', + 'Content-Type': 'multipart/form-data', + 'Accept': 'application/json, text/javascript', }, - complete: function() { - self.ladder.remove(); - } }; + if (this.$progressBar !== null) { + options.onUploadProgress = function (progressEvent) { + var percentComplete = (progressEvent.loaded / progressEvent.total) * 100; + self.$progressBar.find('.progress-bar').css('width', percentComplete + '%'); + } + } + return options; }; AjaxForm.setupProgressBar = function() { var self = this; + this.$progressBar = null; if (this.$form.find('input[type="file"]').length > 0) { this.$progressBar = $.contents( '
' + @@ -246,13 +224,11 @@ function AjaxForm($form) { '
' ); this.$progressBar.insertAfter(this.$btn); - this.options['uploadProgress'] = function(event, position, total, percentComplete) { - self.$progressBar.find('.progress-bar').css('width', percentComplete + '%'); - }; } }; AjaxForm.submit = function($btn, callbacks) { + var self = this; this.$btn = $btn; if (typeof AppConf('fileMaxSize') !== 'undefined' && !this.checkFiles(AppConf('fileMaxSize'))) { return; @@ -262,17 +238,42 @@ function AjaxForm($form) { } this._callbacks = $.extend({ always: function () {}, - error: function (jqXHR, exception) {}, + error: function (request, exception) {}, success: function (response) { return true; }, }, callbacks ); - this.options = this.getOptions(); this.setupProgressBar(); this.ladder = new Ladder(this.$btn); - this.$form.ajaxSubmit(this.options); - var jqXHR = this.$form.data('jqxhr'); - jqXHR.setRequestHeader('X_REQUESTED_WITH', 'XMLHttpRequest'); + this.hasAlways = false; + var formData = new FormData(this.$form.get(0)); + this.beforeSubmit(); + axios.post( + this.getUrl(), + formData, + this.getOptions() + ).then(function (axiosResponse) { + self.always(); + self.hasAlways = true; + if (self._callbacks.success(axiosResponse.data)) { + /** + * Set current AjaxForm bindContext for response viewmodel handler, + * to read this.$form in the handler body. + */ + vmRouter.respond(axiosResponse.data, {context: self}); + } + }).catch(function (axiosError) { + if (!self.hasAlways) { + self.always(); + }; + if (typeof axiosError.request !== 'undefined') { + showAjaxError(axiosError.request, axiosError.message); + self._callbacks.error(axiosError.request, axiosError.message); + } else { + // Most probably an vmRouter error: + console.log(axiosError); + } + }); return false; }; diff --git a/django_jinja_knockout/static/djk/js/document.js b/django_jinja_knockout/static/djk/js/document.js index 093704f..eca24a0 100644 --- a/django_jinja_knockout/static/djk/js/document.js +++ b/django_jinja_knockout/static/djk/js/document.js @@ -1,7 +1,6 @@ import moment from './lib/moment.js'; import { sprintf } from './lib/sprintf-esm.js'; import Cookies from './lib/js.cookie.js'; -import './lib/jquery.form.min.js' /** * Note: datetime.js is not the part of django-jinja-knockout. diff --git a/django_jinja_knockout/static/djk/js/lib/jquery.form.min.js b/django_jinja_knockout/static/djk/js/lib/jquery.form.min.js deleted file mode 100644 index 31ce43b..0000000 --- a/django_jinja_knockout/static/djk/js/lib/jquery.form.min.js +++ /dev/null @@ -1,23 +0,0 @@ -/*! - * jQuery Form Plugin - * version: 4.3.0 - * Requires jQuery v1.7.2 or later - * Project repository: https://github.com/jquery-form/form - - * Copyright 2017 Kevin Morris - * Copyright 2006 M. Alsup - - * Dual licensed under the LGPL-2.1+ or MIT licenses - * https://github.com/jquery-form/form#license - - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - */ -!function(r){"function"==typeof define&&define.amd?define(["jquery"],r):"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),r(t),t}:r(jQuery)}(function(q){"use strict";var m=/\r?\n/g,S={};S.fileapi=void 0!==q('').get(0).files,S.formdata=void 0!==window.FormData;var _=!!q.fn.prop;function o(e){var t=e.data;e.isDefaultPrevented()||(e.preventDefault(),q(e.target).closest("form").ajaxSubmit(t))}function i(e){var t=e.target,r=q(t);if(!r.is("[type=submit],[type=image]")){var a=r.closest("[type=submit]");if(0===a.length)return;t=a[0]}var n,o=t.form;"image"===(o.clk=t).type&&(void 0!==e.offsetX?(o.clk_x=e.offsetX,o.clk_y=e.offsetY):"function"==typeof q.fn.offset?(n=r.offset(),o.clk_x=e.pageX-n.left,o.clk_y=e.pageY-n.top):(o.clk_x=e.pageX-t.offsetLeft,o.clk_y=e.pageY-t.offsetTop)),setTimeout(function(){o.clk=o.clk_x=o.clk_y=null},100)}function N(){var e;q.fn.ajaxSubmit.debug&&(e="[jquery.form] "+Array.prototype.join.call(arguments,""),window.console&&window.console.log?window.console.log(e):window.opera&&window.opera.postError&&window.opera.postError(e))}q.fn.attr2=function(){if(!_)return this.attr.apply(this,arguments);var e=this.prop.apply(this,arguments);return e&&e.jquery||"string"==typeof e?e:this.attr.apply(this,arguments)},q.fn.ajaxSubmit=function(M,e,t,r){if(!this.length)return N("ajaxSubmit: skipping submit process - no element selected"),this;var O,a,n,o,X=this;"function"==typeof M?M={success:M}:"string"==typeof M||!1===M&&0',s)).css({position:"absolute",top:"-1000px",left:"-1000px"}),m=d[0],p={aborted:0,responseText:null,responseXML:null,status:0,statusText:"n/a",getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(e){var t="timeout"===e?"timeout":"aborted";N("aborting upload... "+t),this.aborted=1;try{m.contentWindow.document.execCommand&&m.contentWindow.document.execCommand("Stop")}catch(e){}d.attr("src",l.iframeSrc),p.error=t,l.error&&l.error.call(l.context,p,t,e),f&&q.event.trigger("ajaxError",[p,l,t]),l.complete&&l.complete.call(l.context,p,t)}},(f=l.global)&&0==q.active++&&q.event.trigger("ajaxStart"),f&&q.event.trigger("ajaxSend",[p,l]),l.beforeSend&&!1===l.beforeSend.call(l.context,p,l))return l.global&&q.active--,g.reject(),g;if(p.aborted)return g.reject(),g;(a=i.clk)&&(n=a.name)&&!a.disabled&&(l.extraData=l.extraData||{},l.extraData[n]=a.value,"image"===a.type&&(l.extraData[n+".x"]=i.clk_x,l.extraData[n+".y"]=i.clk_y));var x=1,y=2;function b(t){var r=null;try{t.contentWindow&&(r=t.contentWindow.document)}catch(e){N("cannot get iframe.contentWindow document: "+e)}if(r)return r;try{r=t.contentDocument?t.contentDocument:t.document}catch(e){N("cannot get iframe.contentDocument: "+e),r=t.document}return r}var c=q("meta[name=csrf-token]").attr("content"),T=q("meta[name=csrf-param]").attr("content");function j(){var e=X.attr2("target"),t=X.attr2("action"),r=X.attr("enctype")||X.attr("encoding")||"multipart/form-data";i.setAttribute("target",o),O&&!/post/i.test(O)||i.setAttribute("method","POST"),t!==l.url&&i.setAttribute("action",l.url),l.skipEncodingOverride||O&&!/post/i.test(O)||X.attr({encoding:"multipart/form-data",enctype:"multipart/form-data"}),l.timeout&&(v=setTimeout(function(){h=!0,A(x)},l.timeout));var a=[];try{if(l.extraData)for(var n in l.extraData)l.extraData.hasOwnProperty(n)&&(q.isPlainObject(l.extraData[n])&&l.extraData[n].hasOwnProperty("name")&&l.extraData[n].hasOwnProperty("value")?a.push(q('',s).val(l.extraData[n].value).appendTo(i)[0]):a.push(q('',s).val(l.extraData[n]).appendTo(i)[0]));l.iframeTarget||d.appendTo(u),m.attachEvent?m.attachEvent("onload",A):m.addEventListener("load",A,!1),setTimeout(function e(){try{var t=b(m).readyState;N("state = "+t),t&&"uninitialized"===t.toLowerCase()&&setTimeout(e,50)}catch(e){N("Server abort: ",e," (",e.name,")"),A(y),v&&clearTimeout(v),v=void 0}},15);try{i.submit()}catch(e){document.createElement("form").submit.apply(i)}}finally{i.setAttribute("action",t),i.setAttribute("enctype",r),e?i.setAttribute("target",e):X.removeAttr("target"),q(a).remove()}}T&&c&&(l.extraData=l.extraData||{},l.extraData[T]=c),l.forceSync?j():setTimeout(j,10);var w,S,k,D=50;function A(e){if(!p.aborted&&!k){if((S=b(m))||(N("cannot access response document"),e=y),e===x&&p)return p.abort("timeout"),void g.reject(p,"timeout");if(e===y&&p)return p.abort("server abort"),void g.reject(p,"error","server abort");if(S&&S.location.href!==l.iframeSrc||h){m.detachEvent?m.detachEvent("onload",A):m.removeEventListener("load",A,!1);var t,r="success";try{if(h)throw"timeout";var a="xml"===l.dataType||S.XMLDocument||q.isXMLDoc(S);if(N("isXml="+a),!a&&window.opera&&(null===S.body||!S.body.innerHTML)&&--D)return N("requeing onLoad callback, DOM not available"),void setTimeout(A,250);var n=S.body?S.body:S.documentElement;p.responseText=n?n.innerHTML:null,p.responseXML=S.XMLDocument?S.XMLDocument:S,a&&(l.dataType="xml"),p.getResponseHeader=function(e){return{"content-type":l.dataType}[e.toLowerCase()]},n&&(p.status=Number(n.getAttribute("status"))||p.status,p.statusText=n.getAttribute("statusText")||p.statusText);var o,i,s,u=(l.dataType||"").toLowerCase(),c=/(json|script|text)/.test(u);c||l.textarea?(o=S.getElementsByTagName("textarea")[0])?(p.responseText=o.value,p.status=Number(o.getAttribute("status"))||p.status,p.statusText=o.getAttribute("statusText")||p.statusText):c&&(i=S.getElementsByTagName("pre")[0],s=S.getElementsByTagName("body")[0],i?p.responseText=i.textContent?i.textContent:i.innerText:s&&(p.responseText=s.textContent?s.textContent:s.innerText)):"xml"===u&&!p.responseXML&&p.responseText&&(p.responseXML=F(p.responseText));try{w=E(p,u,l)}catch(e){r="parsererror",p.error=t=e||r}}catch(e){N("error caught: ",e),r="error",p.error=t=e||r}p.aborted&&(N("upload aborted"),r=null),p.status&&(r=200<=p.status&&p.status<300||304===p.status?"success":"error"),"success"===r?(l.success&&l.success.call(l.context,w,"success",p),g.resolve(p.responseText,"success",p),f&&q.event.trigger("ajaxSuccess",[p,l])):r&&(void 0===t&&(t=p.statusText),l.error&&l.error.call(l.context,p,r,t),g.reject(p,"error",t),f&&q.event.trigger("ajaxError",[p,l,t])),f&&q.event.trigger("ajaxComplete",[p,l]),f&&!--q.active&&q.event.trigger("ajaxStop"),l.complete&&l.complete.call(l.context,p,r),k=!0,l.timeout&&clearTimeout(v),setTimeout(function(){l.iframeTarget?d.attr("src",l.iframeSrc):d.remove(),p.responseXML=null},100)}}}var F=q.parseXML||function(e,t){return window.ActiveXObject?((t=new ActiveXObject("Microsoft.XMLDOM")).async="false",t.loadXML(e)):t=(new DOMParser).parseFromString(e,"text/xml"),t&&t.documentElement&&"parsererror"!==t.documentElement.nodeName?t:null},L=q.parseJSON||function(e){return window.eval("("+e+")")},E=function(e,t,r){var a=e.getResponseHeader("content-type")||"",n=("xml"===t||!t)&&0<=a.indexOf("xml"),o=n?e.responseXML:e.responseText;return n&&"parsererror"===o.documentElement.nodeName&&q.error&&q.error("parsererror"),r&&r.dataFilter&&(o=r.dataFilter(o,t)),"string"==typeof o&&(("json"===t||!t)&&0<=a.indexOf("json")?o=L(o):("script"===t||!t)&&0<=a.indexOf("javascript")&&q.globalEval(o)),o};return g}},q.fn.ajaxForm=function(e,t,r,a){if(("string"==typeof e||!1===e&&0