From e49d8947f7ca00254d09920784bcf8a3e4e16f2d Mon Sep 17 00:00:00 2001 From: BehindTheMath Date: Sun, 29 Apr 2018 15:05:22 -0400 Subject: [PATCH] Add the option to use FormData to encode the form elements (#153) * Add the option to use FormData to encode the form elements If the form's enctype attribute is set to "multipart/form-data", use FormData to encode the form's elements. --- index.d.ts | 1 + lib/proto/attach-form.js | 26 +++++++++++++++++++------- lib/send-request.js | 4 ++++ tests/lib/proto/attach-form.js | 30 ++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/index.d.ts b/index.d.ts index 96e5877..1e78099 100644 --- a/index.d.ts +++ b/index.d.ts @@ -177,6 +177,7 @@ declare namespace Pjax { requestUrl?: string; requestMethod?: string; requestParams?: IRequestParams[]; + formData?: FormData; } } diff --git a/lib/proto/attach-form.js b/lib/proto/attach-form.js index 0dbab38..44c4d48 100644 --- a/lib/proto/attach-form.js +++ b/lib/proto/attach-form.js @@ -15,8 +15,7 @@ var formAction = function(el, event) { // Initialize requestOptions options.requestOptions = { requestUrl: el.getAttribute("action") || window.location.href, - requestMethod: el.getAttribute("method") || "GET", - requestParams: [] + requestMethod: el.getAttribute("method") || "GET" } // create a testable virtual link of the form action @@ -31,6 +30,22 @@ var formAction = function(el, event) { event.preventDefault() + if (el.enctype === "multipart/form-data") { + options.requestOptions.formData = new FormData(el) + } + else { + options.requestOptions.requestParams = parseFormElements(el) + } + + el.setAttribute(attrState, "submit") + + options.triggerElement = el + this.loadUrl(virtLinkElement.href, options) +} + +function parseFormElements(el) { + var requestParams = [] + for (var elementKey in el.elements) { if (Number.isNaN(Number(elementKey))) { continue; @@ -62,7 +77,7 @@ var formAction = function(el, event) { } for (var j = 0; j < values.length; j++) { - options.requestOptions.requestParams.push({ + requestParams.push({ name: encodeURIComponent(element.name), value: encodeURIComponent(values[j]) }) @@ -71,10 +86,7 @@ var formAction = function(el, event) { } } - el.setAttribute(attrState, "submit") - - options.triggerElement = el - this.loadUrl(virtLinkElement.href, options) + return requestParams } function checkIfShouldAbort(virtLinkElement, options) { diff --git a/lib/send-request.js b/lib/send-request.js index 5f74d5f..11b88c4 100644 --- a/lib/send-request.js +++ b/lib/send-request.js @@ -6,6 +6,7 @@ module.exports = function(location, options, callback) { var requestOptions = options.requestOptions || {} var requestMethod = (requestOptions.requestMethod || "GET").toUpperCase() var requestParams = requestOptions.requestParams || null + var formData = requestOptions.formData || null; var requestPayload = null var request = new XMLHttpRequest() var timeout = options.timeout || 0 @@ -51,6 +52,9 @@ module.exports = function(location, options, callback) { break } } + else if (formData) { + requestPayload = formData + } // Add a timestamp as part of the query string if cache busting is enabled if (options.cacheBust) { diff --git a/tests/lib/proto/attach-form.js b/tests/lib/proto/attach-form.js index 865e993..9963545 100644 --- a/tests/lib/proto/attach-form.js +++ b/tests/lib/proto/attach-form.js @@ -152,3 +152,33 @@ tape("test form elements parsed correctly", function(t) { t.end() }) + +tape("test form.enctype=\"multipart/form-data\"", function(t) { + t.plan(4) + + var form = document.createElement("form") + form.enctype = "multipart/form-data" + var input = document.createElement("input") + input.name = "input" + input.value = "value" + form.appendChild(input) + + var pjax = { + options: {}, + loadUrl: function(href, options) { + t.equals(options.requestOptions.requestParams, undefined, "form elements not parsed manually") + t.true(options.requestOptions.formData instanceof FormData, "requestOptions.formData is a FormData") + t.equals(Array.from(options.requestOptions.formData.entries()).length, 1, "correct number of FormData elements") + t.equals(options.requestOptions.formData.get("input"), "value", "FormData element value set correctly") + } + } + + attachForm.call(pjax, form) + + form.action = window.location.protocol + "//" + window.location.host + "/internal" + + trigger(form, "submit") + // see loadUrl defined above + + t.end() +})