API Removed duplicated thirdparty deps

These were originally copied from node_modules via an "npm run thirdparty" task,
in order to have them loadable with oldschool <script> tags.
Since webpack supports CommonJS-style loading, that's no longer required,
we can simply inline those scripts into the bundle.

We need to use imports-loader though, in order to ensure
that "define" is not available in some module scopes,
which triggers AMD behavior that's not compatible with Webpack's loaders.
See http://webpack.github.io/docs/shimming-modules.html

I've had to pin to the exact versions used in the 3.x CMS,
since jquery-upload has introduced an AMD wrapper sometime
between 6.0 and 6.9 (the latest version NPM automatically pulls in).
This AMD wrapper confuses Webpack, since it's trying to resolve the
dependencies contained in it. We could create shims for those instead,
but the easiest way was to simply revert to the versions already used
before the Webpack migration (since the newer versions in node_modules
were never actually copied into thirdparty, they weren't used before).
This commit is contained in:
Ingo Schommer 2016-09-07 22:21:43 +12:00
parent 0a380a94cd
commit 9cb9a05ec0
15 changed files with 14 additions and 2026 deletions

View File

@ -39,7 +39,7 @@ require('../../../../thirdparty/jquery-form/jquery.form.js');
require('../../../thirdparty/jquery-notice/jquery.notice.js');
require('../../../thirdparty/jquery-notice/jquery.notice.css');
require('../../../thirdparty/jsizes/lib/jquery.sizes.js');
require('jquery-sizes/lib/jquery.sizes.js');
require('../../../thirdparty/jlayout/lib/jlayout.border.js');
require('../../../thirdparty/jlayout/lib/jquery.jlayout.js');
@ -51,6 +51,7 @@ require('../../../../thirdparty/jquery-changetracker/lib/jquery.changetracker.js
require('../../../../client/src/legacy/TreeDropdownField.js');
require('../../../../client/src/legacy/DateField.js');
require('../../../../client/src/legacy/UploadField.js');
require('../../../../client/src/legacy/HtmlEditorField.js');
require('../../../../client/src/legacy/TabSet.js');
require('../legacy/ssui.core.js');

View File

@ -1,8 +0,0 @@
---
format: 1
handler:
commit: 15dc4845734b83b31fb820131c675a5f0c10db95
branch: master
lock: false
repository_class: Piston::Git::Repository
repository_url: git://github.com/bramstein/jsizes.git

View File

@ -1,76 +0,0 @@
/**
* @preserve JSizes - JQuery plugin v0.33
*
* Licensed under the revised BSD License.
* Copyright 2008-2010 Bram Stein
* All rights reserved.
*/
/*global jQuery*/
(function ($) {
'use strict';
var num = function (value) {
return parseInt(value, 10) || 0;
};
/**
* Sets or gets the values for min-width, min-height, max-width
* and max-height.
*/
$.each(['min', 'max'], function (i, name) {
$.fn[name + 'Size'] = function (value) {
var width, height;
if (value) {
if (value.width !== undefined) {
this.css(name + '-width', value.width);
}
if (value.height !== undefined) {
this.css(name + '-height', value.height);
}
} else {
width = this.css(name + '-width');
height = this.css(name + '-height');
// Apparently:
// * Opera returns -1px instead of none
// * IE6 returns undefined instead of none
return {'width': (name === 'max' && (width === undefined || width === 'none' || num(width) === -1) && Number.MAX_VALUE) || num(width),
'height': (name === 'max' && (height === undefined || height === 'none' || num(height) === -1) && Number.MAX_VALUE) || num(height)};
}
return this;
};
});
/**
* Returns whether or not an element is visible.
*/
$.fn.isVisible = function () {
return this.is(':visible');
};
/**
* Sets or gets the values for border, margin and padding.
*/
$.each(['border', 'margin', 'padding'], function (i, name) {
$.fn[name] = function (value) {
if (value) {
if (value.top !== undefined) {
this.css(name + '-top' + (name === 'border' ? '-width' : ''), value.top);
}
if (value.bottom !== undefined) {
this.css(name + '-bottom' + (name === 'border' ? '-width' : ''), value.bottom);
}
if (value.left !== undefined) {
this.css(name + '-left' + (name === 'border' ? '-width' : ''), value.left);
}
if (value.right !== undefined) {
this.css(name + '-right' + (name === 'border' ? '-width' : ''), value.right);
}
} else {
return {top: num(this.css(name + '-top' + (name === 'border' ? '-width' : ''))),
bottom: num(this.css(name + '-bottom' + (name === 'border' ? '-width' : ''))),
left: num(this.css(name + '-left' + (name === 'border' ? '-width' : ''))),
right: num(this.css(name + '-right' + (name === 'border' ? '-width' : '')))};
}
return this;
};
});
}(jQuery));

View File

@ -5,12 +5,13 @@ import i18n from 'i18n';
require('../../../thirdparty/jquery-ui/jquery-ui.js');
require('../../../admin/client/src/legacy/ssui.core.js');
window.tmpl = require('../../../thirdparty/javascript-templates/tmpl.js');
require('../../../thirdparty/javascript-loadimage/load-image.js');
require('../../../thirdparty/jquery-fileupload/jquery.iframe-transport.js');
require('../../../thirdparty/jquery-fileupload/cors/jquery.xdr-transport.js');
require('../../../thirdparty/jquery-fileupload/jquery.fileupload.js');
require('../../../thirdparty/jquery-fileupload/jquery.fileupload-ui.js');
window.tmpl = require('blueimp-tmpl/tmpl.js');
require('imports?define=>false&this=>window!blueimp-load-image/load-image.js');
require('blueimp-file-upload/jquery.iframe-transport.js');
require('blueimp-file-upload/cors/jquery.xdr-transport.js');
require('blueimp-file-upload/jquery.fileupload.js');
require('blueimp-file-upload/jquery.fileupload-ui.js');
require('./UploadField_uploadtemplate.js');
require('./UploadField_downloadtemplate.js');

View File

@ -33,10 +33,10 @@
"homepage": "https://github.com/silverstripe/silverstripe-framework#readme",
"dependencies": {
"babel-polyfill": "^6.7.4",
"blueimp-file-upload": "^6.0.3",
"blueimp-load-image": "^1.1.3",
"blueimp-tmpl": "^1.0.2",
"bootstrap": "^4.0.0-alpha.2",
"blueimp-file-upload": "6.0.3",
"blueimp-load-image": "1.1.3",
"blueimp-tmpl": "1.0.2",
"bootstrap": "4.0.0-alpha.2",
"chosen-js": "^1.5.1",
"deep-equal": "^1.0.1",
"deep-freeze-strict": "^1.1.1",
@ -79,6 +79,7 @@
"expose-loader": "^0.7.1",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.9.0",
"imports-loader": "^0.6.5",
"jest-cli": "^0.9.2",
"node-sass": "^3.8.0",
"npm-shrinkwrap": "^6.0.1",

View File

@ -1,8 +0,0 @@
---
repository_url: git://github.com/blueimp/JavaScript-Load-Image.git
lock: false
repository_class: Piston::Git::Repository
format: 1
handler:
commit: 19c8e8cf0d4e854238c78174e593b607f04a1521
branch: master

View File

@ -1,114 +0,0 @@
/*
* JavaScript Load Image 1.1.3
* https://github.com/blueimp/JavaScript-Load-Image
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*/
/*jslint nomen: true */
/*global window, document, URL, webkitURL, Blob, FileReader, define */
(function ($) {
'use strict';
// Loads an image for a given File object.
// Invokes the callback with an img or optional canvas
// element (if supported by the browser) as parameter:
var loadImage = function (file, callback, options) {
var img = document.createElement('img'),
url,
isFile;
if (window.Blob && file instanceof Blob) {
url = loadImage.createObjectURL(file);
isFile = true;
} else {
url = file;
}
img.onerror = callback;
img.onload = function () {
if (isFile) {
loadImage.revokeObjectURL(url);
}
callback(loadImage.scale(img, options));
};
if (url) {
img.src = url;
return img;
} else {
return loadImage.readFile(file, function (url) {
img.src = url;
});
}
},
urlAPI = (window.createObjectURL && window) ||
(window.URL && URL) || (window.webkitURL && webkitURL);
// Scales the given image (img HTML element)
// using the given options.
// Returns a canvas object if the canvas option is true
// and the browser supports canvas, else the scaled image:
loadImage.scale = function (img, options) {
options = options || {};
var canvas = document.createElement('canvas'),
scale = Math.max(
(options.minWidth || img.width) / img.width,
(options.minHeight || img.height) / img.height
);
if (scale > 1) {
img.width = parseInt(img.width * scale, 10);
img.height = parseInt(img.height * scale, 10);
}
scale = Math.min(
(options.maxWidth || img.width) / img.width,
(options.maxHeight || img.height) / img.height
);
if (scale < 1) {
img.width = parseInt(img.width * scale, 10);
img.height = parseInt(img.height * scale, 10);
}
if (!options.canvas || !canvas.getContext) {
return img;
}
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d')
.drawImage(img, 0, 0, img.width, img.height);
return canvas;
};
loadImage.createObjectURL = function (file) {
return urlAPI ? urlAPI.createObjectURL(file) : false;
};
loadImage.revokeObjectURL = function (url) {
return urlAPI ? urlAPI.revokeObjectURL(url) : false;
};
// Loads a given File object via FileReader interface,
// invokes the callback with a data url:
loadImage.readFile = function (file, callback) {
if (window.FileReader && FileReader.prototype.readAsDataURL) {
var fileReader = new FileReader();
fileReader.onload = function (e) {
callback(e.target.result);
};
fileReader.readAsDataURL(file);
return fileReader;
}
return false;
};
if (typeof define !== 'undefined' && define.amd) {
// Register as an AMD module:
define('loadImage', function () {
return loadImage;
});
} else {
// Bind to the global (window) object:
$.loadImage = loadImage;
}
}(this));

View File

@ -1,8 +0,0 @@
---
repository_url: git://github.com/blueimp/JavaScript-Templates.git
lock: false
repository_class: Piston::Git::Repository
format: 1
handler:
commit: ddb6a9c25c3a1089c22af6e8a431cefced39e31c
branch: master

View File

@ -1,84 +0,0 @@
/*
* JavaScript Templates 1.0.2
* https://github.com/blueimp/JavaScript-Templates
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*
* Inspired by John Resig's JavaScript Micro-Templating:
* http://ejohn.org/blog/javascript-micro-templating/
*/
/*jslint evil: true, regexp: true */
/*global document, define */
(function ($) {
"use strict";
var tmpl = function (str, data) {
var f = !/[^\-\w]/.test(str) ? tmpl.cache[str] = tmpl.cache[str] ||
tmpl(tmpl.load(str)) :
new Function(
tmpl.arg,
("var _s=''" + tmpl.helper + ";_s+='" +
str.replace(tmpl.regexp, tmpl.func) +
"';return _s;").split("_s+='';").join("")
);
f.tmpl = f.tmpl || tmpl;
return data ? f(data) : f;
};
tmpl.cache = {};
tmpl.load = function (id) {
return document.getElementById(id).innerHTML;
};
tmpl.regexp = /(\s+)|('|\\)(?![^%]*%\})|(?:\{%(=|#)(.+?)%\})|(\{%)|(%\})/g;
tmpl.func = function (s, p1, p2, p3, p4, p5, p6, o, str) {
if (p1) { // whitespace
return o && o + s.length !== str.length ? " " : "";
}
if (p2) { // single quote or backslash
return "\\" + s;
}
if (p3) { // interpolation: {%=prop%}, or unescaped: {%#prop%}
if (p3 === "=") {
return "'+_e(" + p4 + ")+'";
}
return "'+(" + p4 + "||'')+'";
}
if (p5) { // evaluation start tag: {%
return "';";
}
if (p6) { // evaluation end tag: %}
return "_s+='";
}
};
tmpl.encReg = /[<>&"\x00]/g;
tmpl.encMap = {
"<": "&lt;",
">": "&gt;",
"&": "&amp;",
"\"": "&quot;",
"\x00": ""
};
tmpl.encode = function (s) {
return String(s || "").replace(
tmpl.encReg,
function (c) {
return tmpl.encMap[c];
}
);
};
tmpl.arg = "o";
tmpl.helper = ",_t=arguments.callee.tmpl,_e=_t.encode" +
",print=function(s,e){_s+=e&&(s||'')||_e(s);}" +
",include=function(s,d){_s+=_t(s,d);}";
if (typeof define === "function" && define.amd) {
define(function () {
return tmpl;
});
} else {
$.tmpl = tmpl;
}
}(this));

View File

@ -1,8 +0,0 @@
---
repository_url: git://github.com/blueimp/jQuery-File-Upload.git
lock: false
repository_class: Piston::Git::Repository
format: 1
handler:
commit: 57f986dad16bb0da500ca2b025a595da0a2b8719
branch: master

View File

@ -1,108 +0,0 @@
/*
* jQuery postMessage Transport Plugin 1.0
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*/
/*jslint unparam: true, nomen: true */
/*global jQuery, window, document */
(function ($) {
'use strict';
var counter = 0,
names = [
'accepts',
'cache',
'contents',
'contentType',
'crossDomain',
'data',
'dataType',
'headers',
'ifModified',
'mimeType',
'password',
'processData',
'timeout',
'traditional',
'type',
'url',
'username'
],
convert = function (p) {
return p;
};
$.ajaxSetup({
converters: {
'postmessage text': convert,
'postmessage json': convert,
'postmessage html': convert
}
});
$.ajaxTransport('postmessage', function (options) {
if (options.postMessage && window.postMessage) {
var iframe,
loc = $('<a>').prop('href', options.postMessage)[0],
target = loc.protocol + '//' + loc.host,
xhrUpload = options.xhr().upload;
return {
send: function (_, completeCallback) {
var message = {
id: 'postmessage-transport-' + (counter += 1)
},
eventName = 'message.' + message.id;
iframe = $(
'<iframe style="display:none;" src="' +
options.postMessage + '" name="' +
message.id + '"></iframe>'
).bind('load', function () {
$.each(names, function (i, name) {
message[name] = options[name];
});
message.dataType = message.dataType.replace('postmessage ', '');
$(window).bind(eventName, function (e) {
e = e.originalEvent;
var data = e.data,
ev;
if (e.origin === target && data.id === message.id) {
if (data.type === 'progress') {
ev = document.createEvent('Event');
ev.initEvent(data.type, false, true);
$.extend(ev, data);
xhrUpload.dispatchEvent(ev);
} else {
completeCallback(
data.status,
data.statusText,
{postmessage: data.result},
data.headers
);
iframe.remove();
$(window).unbind(eventName);
}
}
});
iframe[0].contentWindow.postMessage(
message,
target
);
}).appendTo(document.body);
},
abort: function () {
if (iframe) {
iframe.remove();
}
}
};
}
});
}(jQuery));

View File

@ -1,76 +0,0 @@
/*
* jQuery XDomainRequest Transport Plugin 1.0.2
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*
* Based on Julian Aubourg's ajaxHooks xdr.js:
* https://github.com/jaubourg/ajaxHooks/
*/
/*jslint unparam: true */
/*global jQuery, window, XDomainRequest */
(function ($) {
'use strict';
if (window.XDomainRequest) {
$.ajaxTransport(function (s) {
if (s.crossDomain && s.async) {
if (s.timeout) {
s.xdrTimeout = s.timeout;
delete s.timeout;
}
var xdr;
return {
send: function (headers, completeCallback) {
function callback(status, statusText, responses, responseHeaders) {
xdr.onload = xdr.onerror = xdr.ontimeout = jQuery.noop;
xdr = null;
completeCallback(status, statusText, responses, responseHeaders);
}
xdr = new XDomainRequest();
// XDomainRequest only supports GET and POST:
if (s.type === 'DELETE') {
s.url = s.url + (/\?/.test(s.url) ? '&' : '?') +
'_method=DELETE';
s.type = 'POST';
} else if (s.type === 'PUT') {
s.url = s.url + (/\?/.test(s.url) ? '&' : '?') +
'_method=PUT';
s.type = 'POST';
}
xdr.open(s.type, s.url);
xdr.onload = function () {
callback(
200,
'OK',
{text: xdr.responseText},
'Content-Type: ' + xdr.contentType
);
};
xdr.onerror = function () {
callback(404, 'Not Found');
};
if (s.xdrTimeout) {
xdr.ontimeout = function () {
callback(0, 'timeout');
};
xdr.timeout = s.xdrTimeout;
}
xdr.send((s.hasContent && s.data) || null);
},
abort: function () {
if (xdr) {
xdr.onerror = jQuery.noop();
xdr.abort();
}
}
};
}
});
}
}(jQuery));

View File

@ -1,538 +0,0 @@
/*
* jQuery File Upload User Interface Plugin 6.0.3
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*/
/*jslint nomen: true, unparam: true, regexp: true */
/*global window, document, URL, webkitURL, FileReader, jQuery */
(function ($) {
'use strict';
// The UI version extends the basic fileupload widget and adds
// a complete user interface based on the given upload/download
// templates.
$.widget('blueimpUI.fileupload', $.blueimp.fileupload, {
options: {
// By default, files added to the widget are uploaded as soon
// as the user clicks on the start buttons. To enable automatic
// uploads, set the following option to true:
autoUpload: false,
// The following option limits the number of files that are
// allowed to be uploaded using this widget:
maxNumberOfFiles: undefined,
// The maximum allowed file size:
maxFileSize: undefined,
// The minimum allowed file size:
minFileSize: 1,
// The regular expression for allowed file types, matches
// against either file type or file name:
acceptFileTypes: /.+$/i,
// The regular expression to define for which files a preview
// image is shown, matched against the file type:
previewFileTypes: /^image\/(gif|jpeg|png)$/,
// The maximum file size for preview images:
previewMaxFileSize: 5000000, // 5MB
// The maximum width of the preview images:
previewMaxWidth: 80,
// The maximum height of the preview images:
previewMaxHeight: 80,
// By default, preview images are displayed as canvas elements
// if supported by the browser. Set the following option to false
// to always display preview images as img elements:
previewAsCanvas: true,
// The expected data type of the upload response, sets the dataType
// option of the $.ajax upload requests:
dataType: 'json',
// The add callback is invoked as soon as files are added to the fileupload
// widget (via file input selection, drag & drop or add API call).
// See the basic file upload widget for more information:
add: function (e, data) {
var that = $(this).data('fileupload'),
files = data.files;
that._adjustMaxNumberOfFiles(-files.length);
data.isAdjusted = true;
data.files.valid = data.isValidated = that._validate(files);
data.context = that._renderUpload(files)
.appendTo(that._files)
.data('data', data);
// Force reflow:
that._reflow = that._transition && data.context[0].offsetWidth;
data.context.addClass('in');
if ((that.options.autoUpload || data.autoUpload) &&
data.isValidated) {
data.submit();
}
},
// Callback for the start of each file upload request:
send: function (e, data) {
if (!data.isValidated) {
var that = $(this).data('fileupload');
if (!data.isAdjusted) {
that._adjustMaxNumberOfFiles(-data.files.length);
}
if (!that._validate(data.files)) {
return false;
}
}
if (data.context && data.dataType &&
data.dataType.substr(0, 6) === 'iframe') {
// Iframe Transport does not support progress events.
// In lack of an indeterminate progress bar, we set
// the progress to 100%, showing the full animated bar:
data.context.find('.progressbar div').css(
'width',
parseInt(100, 10) + '%'
);
}
},
// Callback for successful uploads:
done: function (e, data) {
var that = $(this).data('fileupload'),
template,
preview;
if (data.context) {
data.context.each(function (index) {
var file = ($.isArray(data.result) &&
data.result[index]) || {error: 'emptyResult'};
if (file.error) {
that._adjustMaxNumberOfFiles(1);
}
that._transitionCallback(
$(this).removeClass('in'),
function (node) {
template = that._renderDownload([file]);
preview = node
.find('.preview img, .preview canvas');
if (preview.length) {
template.find('.preview img')
.prop('width', preview.prop('width'))
.prop('height', preview.prop('height'));
}
template
.replaceAll(node);
// Force reflow:
that._reflow = that._transition &&
template[0].offsetWidth;
template.addClass('in');
}
);
});
} else {
template = that._renderDownload(data.result)
.appendTo(that._files);
// Force reflow:
that._reflow = that._transition && template[0].offsetWidth;
template.addClass('in');
}
},
// Callback for failed (abort or error) uploads:
fail: function (e, data) {
var that = $(this).data('fileupload'),
template;
that._adjustMaxNumberOfFiles(data.files.length);
if (data.context) {
data.context.each(function (index) {
if (data.errorThrown !== 'abort') {
var file = data.files[index];
file.error = file.error || data.errorThrown ||
true;
that._transitionCallback(
$(this).removeClass('in'),
function (node) {
template = that._renderDownload([file])
.replaceAll(node);
// Force reflow:
that._reflow = that._transition &&
template[0].offsetWidth;
template.addClass('in');
}
);
} else {
that._transitionCallback(
$(this).removeClass('in'),
function (node) {
node.remove();
}
);
}
});
} else if (data.errorThrown !== 'abort') {
that._adjustMaxNumberOfFiles(-data.files.length);
data.context = that._renderUpload(data.files)
.appendTo(that._files)
.data('data', data);
// Force reflow:
that._reflow = that._transition && data.context[0].offsetWidth;
data.context.addClass('in');
}
},
// Callback for upload progress events:
progress: function (e, data) {
if (data.context) {
data.context.find('.progressbar div').css(
'width',
parseInt(data.loaded / data.total * 100, 10) + '%'
);
}
},
// Callback for global upload progress events:
progressall: function (e, data) {
$(this).find('.fileupload-progressbar div').css(
'width',
parseInt(data.loaded / data.total * 100, 10) + '%'
);
},
// Callback for uploads start, equivalent to the global ajaxStart event:
start: function () {
$(this).find('.fileupload-progressbar')
.addClass('in').find('div').css('width', '0%');
},
// Callback for uploads stop, equivalent to the global ajaxStop event:
stop: function () {
$(this).find('.fileupload-progressbar')
.removeClass('in').find('div').css('width', '0%');
},
// Callback for file deletion:
destroy: function (e, data) {
var that = $(this).data('fileupload');
if (data.url) {
$.ajax(data);
}
that._adjustMaxNumberOfFiles(1);
that._transitionCallback(
data.context.removeClass('in'),
function (node) {
node.remove();
}
);
}
},
// Link handler, that allows to download files
// by drag & drop of the links to the desktop:
_enableDragToDesktop: function () {
var link = $(this),
url = link.prop('href'),
name = decodeURIComponent(url.split('/').pop())
.replace(/:/g, '-'),
type = 'application/octet-stream';
link.bind('dragstart', function (e) {
try {
e.originalEvent.dataTransfer.setData(
'DownloadURL',
[type, name, url].join(':')
);
} catch (err) {}
});
},
_adjustMaxNumberOfFiles: function (operand) {
if (typeof this.options.maxNumberOfFiles === 'number') {
this.options.maxNumberOfFiles += operand;
if (this.options.maxNumberOfFiles < 1) {
this._disableFileInputButton();
} else {
this._enableFileInputButton();
}
}
},
_formatFileSize: function (bytes) {
if (typeof bytes !== 'number') {
return '';
}
if (bytes >= 1000000000) {
return (bytes / 1000000000).toFixed(2) + ' GB';
}
if (bytes >= 1000000) {
return (bytes / 1000000).toFixed(2) + ' MB';
}
return (bytes / 1000).toFixed(2) + ' KB';
},
_hasError: function (file) {
if (file.error) {
return file.error;
}
// The number of added files is subtracted from
// maxNumberOfFiles before validation, so we check if
// maxNumberOfFiles is below 0 (instead of below 1):
if (this.options.maxNumberOfFiles < 0) {
return 'maxNumberOfFiles';
}
// Files are accepted if either the file type or the file name
// matches against the acceptFileTypes regular expression, as
// only browsers with support for the File API report the type:
if (!(this.options.acceptFileTypes.test(file.type) ||
this.options.acceptFileTypes.test(file.name))) {
return 'acceptFileTypes';
}
if (this.options.maxFileSize &&
file.size > this.options.maxFileSize) {
return 'maxFileSize';
}
if (typeof file.size === 'number' &&
file.size < this.options.minFileSize) {
return 'minFileSize';
}
return null;
},
_validate: function (files) {
var that = this,
valid = !!files.length;
$.each(files, function (index, file) {
file.error = that._hasError(file);
if (file.error) {
valid = false;
}
});
return valid;
},
_renderTemplate: function (func, files) {
return $(this.options.templateContainer).html(func({
files: files,
formatFileSize: this._formatFileSize,
options: this.options
})).children();
},
_renderUpload: function (files) {
var that = this,
options = this.options,
nodes = this._renderTemplate(options.uploadTemplate, files);
nodes.find('.preview span').each(function (index, node) {
var file = files[index];
if (options.previewFileTypes.test(file.type) &&
(!options.previewMaxFileSize ||
file.size < options.previewMaxFileSize)) {
window.loadImage(
files[index],
function (img) {
$(node).append(img);
// Force reflow:
that._reflow = that._transition &&
node.offsetWidth;
$(node).addClass('in');
},
{
maxWidth: options.previewMaxWidth,
maxHeight: options.previewMaxHeight,
canvas: options.previewAsCanvas
}
);
}
});
return nodes;
},
_renderDownload: function (files) {
var nodes = this._renderTemplate(
this.options.downloadTemplate,
files
);
nodes.find('a').each(this._enableDragToDesktop);
return nodes;
},
_startHandler: function (e) {
e.preventDefault();
var button = $(this),
tmpl = button.closest('.template-upload'),
data = tmpl.data('data');
if (data && data.submit && !data.jqXHR && data.submit()) {
button.prop('disabled', true);
}
},
_cancelHandler: function (e) {
e.preventDefault();
var tmpl = $(this).closest('.template-upload'),
data = tmpl.data('data') || {};
if (!data.jqXHR) {
data.errorThrown = 'abort';
e.data.fileupload._trigger('fail', e, data);
} else {
data.jqXHR.abort();
}
},
_deleteHandler: function (e) {
e.preventDefault();
var button = $(this);
e.data.fileupload._trigger('destroy', e, {
context: button.closest('.template-download'),
url: button.attr('data-url'),
type: button.attr('data-type'),
dataType: e.data.fileupload.options.dataType
});
},
_transitionCallback: function (node, callback) {
var that = this;
if (this._transition && node.hasClass('fade')) {
node.bind(
this._transitionEnd,
function (e) {
// Make sure we don't respond to other transitions events
// in the container element, e.g. from button elements:
if (e.target === node[0]) {
node.unbind(that._transitionEnd);
callback.call(that, node);
}
}
);
} else {
callback.call(this, node);
}
},
_initTransitionSupport: function () {
var that = this,
style = (document.body || document.documentElement).style,
suffix = '.' + that.options.namespace;
that._transition = style.transition !== undefined ||
style.WebkitTransition !== undefined ||
style.MozTransition !== undefined ||
style.MsTransition !== undefined ||
style.OTransition !== undefined;
if (that._transition) {
that._transitionEnd = [
'MSTransitionEnd',
'webkitTransitionEnd',
'transitionend',
'oTransitionEnd'
].join(suffix + ' ') + suffix;
}
},
_initButtonBarEventHandlers: function () {
var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'),
filesList = this._files,
ns = this.options.namespace;
fileUploadButtonBar.find('.start')
.bind('click.' + ns, function (e) {
e.preventDefault();
filesList.find('.start button').click();
});
fileUploadButtonBar.find('.cancel')
.bind('click.' + ns, function (e) {
e.preventDefault();
filesList.find('.cancel button').click();
});
fileUploadButtonBar.find('.delete')
.bind('click.' + ns, function (e) {
e.preventDefault();
filesList.find('.delete input:checked')
.siblings('button').click();
});
fileUploadButtonBar.find('.toggle')
.bind('change.' + ns, function (e) {
filesList.find('.delete input').prop(
'checked',
$(this).is(':checked')
);
});
},
_destroyButtonBarEventHandlers: function () {
this.element.find('.fileupload-buttonbar button')
.unbind('click.' + this.options.namespace);
this.element.find('.fileupload-buttonbar .toggle')
.unbind('change.' + this.options.namespace);
},
_initEventHandlers: function () {
$.blueimp.fileupload.prototype._initEventHandlers.call(this);
var eventData = {fileupload: this};
this._files
.delegate(
'.start button',
'click.' + this.options.namespace,
eventData,
this._startHandler
)
.delegate(
'.cancel button',
'click.' + this.options.namespace,
eventData,
this._cancelHandler
)
.delegate(
'.delete button',
'click.' + this.options.namespace,
eventData,
this._deleteHandler
);
this._initButtonBarEventHandlers();
this._initTransitionSupport();
},
_destroyEventHandlers: function () {
this._destroyButtonBarEventHandlers();
this._files
.undelegate('.start button', 'click.' + this.options.namespace)
.undelegate('.cancel button', 'click.' + this.options.namespace)
.undelegate('.delete button', 'click.' + this.options.namespace);
$.blueimp.fileupload.prototype._destroyEventHandlers.call(this);
},
_enableFileInputButton: function () {
this.element.find('.fileinput-button input')
.prop('disabled', false)
.parent().removeClass('disabled');
},
_disableFileInputButton: function () {
this.element.find('.fileinput-button input')
.prop('disabled', true)
.parent().addClass('disabled');
},
_initTemplates: function () {
this.options.templateContainer = document.createElement(
this._files.prop('nodeName')
);
this.options.uploadTemplate = window.tmpl('template-upload');
this.options.downloadTemplate = window.tmpl('template-download');
},
_initFiles: function () {
this._files = this.element.find('.files');
},
_create: function () {
this._initFiles();
$.blueimp.fileupload.prototype._create.call(this);
this._initTemplates();
},
destroy: function () {
$.blueimp.fileupload.prototype.destroy.call(this);
},
enable: function () {
$.blueimp.fileupload.prototype.enable.call(this);
this.element.find('input, button').prop('disabled', false);
this._enableFileInputButton();
},
disable: function () {
this.element.find('input, button').prop('disabled', true);
this._disableFileInputButton();
$.blueimp.fileupload.prototype.disable.call(this);
}
});
}(jQuery));

View File

@ -1,831 +0,0 @@
/*
* jQuery File Upload Plugin 5.5.4
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*/
/*jslint nomen: true, unparam: true, regexp: true */
/*global document, XMLHttpRequestUpload, Blob, File, FormData, location, jQuery */
(function ($) {
'use strict';
// The fileupload widget listens for change events on file input fields defined
// via fileInput setting and paste or drop events of the given dropZone.
// In addition to the default jQuery Widget methods, the fileupload widget
// exposes the "add" and "send" methods, to add or directly send files using
// the fileupload API.
// By default, files added via file input selection, paste, drag & drop or
// "add" method are uploaded immediately, but it is possible to override
// the "add" callback option to queue file uploads.
$.widget('blueimp.fileupload', {
options: {
// The namespace used for event handler binding on the dropZone and
// fileInput collections.
// If not set, the name of the widget ("fileupload") is used.
namespace: undefined,
// The drop target collection, by the default the complete document.
// Set to null or an empty collection to disable drag & drop support:
dropZone: $(document),
// The file input field collection, that is listened for change events.
// If undefined, it is set to the file input fields inside
// of the widget element on plugin initialization.
// Set to null or an empty collection to disable the change listener.
fileInput: undefined,
// By default, the file input field is replaced with a clone after
// each input field change event. This is required for iframe transport
// queues and allows change events to be fired for the same file
// selection, but can be disabled by setting the following option to false:
replaceFileInput: true,
// The parameter name for the file form data (the request argument name).
// If undefined or empty, the name property of the file input field is
// used, or "files[]" if the file input name property is also empty:
paramName: undefined,
// By default, each file of a selection is uploaded using an individual
// request for XHR type uploads. Set to false to upload file
// selections in one request each:
singleFileUploads: true,
// To limit the number of files uploaded with one XHR request,
// set the following option to an integer greater than 0:
limitMultiFileUploads: undefined,
// Set the following option to true to issue all file upload requests
// in a sequential order:
sequentialUploads: false,
// To limit the number of concurrent uploads,
// set the following option to an integer greater than 0:
limitConcurrentUploads: undefined,
// Set the following option to true to force iframe transport uploads:
forceIframeTransport: false,
// Set the following option to the location of a postMessage window,
// to enable postMessage transport uploads:
postMessage: undefined,
// By default, XHR file uploads are sent as multipart/form-data.
// The iframe transport is always using multipart/form-data.
// Set to false to enable non-multipart XHR uploads:
multipart: true,
// To upload large files in smaller chunks, set the following option
// to a preferred maximum chunk size. If set to 0, null or undefined,
// or the browser does not support the required Blob API, files will
// be uploaded as a whole.
maxChunkSize: undefined,
// When a non-multipart upload or a chunked multipart upload has been
// aborted, this option can be used to resume the upload by setting
// it to the size of the already uploaded bytes. This option is most
// useful when modifying the options object inside of the "add" or
// "send" callbacks, as the options are cloned for each file upload.
uploadedBytes: undefined,
// By default, failed (abort or error) file uploads are removed from the
// global progress calculation. Set the following option to false to
// prevent recalculating the global progress data:
recalculateProgress: true,
// Additional form data to be sent along with the file uploads can be set
// using this option, which accepts an array of objects with name and
// value properties, a function returning such an array, a FormData
// object (for XHR file uploads), or a simple object.
// The form of the first fileInput is given as parameter to the function:
formData: function (form) {
return form.serializeArray();
},
// The add callback is invoked as soon as files are added to the fileupload
// widget (via file input selection, drag & drop, paste or add API call).
// If the singleFileUploads option is enabled, this callback will be
// called once for each file in the selection for XHR file uplaods, else
// once for each file selection.
// The upload starts when the submit method is invoked on the data parameter.
// The data object contains a files property holding the added files
// and allows to override plugin options as well as define ajax settings.
// Listeners for this callback can also be bound the following way:
// .bind('fileuploadadd', func);
// data.submit() returns a Promise object and allows to attach additional
// handlers using jQuery's Deferred callbacks:
// data.submit().done(func).fail(func).always(func);
add: function (e, data) {
data.submit();
},
// Other callbacks:
// Callback for the submit event of each file upload:
// submit: function (e, data) {}, // .bind('fileuploadsubmit', func);
// Callback for the start of each file upload request:
// send: function (e, data) {}, // .bind('fileuploadsend', func);
// Callback for successful uploads:
// done: function (e, data) {}, // .bind('fileuploaddone', func);
// Callback for failed (abort or error) uploads:
// fail: function (e, data) {}, // .bind('fileuploadfail', func);
// Callback for completed (success, abort or error) requests:
// always: function (e, data) {}, // .bind('fileuploadalways', func);
// Callback for upload progress events:
// progress: function (e, data) {}, // .bind('fileuploadprogress', func);
// Callback for global upload progress events:
// progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);
// Callback for uploads start, equivalent to the global ajaxStart event:
// start: function (e) {}, // .bind('fileuploadstart', func);
// Callback for uploads stop, equivalent to the global ajaxStop event:
// stop: function (e) {}, // .bind('fileuploadstop', func);
// Callback for change events of the fileInput collection:
// change: function (e, data) {}, // .bind('fileuploadchange', func);
// Callback for paste events to the dropZone collection:
// paste: function (e, data) {}, // .bind('fileuploadpaste', func);
// Callback for drop events of the dropZone collection:
// drop: function (e, data) {}, // .bind('fileuploaddrop', func);
// Callback for dragover events of the dropZone collection:
// dragover: function (e) {}, // .bind('fileuploaddragover', func);
// The plugin options are used as settings object for the ajax calls.
// The following are jQuery ajax settings required for the file uploads:
processData: false,
contentType: false,
cache: false
},
// A list of options that require a refresh after assigning a new value:
_refreshOptionsList: ['namespace', 'dropZone', 'fileInput'],
_isXHRUpload: function (options) {
var undef = 'undefined';
return !options.forceIframeTransport &&
typeof XMLHttpRequestUpload !== undef && typeof File !== undef &&
(!options.multipart || typeof FormData !== undef);
},
_getFormData: function (options) {
var formData;
if (typeof options.formData === 'function') {
return options.formData(options.form);
} else if ($.isArray(options.formData)) {
return options.formData;
} else if (options.formData) {
formData = [];
$.each(options.formData, function (name, value) {
formData.push({name: name, value: value});
});
return formData;
}
return [];
},
_getTotal: function (files) {
var total = 0;
$.each(files, function (index, file) {
total += file.size || 1;
});
return total;
},
_onProgress: function (e, data) {
if (e.lengthComputable) {
var total = data.total || this._getTotal(data.files),
loaded = parseInt(
e.loaded / e.total * (data.chunkSize || total),
10
) + (data.uploadedBytes || 0);
this._loaded += loaded - (data.loaded || data.uploadedBytes || 0);
data.lengthComputable = true;
data.loaded = loaded;
data.total = total;
// Trigger a custom progress event with a total data property set
// to the file size(s) of the current upload and a loaded data
// property calculated accordingly:
this._trigger('progress', e, data);
// Trigger a global progress event for all current file uploads,
// including ajax calls queued for sequential file uploads:
this._trigger('progressall', e, {
lengthComputable: true,
loaded: this._loaded,
total: this._total
});
}
},
_initProgressListener: function (options) {
var that = this,
xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
// Accesss to the native XHR object is required to add event listeners
// for the upload progress event:
if (xhr.upload) {
$(xhr.upload).bind('progress', function (e) {
var oe = e.originalEvent;
// Make sure the progress event properties get copied over:
e.lengthComputable = oe.lengthComputable;
e.loaded = oe.loaded;
e.total = oe.total;
that._onProgress(e, options);
});
options.xhr = function () {
return xhr;
};
}
},
_initXHRData: function (options) {
var formData,
file = options.files[0];
if (!options.multipart || options.blob) {
// For non-multipart uploads and chunked uploads,
// file meta data is not part of the request body,
// so we transmit this data as part of the HTTP headers.
// For cross domain requests, these headers must be allowed
// via Access-Control-Allow-Headers or removed using
// the beforeSend callback:
options.headers = $.extend(options.headers, {
'X-File-Name': file.name,
'X-File-Type': file.type,
'X-File-Size': file.size
});
if (!options.blob) {
// Non-chunked non-multipart upload:
options.contentType = file.type;
options.data = file;
} else if (!options.multipart) {
// Chunked non-multipart upload:
options.contentType = 'application/octet-stream';
options.data = options.blob;
}
}
if (options.multipart && typeof FormData !== 'undefined') {
if (options.postMessage) {
// window.postMessage does not allow sending FormData
// objects, so we just add the File/Blob objects to
// the formData array and let the postMessage window
// create the FormData object out of this array:
formData = this._getFormData(options);
if (options.blob) {
formData.push({
name: options.paramName,
value: options.blob
});
} else {
$.each(options.files, function (index, file) {
formData.push({
name: options.paramName,
value: file
});
});
}
} else {
if (options.formData instanceof FormData) {
formData = options.formData;
} else {
formData = new FormData();
$.each(this._getFormData(options), function (index, field) {
formData.append(field.name, field.value);
});
}
if (options.blob) {
formData.append(options.paramName, options.blob);
} else {
$.each(options.files, function (index, file) {
// File objects are also Blob instances.
// This check allows the tests to run with
// dummy objects:
if (file instanceof Blob) {
formData.append(options.paramName, file);
}
});
}
}
options.data = formData;
}
// Blob reference is not needed anymore, free memory:
options.blob = null;
},
_initIframeSettings: function (options) {
// Setting the dataType to iframe enables the iframe transport:
options.dataType = 'iframe ' + (options.dataType || '');
// The iframe transport accepts a serialized array as form data:
options.formData = this._getFormData(options);
},
_initDataSettings: function (options) {
if (this._isXHRUpload(options)) {
if (!this._chunkedUpload(options, true)) {
if (!options.data) {
this._initXHRData(options);
}
this._initProgressListener(options);
}
if (options.postMessage) {
// Setting the dataType to postmessage enables the
// postMessage transport:
options.dataType = 'postmessage ' + (options.dataType || '');
}
} else {
this._initIframeSettings(options, 'iframe');
}
},
_initFormSettings: function (options) {
// Retrieve missing options from the input field and the
// associated form, if available:
if (!options.form || !options.form.length) {
options.form = $(options.fileInput.prop('form'));
}
if (!options.paramName) {
options.paramName = options.fileInput.prop('name') ||
'files[]';
}
if (!options.url) {
options.url = options.form.prop('action') || location.href;
}
// The HTTP request method must be "POST" or "PUT":
options.type = (options.type || options.form.prop('method') || '')
.toUpperCase();
if (options.type !== 'POST' && options.type !== 'PUT') {
options.type = 'POST';
}
},
_getAJAXSettings: function (data) {
var options = $.extend({}, this.options, data);
this._initFormSettings(options);
this._initDataSettings(options);
return options;
},
// Maps jqXHR callbacks to the equivalent
// methods of the given Promise object:
_enhancePromise: function (promise) {
promise.success = promise.done;
promise.error = promise.fail;
promise.complete = promise.always;
return promise;
},
// Creates and returns a Promise object enhanced with
// the jqXHR methods abort, success, error and complete:
_getXHRPromise: function (resolveOrReject, context, args) {
var dfd = $.Deferred(),
promise = dfd.promise();
context = context || this.options.context || promise;
if (resolveOrReject === true) {
dfd.resolveWith(context, args);
} else if (resolveOrReject === false) {
dfd.rejectWith(context, args);
}
promise.abort = dfd.promise;
return this._enhancePromise(promise);
},
// Uploads a file in multiple, sequential requests
// by splitting the file up in multiple blob chunks.
// If the second parameter is true, only tests if the file
// should be uploaded in chunks, but does not invoke any
// upload requests:
_chunkedUpload: function (options, testOnly) {
var that = this,
file = options.files[0],
fs = file.size,
ub = options.uploadedBytes = options.uploadedBytes || 0,
mcs = options.maxChunkSize || fs,
// Use the Blob methods with the slice implementation
// according to the W3C Blob API specification:
slice = file.webkitSlice || file.mozSlice || file.slice,
upload,
n,
jqXHR,
pipe;
if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) ||
options.data) {
return false;
}
if (testOnly) {
return true;
}
if (ub >= fs) {
file.error = 'uploadedBytes';
return this._getXHRPromise(
false,
options.context,
[null, 'error', file.error]
);
}
// n is the number of blobs to upload,
// calculated via filesize, uploaded bytes and max chunk size:
n = Math.ceil((fs - ub) / mcs);
// The chunk upload method accepting the chunk number as parameter:
upload = function (i) {
if (!i) {
return that._getXHRPromise(true, options.context);
}
// Upload the blobs in sequential order:
return upload(i -= 1).pipe(function () {
// Clone the options object for each chunk upload:
var o = $.extend({}, options);
o.blob = slice.call(
file,
ub + i * mcs,
ub + (i + 1) * mcs
);
// Store the current chunk size, as the blob itself
// will be dereferenced after data processing:
o.chunkSize = o.blob.size;
// Process the upload data (the blob and potential form data):
that._initXHRData(o);
// Add progress listeners for this chunk upload:
that._initProgressListener(o);
jqXHR = ($.ajax(o) || that._getXHRPromise(false, o.context))
.done(function () {
// Create a progress event if upload is done and
// no progress event has been invoked for this chunk:
if (!o.loaded) {
that._onProgress($.Event('progress', {
lengthComputable: true,
loaded: o.chunkSize,
total: o.chunkSize
}), o);
}
options.uploadedBytes = o.uploadedBytes +=
o.chunkSize;
});
return jqXHR;
});
};
// Return the piped Promise object, enhanced with an abort method,
// which is delegated to the jqXHR object of the current upload,
// and jqXHR callbacks mapped to the equivalent Promise methods:
pipe = upload(n);
pipe.abort = function () {
return jqXHR.abort();
};
return this._enhancePromise(pipe);
},
_beforeSend: function (e, data) {
if (this._active === 0) {
// the start callback is triggered when an upload starts
// and no other uploads are currently running,
// equivalent to the global ajaxStart event:
this._trigger('start');
}
this._active += 1;
// Initialize the global progress values:
this._loaded += data.uploadedBytes || 0;
this._total += this._getTotal(data.files);
},
_onDone: function (result, textStatus, jqXHR, options) {
if (!this._isXHRUpload(options)) {
// Create a progress event for each iframe load:
this._onProgress($.Event('progress', {
lengthComputable: true,
loaded: 1,
total: 1
}), options);
}
options.result = result;
options.textStatus = textStatus;
options.jqXHR = jqXHR;
this._trigger('done', null, options);
},
_onFail: function (jqXHR, textStatus, errorThrown, options) {
options.jqXHR = jqXHR;
options.textStatus = textStatus;
options.errorThrown = errorThrown;
this._trigger('fail', null, options);
if (options.recalculateProgress) {
// Remove the failed (error or abort) file upload from
// the global progress calculation:
this._loaded -= options.loaded || options.uploadedBytes || 0;
this._total -= options.total || this._getTotal(options.files);
}
},
_onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {
this._active -= 1;
options.textStatus = textStatus;
if (jqXHRorError && jqXHRorError.always) {
options.jqXHR = jqXHRorError;
options.result = jqXHRorResult;
} else {
options.jqXHR = jqXHRorResult;
options.errorThrown = jqXHRorError;
}
this._trigger('always', null, options);
if (this._active === 0) {
// The stop callback is triggered when all uploads have
// been completed, equivalent to the global ajaxStop event:
this._trigger('stop');
// Reset the global progress values:
this._loaded = this._total = 0;
}
},
_onSend: function (e, data) {
var that = this,
jqXHR,
slot,
pipe,
options = that._getAJAXSettings(data),
send = function (resolve, args) {
that._sending += 1;
jqXHR = jqXHR || (
(resolve !== false &&
that._trigger('send', e, options) !== false &&
(that._chunkedUpload(options) || $.ajax(options))) ||
that._getXHRPromise(false, options.context, args)
).done(function (result, textStatus, jqXHR) {
that._onDone(result, textStatus, jqXHR, options);
}).fail(function (jqXHR, textStatus, errorThrown) {
that._onFail(jqXHR, textStatus, errorThrown, options);
}).always(function (jqXHRorResult, textStatus, jqXHRorError) {
that._sending -= 1;
that._onAlways(
jqXHRorResult,
textStatus,
jqXHRorError,
options
);
if (options.limitConcurrentUploads &&
options.limitConcurrentUploads > that._sending) {
// Start the next queued upload,
// that has not been aborted:
var nextSlot = that._slots.shift();
while (nextSlot) {
if (!nextSlot.isRejected()) {
nextSlot.resolve();
break;
}
nextSlot = that._slots.shift();
}
}
});
return jqXHR;
};
this._beforeSend(e, options);
if (this.options.sequentialUploads ||
(this.options.limitConcurrentUploads &&
this.options.limitConcurrentUploads <= this._sending)) {
if (this.options.limitConcurrentUploads > 1) {
slot = $.Deferred();
this._slots.push(slot);
pipe = slot.pipe(send);
} else {
pipe = (this._sequence = this._sequence.pipe(send, send));
}
// Return the piped Promise object, enhanced with an abort method,
// which is delegated to the jqXHR object of the current upload,
// and jqXHR callbacks mapped to the equivalent Promise methods:
pipe.abort = function () {
var args = [undefined, 'abort', 'abort'];
if (!jqXHR) {
if (slot) {
slot.rejectWith(args);
}
return send(false, args);
}
return jqXHR.abort();
};
return this._enhancePromise(pipe);
}
return send();
},
_onAdd: function (e, data) {
var that = this,
result = true,
options = $.extend({}, this.options, data),
limit = options.limitMultiFileUploads,
fileSet,
i;
if (!(options.singleFileUploads || limit) ||
!this._isXHRUpload(options)) {
fileSet = [data.files];
} else if (!options.singleFileUploads && limit) {
fileSet = [];
for (i = 0; i < data.files.length; i += limit) {
fileSet.push(data.files.slice(i, i + limit));
}
}
data.originalFiles = data.files;
$.each(fileSet || data.files, function (index, element) {
var files = fileSet ? element : [element],
newData = $.extend({}, data, {files: files});
newData.submit = function () {
newData.jqXHR = this.jqXHR =
(that._trigger('submit', e, this) !== false) &&
that._onSend(e, this);
return this.jqXHR;
};
return (result = that._trigger('add', e, newData));
});
return result;
},
// File Normalization for Gecko 1.9.1 (Firefox 3.5) support:
_normalizeFile: function (index, file) {
if (file.name === undefined && file.size === undefined) {
file.name = file.fileName;
file.size = file.fileSize;
}
},
_replaceFileInput: function (input) {
var inputClone = input.clone(true);
$('<form></form>').append(inputClone)[0].reset();
// Detaching allows to insert the fileInput on another form
// without loosing the file input value:
input.after(inputClone).detach();
// Avoid memory leaks with the detached file input:
$.cleanData(input.unbind('remove'));
// Replace the original file input element in the fileInput
// collection with the clone, which has been copied including
// event handlers:
this.options.fileInput = this.options.fileInput.map(function (i, el) {
if (el === input[0]) {
return inputClone[0];
}
return el;
});
// If the widget has been initialized on the file input itself,
// override this.element with the file input clone:
if (input[0] === this.element[0]) {
this.element = inputClone;
}
},
_onChange: function (e) {
var that = e.data.fileupload,
data = {
files: $.each($.makeArray(e.target.files), that._normalizeFile),
fileInput: $(e.target),
form: $(e.target.form)
};
if (!data.files.length) {
// If the files property is not available, the browser does not
// support the File API and we add a pseudo File object with
// the input value as name with path information removed:
data.files = [{name: e.target.value.replace(/^.*\\/, '')}];
}
if (that.options.replaceFileInput) {
that._replaceFileInput(data.fileInput);
}
if (that._trigger('change', e, data) === false ||
that._onAdd(e, data) === false) {
return false;
}
},
_onPaste: function (e) {
var that = e.data.fileupload,
cbd = e.originalEvent.clipboardData,
items = (cbd && cbd.items) || [],
data = {files: []};
$.each(items, function (index, item) {
var file = item.getAsFile && item.getAsFile();
if (file) {
data.files.push(file);
}
});
if (that._trigger('paste', e, data) === false ||
that._onAdd(e, data) === false) {
return false;
}
},
_onDrop: function (e) {
var that = e.data.fileupload,
dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer,
data = {
files: $.each(
$.makeArray(dataTransfer && dataTransfer.files),
that._normalizeFile
)
};
if (that._trigger('drop', e, data) === false ||
that._onAdd(e, data) === false) {
return false;
}
e.preventDefault();
},
_onDragOver: function (e) {
var that = e.data.fileupload,
dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer;
if (that._trigger('dragover', e) === false) {
return false;
}
if (dataTransfer) {
dataTransfer.dropEffect = dataTransfer.effectAllowed = 'copy';
}
e.preventDefault();
},
_initEventHandlers: function () {
var ns = this.options.namespace;
this.options.dropZone
.bind('dragover.' + ns, {fileupload: this}, this._onDragOver)
.bind('drop.' + ns, {fileupload: this}, this._onDrop)
.bind('paste.' + ns, {fileupload: this}, this._onPaste);
this.options.fileInput
.bind('change.' + ns, {fileupload: this}, this._onChange);
},
_destroyEventHandlers: function () {
var ns = this.options.namespace;
this.options.dropZone
.unbind('dragover.' + ns, this._onDragOver)
.unbind('drop.' + ns, this._onDrop)
.unbind('paste.' + ns, this._onPaste);
this.options.fileInput
.unbind('change.' + ns, this._onChange);
},
_beforeSetOption: function (key, value) {
this._destroyEventHandlers();
},
_afterSetOption: function (key, value) {
var options = this.options;
if (!options.fileInput) {
options.fileInput = $();
}
if (!options.dropZone) {
options.dropZone = $();
}
this._initEventHandlers();
},
_setOption: function (key, value) {
var refresh = $.inArray(key, this._refreshOptionsList) !== -1;
if (refresh) {
this._beforeSetOption(key, value);
}
$.Widget.prototype._setOption.call(this, key, value);
if (refresh) {
this._afterSetOption(key, value);
}
},
_create: function () {
var options = this.options;
options.namespace = options.namespace || this.widgetName;
if (options.fileInput === undefined) {
options.fileInput = this.element.is('input:file') ?
this.element : this.element.find('input:file');
} else if (!options.fileInput) {
options.fileInput = $();
}
if (!options.dropZone) {
options.dropZone = $();
}
this._slots = [];
this._sequence = this._getXHRPromise(true);
this._sending = this._active = this._loaded = this._total = 0;
this._initEventHandlers();
},
destroy: function () {
this._destroyEventHandlers();
$.Widget.prototype.destroy.call(this);
},
enable: function () {
$.Widget.prototype.enable.call(this);
this._initEventHandlers();
},
disable: function () {
this._destroyEventHandlers();
$.Widget.prototype.disable.call(this);
},
// This method is exposed to the widget API and allows adding files
// using the fileupload API. The data parameter accepts an object which
// must have a files property and can contain additional options:
// .fileupload('add', {files: filesList});
add: function (data) {
if (!data || this.options.disabled) {
return;
}
data.files = $.each($.makeArray(data.files), this._normalizeFile);
this._onAdd(null, data);
},
// This method is exposed to the widget API and allows sending files
// using the fileupload API. The data parameter accepts an object which
// must have a files property and can contain additional options:
// .fileupload('send', {files: filesList});
// The method returns a Promise object for the file upload call.
send: function (data) {
if (data && !this.options.disabled) {
data.files = $.each($.makeArray(data.files), this._normalizeFile);
if (data.files.length) {
return this._onSend(null, data);
}
}
return this._getXHRPromise(false, data && data.context);
}
});
}(jQuery));

View File

@ -1,156 +0,0 @@
/*
* jQuery Iframe Transport Plugin 1.2.5
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*/
/*jslint unparam: true, nomen: true */
/*global jQuery, document */
(function ($) {
'use strict';
// Helper variable to create unique names for the transport iframes:
var counter = 0;
// The iframe transport accepts three additional options:
// options.fileInput: a jQuery collection of file input fields
// options.paramName: the parameter name for the file form data,
// overrides the name property of the file input field(s)
// options.formData: an array of objects with name and value properties,
// equivalent to the return data of .serializeArray(), e.g.:
// [{name: 'a', value: 1}, {name: 'b', value: 2}]
$.ajaxTransport('iframe', function (options) {
if (options.async && (options.type === 'POST' || options.type === 'GET')) {
var form,
iframe;
return {
send: function (_, completeCallback) {
form = $('<form style="display:none;"></form>');
// javascript:false as initial iframe src
// prevents warning popups on HTTPS in IE6.
// IE versions below IE8 cannot set the name property of
// elements that have already been added to the DOM,
// so we set the name along with the iframe HTML markup:
iframe = $(
'<iframe src="javascript:false;" name="iframe-transport-' +
(counter += 1) + '"></iframe>'
).bind('load', function () {
var fileInputClones;
iframe
.unbind('load')
.bind('load', function () {
var response;
// Wrap in a try/catch block to catch exceptions thrown
// when trying to access cross-domain iframe contents:
try {
response = iframe.contents();
// Google Chrome and Firefox do not throw an
// exception when calling iframe.contents() on
// cross-domain requests, so we unify the response:
if (!response.length || !response[0].firstChild) {
throw new Error();
}
} catch (e) {
response = undefined;
}
// The complete callback returns the
// iframe content document as response object:
completeCallback(
200,
'success',
{'iframe': response}
);
// Fix for IE endless progress bar activity bug
// (happens on form submits to iframe targets):
$('<iframe src="javascript:false;"></iframe>')
.appendTo(form);
form.remove();
});
form
.prop('target', iframe.prop('name'))
.prop('action', options.url)
.prop('method', options.type);
if (options.formData) {
$.each(options.formData, function (index, field) {
$('<input type="hidden"/>')
.prop('name', field.name)
.val(field.value)
.appendTo(form);
});
}
if (options.fileInput && options.fileInput.length &&
options.type === 'POST') {
fileInputClones = options.fileInput.clone();
// Insert a clone for each file input field:
options.fileInput.after(function (index) {
return fileInputClones[index];
});
if (options.paramName) {
options.fileInput.each(function () {
$(this).prop('name', options.paramName);
});
}
// Appending the file input fields to the hidden form
// removes them from their original location:
form
.append(options.fileInput)
.prop('enctype', 'multipart/form-data')
// enctype must be set as encoding for IE:
.prop('encoding', 'multipart/form-data');
}
form.submit();
// Insert the file input fields at their original location
// by replacing the clones with the originals:
if (fileInputClones && fileInputClones.length) {
options.fileInput.each(function (index, input) {
var clone = $(fileInputClones[index]);
$(input).prop('name', clone.prop('name'));
clone.replaceWith(input);
});
}
});
form.append(iframe).appendTo(document.body);
},
abort: function () {
if (iframe) {
// javascript:false as iframe src aborts the request
// and prevents warning popups on HTTPS in IE6.
// concat is used to avoid the "Script URL" JSLint error:
iframe
.unbind('load')
.prop('src', 'javascript'.concat(':false;'));
}
if (form) {
form.remove();
}
}
};
}
});
// The iframe transport returns the iframe content document as response.
// The following adds converters from iframe to text, json, html, and script:
$.ajaxSetup({
converters: {
'iframe text': function (iframe) {
return $(iframe[0].body).text();
},
'iframe json': function (iframe) {
return $.parseJSON($(iframe[0].body).text());
},
'iframe html': function (iframe) {
return $(iframe[0].body).html();
},
'iframe script': function (iframe) {
return $.globalEval($(iframe[0].body).text());
}
}
});
}(jQuery));