Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "remotipart",
"version": "1.4.2",
"description": "JS assets for rails jQuery file uploads via standard Rails 'remote: true' forms.",
"main": "vendor/assets/javascripts/jquery.remotipart.module.js",
"files": [
"vendor/assets/javascripts/jquery.iframe-transport.js",
"vendor/assets/javascripts/jquery.remotipart.library.js"
],
"license": "MIT",
"peerDependencies": {
"jquery": ">= 1.12"
}
}
299 changes: 154 additions & 145 deletions vendor/assets/javascripts/jquery.iframe-transport.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,159 +89,168 @@

// ## Annotated Source

(function($, undefined) {
(function() {
"use strict";

// Register a prefilter that checks whether the `iframe` option is set, and
// switches to the "iframe" data type if it is `true`.
$.ajaxPrefilter(function(options, origOptions, jqXHR) {
if (options.iframe) {
options.originalURL = options.url;
return "iframe";
}
});

// Register a transport for the "iframe" data type. It will only activate
// when the "files" option has been set to a non-empty list of enabled file
// inputs.
$.ajaxTransport("iframe", function(options, origOptions, jqXHR) {
var form = null,
iframe = null,
name = "iframe-" + $.now(),
files = $(options.files).filter(":file:enabled"),
markers = null,
accepts = null;

// This function gets called after a successful submission or an abortion
// and should revert all changes made to the page to enable the
// submission via this transport.
function cleanUp() {
files.each(function(i, file) {
var $file = $(file);
$file.data("clone").replaceWith($file);
});
form.remove();
iframe.one("load", function() { iframe.remove(); });
iframe.attr("src", "about:blank");
}

// Remove "iframe" from the data types list so that further processing is
// based on the content type returned by the server, without attempting an
// (unsupported) conversion from "iframe" to the actual type.
options.dataTypes.shift();

// Use the data from the original AJAX options, as it doesn't seem to be
// copied over since jQuery 1.7.
// See https://github.com/cmlenz/jquery-iframe-transport/issues/6
options.data = origOptions.data;

if (files.length) {
form = $("<form enctype='multipart/form-data' method='post'></form>").
hide().attr({action: options.originalURL, target: name});

// If there is any additional data specified via the `data` option,
// we add it as hidden fields to the form. This (currently) requires
// the `processData` option to be set to false so that the data doesn't
// get serialized to a string.
if (typeof(options.data) === "string" && options.data.length > 0) {
$.error("data must not be serialized");
var jqueryIframeTransport = function($, undefined) {

// Register a prefilter that checks whether the `iframe` option is set, and
// switches to the "iframe" data type if it is `true`.
$.ajaxPrefilter(function(options, origOptions, jqXHR) {
if (options.iframe) {
options.originalURL = options.url;
return "iframe";
}
});

// Register a transport for the "iframe" data type. It will only activate
// when the "files" option has been set to a non-empty list of enabled file
// inputs.
$.ajaxTransport("iframe", function(options, origOptions, jqXHR) {
var form = null,
iframe = null,
name = "iframe-" + $.now(),
files = $(options.files).filter(":file:enabled"),
markers = null,
accepts = null;

// This function gets called after a successful submission or an abortion
// and should revert all changes made to the page to enable the
// submission via this transport.
function cleanUp() {
files.each(function(i, file) {
var $file = $(file);
$file.data("clone").replaceWith($file);
});
form.remove();
iframe.one("load", function() { iframe.remove(); });
iframe.attr("src", "about:blank");
}
$.each(options.data || {}, function(name, value) {
if ($.isPlainObject(value)) {
name = value.name;
value = value.value;

// Remove "iframe" from the data types list so that further processing is
// based on the content type returned by the server, without attempting an
// (unsupported) conversion from "iframe" to the actual type.
options.dataTypes.shift();

// Use the data from the original AJAX options, as it doesn't seem to be
// copied over since jQuery 1.7.
// See https://github.com/cmlenz/jquery-iframe-transport/issues/6
options.data = origOptions.data;

if (files.length) {
form = $("<form enctype='multipart/form-data' method='post'></form>").
hide().attr({action: options.originalURL, target: name});

// If there is any additional data specified via the `data` option,
// we add it as hidden fields to the form. This (currently) requires
// the `processData` option to be set to false so that the data doesn't
// get serialized to a string.
if (typeof(options.data) === "string" && options.data.length > 0) {
$.error("data must not be serialized");
}
$("<input type='hidden' />").attr({name: name, value: value}).
$.each(options.data || {}, function(name, value) {
if ($.isPlainObject(value)) {
name = value.name;
value = value.value;
}
$("<input type='hidden' />").attr({name: name, value: value}).
appendTo(form);
});

// Add a hidden `X-Requested-With` field with the value `IFrame` to the
// field, to help server-side code to determine that the upload happened
// through this transport.
$("<input type='hidden' value='IFrame' name='X-Requested-With' />").
appendTo(form);
});

// Add a hidden `X-Requested-With` field with the value `IFrame` to the
// field, to help server-side code to determine that the upload happened
// through this transport.
$("<input type='hidden' value='IFrame' name='X-Requested-With' />").
appendTo(form);

// Borrowed straight from the JQuery source.
// Provides a way of specifying the accepted data type similar to the
// HTTP "Accept" header
if (options.dataTypes[0] && options.accepts[options.dataTypes[0]]) {
accepts = options.accepts[options.dataTypes[0]] +
(options.dataTypes[0] !== "*" ? ", */*; q=0.01" : "");
} else {
accepts = options.accepts["*"];
}
$("<input type='hidden' name='X-HTTP-Accept'>").
attr("value", accepts).appendTo(form);

// Move the file fields into the hidden form, but first remember their
// original locations in the document by replacing them with disabled
// clones. This should also avoid introducing unwanted changes to the
// page layout during submission.
markers = files.after(function(idx) {
var $this = $(this),
$clone = $this.clone().prop("disabled", true);
$this.data("clone", $clone);
return $clone;
}).next();
files.appendTo(form);

return {

// The `send` function is called by jQuery when the request should be
// sent.
send: function(headers, completeCallback) {
iframe = $("<iframe src='about:blank' name='" + name +
"' id='" + name + "' style='display:none'></iframe>");

// The first load event gets fired after the iframe has been injected
// into the DOM, and is used to prepare the actual submission.
iframe.one("load", function() {

// The second load event gets fired when the response to the form
// submission is received. The implementation detects whether the
// actual payload is embedded in a `<textarea>` element, and
// prepares the required conversions to be made in that case.

// Borrowed straight from the JQuery source.
// Provides a way of specifying the accepted data type similar to the
// HTTP "Accept" header
if (options.dataTypes[0] && options.accepts[options.dataTypes[0]]) {
accepts = options.accepts[options.dataTypes[0]] +
(options.dataTypes[0] !== "*" ? ", */*; q=0.01" : "");
} else {
accepts = options.accepts["*"];
}
$("<input type='hidden' name='X-HTTP-Accept'>").
attr("value", accepts).appendTo(form);

// Move the file fields into the hidden form, but first remember their
// original locations in the document by replacing them with disabled
// clones. This should also avoid introducing unwanted changes to the
// page layout during submission.
markers = files.after(function(idx) {
var $this = $(this),
$clone = $this.clone().prop("disabled", true);
$this.data("clone", $clone);
return $clone;
}).next();
files.appendTo(form);

return {

// The `send` function is called by jQuery when the request should be
// sent.
send: function(headers, completeCallback) {
iframe = $("<iframe src='about:blank' name='" + name +
"' id='" + name + "' style='display:none'></iframe>");

// The first load event gets fired after the iframe has been injected
// into the DOM, and is used to prepare the actual submission.
iframe.one("load", function() {
var doc = this.contentWindow ? this.contentWindow.document :
(this.contentDocument ? this.contentDocument : this.document),
root = doc.documentElement ? doc.documentElement : doc.body,
textarea = root.getElementsByTagName("textarea")[0],
type = textarea && textarea.getAttribute("data-type") || null,
status = textarea && textarea.getAttribute("data-status") || 200,
statusText = textarea && textarea.getAttribute("data-statusText") || "OK",
content = {
html: root.innerHTML,
text: type ?
textarea.value :
root ? (root.textContent || root.innerText) : null
};
cleanUp();
completeCallback(status, statusText, content, type ?
("Content-Type: " + type) :
null);

// The second load event gets fired when the response to the form
// submission is received. The implementation detects whether the
// actual payload is embedded in a `<textarea>` element, and
// prepares the required conversions to be made in that case.
iframe.one("load", function() {
var doc = this.contentWindow ? this.contentWindow.document :
(this.contentDocument ? this.contentDocument : this.document),
root = doc.documentElement ? doc.documentElement : doc.body,
textarea = root.getElementsByTagName("textarea")[0],
type = textarea && textarea.getAttribute("data-type") || null,
status = textarea && textarea.getAttribute("data-status") || 200,
statusText = textarea && textarea.getAttribute("data-statusText") || "OK",
content = {
html: root.innerHTML,
text: type ?
textarea.value :
root ? (root.textContent || root.innerText) : null
};
cleanUp();
completeCallback(status, statusText, content, type ?
("Content-Type: " + type) :
null);
});

// Now that the load handler has been set up, submit the form.
form[0].submit();
});

// Now that the load handler has been set up, submit the form.
form[0].submit();
});

// After everything has been set up correctly, the form and iframe
// get injected into the DOM so that the submission can be
// initiated.
$("body").append(form, iframe);
},

// The `abort` function is called by jQuery when the request should be
// aborted.
abort: function() {
if (iframe !== null) {
iframe.unbind("load").attr("src", "about:blank");
cleanUp();
// After everything has been set up correctly, the form and iframe
// get injected into the DOM so that the submission can be
// initiated.
$("body").append(form, iframe);
},

// The `abort` function is called by jQuery when the request should be
// aborted.
abort: function() {
if (iframe !== null) {
iframe.unbind("load").attr("src", "about:blank");
cleanUp();
}
}
}

};
}
});
};
}
});
}

if (window.jQuery) {
jqueryIframeTransport(jQuery);
} else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = jqueryIframeTransport;
}

})(jQuery);
})(this);
Loading