fine_uploader 3.1.1 → 3.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +1 -3
- data/Vendorfile +16 -5
- data/lib/fine_uploader/version.rb +1 -1
- data/vendor/assets/javascripts/fine_uploader/ajax.requester.js +184 -0
- data/vendor/assets/javascripts/fine_uploader/button.js +62 -58
- data/vendor/assets/javascripts/fine_uploader/deletefile.ajax.requester.js +44 -0
- data/vendor/assets/javascripts/fine_uploader/dnd.js +2 -0
- data/vendor/assets/javascripts/fine_uploader/handler.base.js +164 -92
- data/vendor/assets/javascripts/fine_uploader/handler.form.js +220 -133
- data/vendor/assets/javascripts/fine_uploader/handler.xhr.js +594 -132
- data/vendor/assets/javascripts/fine_uploader/header.js +3 -4
- data/vendor/assets/javascripts/fine_uploader/iframe.xss.response.js +6 -0
- data/vendor/assets/javascripts/fine_uploader/jquery-plugin.js +13 -4
- data/vendor/assets/javascripts/fine_uploader/paste.js +49 -0
- data/vendor/assets/javascripts/fine_uploader/promise.js +45 -0
- data/vendor/assets/javascripts/fine_uploader/uploader.basic.js +547 -175
- data/vendor/assets/javascripts/fine_uploader/uploader.js +197 -42
- data/vendor/assets/javascripts/fine_uploader/util.js +117 -12
- data/vendor/assets/javascripts/fine_uploader/window.receive.message.js +32 -0
- data/vendor/assets/javascripts/fine_uploader.js +17 -0
- data/vendor/assets/stylesheets/fine_uploader.css.scss +6 -7
- metadata +9 -2
@@ -1,161 +1,143 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
qq.UploadHandlerForm = function(o){
|
6
|
-
qq.UploadHandlerAbstract.apply(this, arguments);
|
7
|
-
|
8
|
-
this._inputs = {};
|
9
|
-
this._detach_load_events = {};
|
10
|
-
};
|
11
|
-
// @inherits qq.UploadHandlerAbstract
|
12
|
-
qq.extend(qq.UploadHandlerForm.prototype, qq.UploadHandlerAbstract.prototype);
|
1
|
+
/*globals qq, document, setTimeout*/
|
2
|
+
/*globals clearTimeout*/
|
3
|
+
qq.UploadHandlerForm = function(o, uploadCompleteCallback, logCallback) {
|
4
|
+
"use strict";
|
13
5
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
6
|
+
var options = o,
|
7
|
+
inputs = [],
|
8
|
+
uuids = [],
|
9
|
+
detachLoadEvents = {},
|
10
|
+
postMessageCallbackTimers = {},
|
11
|
+
uploadComplete = uploadCompleteCallback,
|
12
|
+
log = logCallback,
|
13
|
+
corsMessageReceiver = new qq.WindowReceiveMessage({log: log}),
|
14
|
+
onloadCallbacks = {},
|
15
|
+
api;
|
18
16
|
|
19
|
-
this._inputs[id] = fileInput;
|
20
17
|
|
21
|
-
|
22
|
-
if (
|
23
|
-
|
18
|
+
function detachLoadEvent(id) {
|
19
|
+
if (detachLoadEvents[id] !== undefined) {
|
20
|
+
detachLoadEvents[id]();
|
21
|
+
delete detachLoadEvents[id];
|
24
22
|
}
|
23
|
+
}
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
getName: function(id){
|
29
|
-
// get input value and remove path to normalize
|
30
|
-
return this._inputs[id].value.replace(/.*(\/|\\)/, "");
|
31
|
-
},
|
32
|
-
isValid: function(id) {
|
33
|
-
return this._inputs[id] !== undefined;
|
34
|
-
},
|
35
|
-
reset: function() {
|
36
|
-
qq.UploadHandlerAbstract.prototype.reset.apply(this, arguments);
|
37
|
-
this._inputs = {};
|
38
|
-
this._detach_load_events = {};
|
39
|
-
},
|
40
|
-
_cancel: function(id){
|
41
|
-
this._options.onCancel(id, this.getName(id));
|
42
|
-
|
43
|
-
delete this._inputs[id];
|
44
|
-
delete this._detach_load_events[id];
|
45
|
-
|
46
|
-
var iframe = document.getElementById(id);
|
47
|
-
if (iframe){
|
48
|
-
// to cancel request set src to something else
|
49
|
-
// we use src="javascript:false;" because it doesn't
|
50
|
-
// trigger ie6 prompt on https
|
51
|
-
iframe.setAttribute('src', 'javascript:false;');
|
52
|
-
|
53
|
-
qq(iframe).remove();
|
54
|
-
}
|
55
|
-
},
|
56
|
-
_upload: function(id){
|
57
|
-
this._options.onUpload(id, this.getName(id), false);
|
58
|
-
var input = this._inputs[id];
|
25
|
+
function registerPostMessageCallback(iframe, callback) {
|
26
|
+
var id = iframe.id;
|
59
27
|
|
60
|
-
|
61
|
-
throw new Error('file with passed id was not added, or already uploaded or cancelled');
|
62
|
-
}
|
28
|
+
onloadCallbacks[uuids[id]] = callback;
|
63
29
|
|
64
|
-
|
30
|
+
detachLoadEvents[id] = qq(iframe).attach('load', function() {
|
31
|
+
if (inputs[id]) {
|
32
|
+
log("Received iframe load event for CORS upload request (file id " + id + ")");
|
65
33
|
|
66
|
-
|
67
|
-
|
68
|
-
|
34
|
+
postMessageCallbackTimers[id] = setTimeout(function() {
|
35
|
+
var errorMessage = "No valid message received from loaded iframe for file id " + id;
|
36
|
+
log(errorMessage, "error");
|
37
|
+
callback({
|
38
|
+
error: errorMessage
|
39
|
+
});
|
40
|
+
}, 1000);
|
41
|
+
}
|
42
|
+
});
|
69
43
|
|
70
|
-
|
71
|
-
|
72
|
-
|
44
|
+
corsMessageReceiver.receiveMessage(id, function(message) {
|
45
|
+
log("Received the following window message: '" + message + "'");
|
46
|
+
var response = qq.parseJson(message),
|
47
|
+
uuid = response.uuid,
|
48
|
+
onloadCallback;
|
73
49
|
|
74
|
-
|
50
|
+
if (uuid && onloadCallbacks[uuid]) {
|
51
|
+
clearTimeout(postMessageCallbackTimers[id]);
|
52
|
+
delete postMessageCallbackTimers[id];
|
75
53
|
|
76
|
-
|
77
|
-
setTimeout(function(){
|
78
|
-
self._detach_load_events[id]();
|
79
|
-
delete self._detach_load_events[id];
|
80
|
-
qq(iframe).remove();
|
81
|
-
}, 1);
|
54
|
+
detachLoadEvent(id);
|
82
55
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
56
|
+
onloadCallback = onloadCallbacks[uuid];
|
57
|
+
|
58
|
+
delete onloadCallbacks[uuid];
|
59
|
+
corsMessageReceiver.stopReceivingMessages(id);
|
60
|
+
onloadCallback(response);
|
61
|
+
}
|
62
|
+
else if (!uuid) {
|
63
|
+
log("'" + message + "' does not contain a UUID - ignoring.");
|
87
64
|
}
|
88
|
-
self._options.onComplete(id, fileName, response);
|
89
|
-
self._dequeue(id);
|
90
65
|
});
|
66
|
+
}
|
91
67
|
|
92
|
-
|
93
|
-
|
94
|
-
qq(form).remove();
|
95
|
-
|
96
|
-
return id;
|
97
|
-
},
|
98
|
-
_attachLoadEvent: function(iframe, callback){
|
99
|
-
var self = this;
|
100
|
-
this._detach_load_events[iframe.id] = qq(iframe).attach('load', function(){
|
101
|
-
self.log('Received response for ' + iframe.id);
|
102
|
-
|
103
|
-
// when we remove iframe from dom
|
104
|
-
// the request stops, but in IE load
|
105
|
-
// event fires
|
106
|
-
if (!iframe.parentNode){
|
107
|
-
return;
|
108
|
-
}
|
68
|
+
function attachLoadEvent(iframe, callback) {
|
69
|
+
/*jslint eqeq: true*/
|
109
70
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
71
|
+
if (options.cors.expected) {
|
72
|
+
registerPostMessageCallback(iframe, callback);
|
73
|
+
}
|
74
|
+
else {
|
75
|
+
detachLoadEvents[iframe.id] = qq(iframe).attach('load', function(){
|
76
|
+
log('Received response for ' + iframe.id);
|
77
|
+
|
78
|
+
// when we remove iframe from dom
|
79
|
+
// the request stops, but in IE load
|
80
|
+
// event fires
|
81
|
+
if (!iframe.parentNode){
|
119
82
|
return;
|
120
83
|
}
|
121
|
-
}
|
122
|
-
catch (error) {
|
123
|
-
//IE may throw an "access is denied" error when attempting to access contentDocument on the iframe in some cases
|
124
|
-
self.log('Error when attempting to access iframe during handling of upload response (' + error + ")", 'error');
|
125
|
-
}
|
126
84
|
|
127
|
-
|
128
|
-
|
129
|
-
|
85
|
+
try {
|
86
|
+
// fixing Opera 10.53
|
87
|
+
if (iframe.contentDocument &&
|
88
|
+
iframe.contentDocument.body &&
|
89
|
+
iframe.contentDocument.body.innerHTML == "false"){
|
90
|
+
// In Opera event is fired second time
|
91
|
+
// when body.innerHTML changed from false
|
92
|
+
// to server response approx. after 1 sec
|
93
|
+
// when we upload file with iframe
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
}
|
97
|
+
catch (error) {
|
98
|
+
//IE may throw an "access is denied" error when attempting to access contentDocument on the iframe in some cases
|
99
|
+
log('Error when attempting to access iframe during handling of upload response (' + error + ")", 'error');
|
100
|
+
}
|
101
|
+
|
102
|
+
callback();
|
103
|
+
});
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
130
107
|
/**
|
131
108
|
* Returns json object received by iframe from server.
|
132
109
|
*/
|
133
|
-
|
110
|
+
function getIframeContentJson(iframe) {
|
111
|
+
/*jshint evil: true*/
|
112
|
+
|
113
|
+
var response;
|
114
|
+
|
134
115
|
//IE may throw an "access is denied" error when attempting to access contentDocument on the iframe in some cases
|
135
116
|
try {
|
136
117
|
// iframe.contentWindow.document - for IE<7
|
137
|
-
var doc = iframe.contentDocument
|
138
|
-
|
118
|
+
var doc = iframe.contentDocument || iframe.contentWindow.document,
|
119
|
+
innerHTML = doc.body.innerHTML;
|
139
120
|
|
140
|
-
|
141
|
-
|
142
|
-
this.log("innerHTML = " + innerHTML);
|
121
|
+
log("converting iframe's innerHTML to JSON");
|
122
|
+
log("innerHTML = " + innerHTML);
|
143
123
|
//plain text response may be wrapped in <pre> tag
|
144
124
|
if (innerHTML && innerHTML.match(/^<pre/i)) {
|
145
125
|
innerHTML = doc.body.firstChild.firstChild.nodeValue;
|
146
126
|
}
|
147
|
-
|
127
|
+
|
128
|
+
response = qq.parseJson(innerHTML);
|
148
129
|
} catch(error){
|
149
|
-
|
130
|
+
log('Error when attempting to parse form upload response (' + error + ")", 'error');
|
150
131
|
response = {success: false};
|
151
132
|
}
|
152
133
|
|
153
134
|
return response;
|
154
|
-
}
|
135
|
+
}
|
136
|
+
|
155
137
|
/**
|
156
138
|
* Creates iframe with unique name
|
157
139
|
*/
|
158
|
-
|
140
|
+
function createIframe(id){
|
159
141
|
// We can't use following code as the name attribute
|
160
142
|
// won't be properly registered in IE6, and new window
|
161
143
|
// on form submit will open
|
@@ -163,7 +145,6 @@ qq.extend(qq.UploadHandlerForm.prototype, {
|
|
163
145
|
// iframe.setAttribute('name', id);
|
164
146
|
|
165
147
|
var iframe = qq.toElement('<iframe src="javascript:false;" name="' + id + '" />');
|
166
|
-
// src="javascript:false;" removes ie6 prompt on https
|
167
148
|
|
168
149
|
iframe.setAttribute('id', id);
|
169
150
|
|
@@ -171,22 +152,22 @@ qq.extend(qq.UploadHandlerForm.prototype, {
|
|
171
152
|
document.body.appendChild(iframe);
|
172
153
|
|
173
154
|
return iframe;
|
174
|
-
}
|
155
|
+
}
|
156
|
+
|
175
157
|
/**
|
176
158
|
* Creates form, that will be submitted to iframe
|
177
159
|
*/
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
// form.setAttribute('method', 'post');
|
182
|
-
// form.setAttribute('enctype', 'multipart/form-data');
|
183
|
-
// Because in this case file won't be attached to request
|
184
|
-
var protocol = this._options.demoMode ? "GET" : "POST",
|
160
|
+
function createForm(id, iframe){
|
161
|
+
var params = options.paramsStore.getParams(id),
|
162
|
+
protocol = options.demoMode ? "GET" : "POST",
|
185
163
|
form = qq.toElement('<form method="' + protocol + '" enctype="multipart/form-data"></form>'),
|
186
|
-
|
164
|
+
endpoint = options.endpointStore.getEndpoint(id),
|
165
|
+
url = endpoint;
|
166
|
+
|
167
|
+
params[options.uuidParamName] = uuids[id];
|
187
168
|
|
188
|
-
if (!
|
189
|
-
url = qq.obj2url(params,
|
169
|
+
if (!options.paramsInBody) {
|
170
|
+
url = qq.obj2url(params, endpoint);
|
190
171
|
}
|
191
172
|
else {
|
192
173
|
qq.obj2Inputs(params, form);
|
@@ -199,4 +180,110 @@ qq.extend(qq.UploadHandlerForm.prototype, {
|
|
199
180
|
|
200
181
|
return form;
|
201
182
|
}
|
202
|
-
|
183
|
+
|
184
|
+
|
185
|
+
api = {
|
186
|
+
add: function(fileInput) {
|
187
|
+
fileInput.setAttribute('name', options.inputName);
|
188
|
+
|
189
|
+
var id = inputs.push(fileInput) - 1;
|
190
|
+
uuids[id] = qq.getUniqueId();
|
191
|
+
|
192
|
+
// remove file input from DOM
|
193
|
+
if (fileInput.parentNode){
|
194
|
+
qq(fileInput).remove();
|
195
|
+
}
|
196
|
+
|
197
|
+
return id;
|
198
|
+
},
|
199
|
+
getName: function(id) {
|
200
|
+
/*jslint regexp: true*/
|
201
|
+
|
202
|
+
if (api.isValid(id)) {
|
203
|
+
// get input value and remove path to normalize
|
204
|
+
return inputs[id].value.replace(/.*(\/|\\)/, "");
|
205
|
+
}
|
206
|
+
else {
|
207
|
+
log(id + " is not a valid item ID.", "error");
|
208
|
+
}
|
209
|
+
},
|
210
|
+
isValid: function(id) {
|
211
|
+
return inputs[id] !== undefined;
|
212
|
+
},
|
213
|
+
reset: function() {
|
214
|
+
inputs = [];
|
215
|
+
uuids = [];
|
216
|
+
detachLoadEvents = {};
|
217
|
+
},
|
218
|
+
getUuid: function(id) {
|
219
|
+
return uuids[id];
|
220
|
+
},
|
221
|
+
cancel: function(id) {
|
222
|
+
options.onCancel(id, this.getName(id));
|
223
|
+
|
224
|
+
delete inputs[id];
|
225
|
+
delete uuids[id];
|
226
|
+
delete detachLoadEvents[id];
|
227
|
+
|
228
|
+
if (options.cors.expected) {
|
229
|
+
clearTimeout(postMessageCallbackTimers[id]);
|
230
|
+
delete postMessageCallbackTimers[id];
|
231
|
+
corsMessageReceiver.stopReceivingMessages(id);
|
232
|
+
}
|
233
|
+
|
234
|
+
var iframe = document.getElementById(id);
|
235
|
+
if (iframe) {
|
236
|
+
// to cancel request set src to something else
|
237
|
+
// we use src="javascript:false;" because it doesn't
|
238
|
+
// trigger ie6 prompt on https
|
239
|
+
iframe.setAttribute('src', 'java' + String.fromCharCode(115) + 'cript:false;'); //deal with "JSLint: javascript URL" warning, which apparently cannot be turned off
|
240
|
+
|
241
|
+
qq(iframe).remove();
|
242
|
+
}
|
243
|
+
},
|
244
|
+
upload: function(id){
|
245
|
+
var input = inputs[id],
|
246
|
+
fileName = api.getName(id),
|
247
|
+
iframe = createIframe(id),
|
248
|
+
form;
|
249
|
+
|
250
|
+
if (!input){
|
251
|
+
throw new Error('file with passed id was not added, or already uploaded or cancelled');
|
252
|
+
}
|
253
|
+
|
254
|
+
options.onUpload(id, this.getName(id));
|
255
|
+
|
256
|
+
form = createForm(id, iframe);
|
257
|
+
form.appendChild(input);
|
258
|
+
|
259
|
+
attachLoadEvent(iframe, function(responseFromMessage){
|
260
|
+
log('iframe loaded');
|
261
|
+
|
262
|
+
var response = responseFromMessage ? responseFromMessage : getIframeContentJson(iframe);
|
263
|
+
|
264
|
+
detachLoadEvent(id);
|
265
|
+
|
266
|
+
//we can't remove an iframe if the iframe doesn't belong to the same domain
|
267
|
+
if (!options.cors.expected) {
|
268
|
+
qq(iframe).remove();
|
269
|
+
}
|
270
|
+
|
271
|
+
if (!response.success) {
|
272
|
+
if (options.onAutoRetry(id, fileName, response)) {
|
273
|
+
return;
|
274
|
+
}
|
275
|
+
}
|
276
|
+
options.onComplete(id, fileName, response);
|
277
|
+
uploadComplete(id);
|
278
|
+
});
|
279
|
+
|
280
|
+
log('Sending upload request for ' + id);
|
281
|
+
form.submit();
|
282
|
+
qq(form).remove();
|
283
|
+
|
284
|
+
return id;
|
285
|
+
}
|
286
|
+
};
|
287
|
+
|
288
|
+
return api;
|
289
|
+
};
|