Skip to content

Commit 96559e7

Browse files
committed
Merge pull request #164 from mailru/iframe
* IFrame-fallback
2 parents b1d8466 + 1faa785 commit 96559e7

14 files changed

+376
-117
lines changed

.travis.yml

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
language: node_js
22
node_js:
3-
- 0.8
43
- 0.10
54
before_script:
65
- npm install -g grunt-cli

Gruntfile.js

+24-12
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,28 @@ module.exports = function (grunt){
3838
src: 'lib/FileAPI.core.js'
3939
},
4040

41+
connect: {
42+
server: {
43+
options: {
44+
port: 9001,
45+
base: '.'
46+
}
47+
}
48+
},
49+
4150
qunit: {
42-
options: {
43-
files: {
44-
'1px.gif': ['tests/files/1px.gif']
45-
, 'hello.txt': ['tests/files/hello.txt']
46-
, 'image.jpg': ['tests/files/image.jpg']
47-
, 'dino.png': ['tests/files/dino.png']
48-
, 'multiple': ['tests/files/1px.gif', 'tests/files/hello.txt', 'tests/files/image.jpg', 'tests/files/dino.png', 'tests/files/lebowski.json']
51+
all: {
52+
options: {
53+
files: {
54+
'1px.gif': ['tests/files/1px.gif']
55+
, 'hello.txt': ['tests/files/hello.txt']
56+
, 'image.jpg': ['tests/files/image.jpg']
57+
, 'dino.png': ['tests/files/dino.png']
58+
, 'multiple': ['tests/files/1px.gif', 'tests/files/hello.txt', 'tests/files/image.jpg', 'tests/files/dino.png', 'tests/files/lebowski.json']
59+
},
60+
urls: ['http://127.0.0.1:<%=connect.server.options.port%>/tests/index.html']
4961
}
50-
},
51-
all: ['tests/*.html']
62+
}
5263
},
5364

5465
concat: {
@@ -114,12 +125,13 @@ module.exports = function (grunt){
114125
grunt.loadNpmTasks('grunt-contrib-concat');
115126
grunt.loadNpmTasks('grunt-contrib-uglify');
116127
grunt.loadNpmTasks('grunt-contrib-watch');
128+
grunt.loadNpmTasks('grunt-contrib-connect');
117129

118130
// Load custom QUnit task, based on grunt-contrib-qunit, but support "files" option.
119131
grunt.loadTasks('./tests/grunt-task/');
120132

121133
// "npm build" runs these tasks
122-
grunt.registerTask('test', ['jshint', 'concat', 'qunit']);
123-
grunt.registerTask('build', ['version', 'concat', 'uglify', 'qunit']);
124-
grunt.registerTask('default', ['jshint', 'build']);
134+
grunt.registerTask('tests', ['jshint', 'concat', 'connect', 'qunit']);
135+
grunt.registerTask('build', ['version', 'concat', 'uglify']);
136+
grunt.registerTask('default', ['tests', 'build']);
125137
};

README.md

+12-3
Original file line numberDiff line numberDiff line change
@@ -1165,10 +1165,16 @@ Submit Query
11651165
<script>
11661166
(function (ctx, jsonp){
11671167
'use strict';
1168-
if( ctx && ctx[jsonp] ){
1169-
ctx[jsonp](200/*http.status*/, 'OK' /*http.statusText*/, "response body");
1168+
var status = {{httpStatus}}, statusText = "{{httpStatusText}}", response = "{{responseBody}}";
1169+
try {
1170+
ctx[jsonp](status, statusText, response);
1171+
} catch (e){
1172+
var data = "{\"id\":\""+jsonp+"\",\"status\":"+status+",\"statusText\":\""+statusText+"\",\"response\":\""+response.replace(/\"/g, '\\\\\"')+"\"}";
1173+
try {
1174+
ctx.postMessage(data, document.referrer);
1175+
} catch (e){}
11701176
}
1171-
})(window, '{{$request_param_callback}}');
1177+
})(window.parent, '{{request_param_callback}}');
11721178
</script>
11731179
11741180
<!-- or -->
@@ -1378,6 +1384,9 @@ Button like link.
13781384
<a name="Changelog"></a>
13791385
## Changelog
13801386
<ul>
1387+
<li>+ QUnit-tests for iframe-transport</li>
1388+
<li>+ `postMessage` for iframe-transport</li>
1389+
<li>+ `jsonp: "callback"` option</li>
13811390
<li>* resize: `imageTransform.type` rename to `imageTransform.strategy` (!!!)</li>
13821391
</ul>
13831392

README.ru.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -1147,10 +1147,16 @@ Submit Query
11471147
<script>
11481148
(function (ctx, jsonp){
11491149
'use strict';
1150-
if( ctx && ctx[jsonp] ){
1151-
ctx[jsonp](200/*http.status*/, 'OK' /*http.statusText*/, "response body");
1150+
var status = {{httpStatus}}, statusText = "{{httpStatusText}}", response = "{{responseBody}}";
1151+
try {
1152+
ctx[jsonp](status, statusText, response);
1153+
} catch (e){
1154+
var data = "{\"id\":\""+jsonp+"\",\"status\":"+status+",\"statusText\":\""+statusText+"\",\"response\":\""+response.replace(/\"/g, '\\\\\"')+"\"}";
1155+
try {
1156+
ctx.postMessage(data, document.referrer);
1157+
} catch (e){}
11521158
}
1153-
})(window, '{{$request_param_callback}}');
1159+
})(window.parent, '{{request_param_callback}}');
11541160
</script>
11551161
11561162
<!-- or -->

dist/FileAPI.html5.js

+62-22
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,8 @@
10071007

10081008
upload: function (options){
10091009
options = _extend({
1010-
prepare: api.F
1010+
jsonp: 'callback'
1011+
, prepare: api.F
10111012
, beforeupload: api.F
10121013
, upload: api.F
10131014
, fileupload: api.F
@@ -2711,31 +2712,27 @@
27112712
}
27122713

27132714
if( data.nodeName ){
2715+
var jsonp = options.jsonp;
2716+
2717+
// prepare callback in GET
2718+
url = url.replace(/([a-z]+)=(\?)/i, '$1='+uid);
2719+
27142720
// legacy
27152721
options.upload(options, _this);
27162722

27172723
xhr = document.createElement('div');
27182724
xhr.innerHTML = '<form target="'+ uid +'" action="'+ url +'" method="POST" enctype="multipart/form-data" style="position: absolute; top: -1000px; overflow: hidden; width: 1px; height: 1px;">'
27192725
+ '<iframe name="'+ uid +'" src="javascript:false;"></iframe>'
2720-
+ '<input value="'+ uid +'" name="callback" type="hidden"/>'
2726+
+ (jsonp && (options.url.indexOf('=?') == -1) ? '<input value="'+ uid +'" name="'+jsonp+'" type="hidden"/>' : '')
27212727
+ '</form>'
27222728
;
27232729

2724-
_this.xhr.abort = function (){
2725-
var transport = xhr.getElementsByTagName('iframe')[0];
2726-
if( transport ){
2727-
try {
2728-
if( transport.stop ){ transport.stop(); }
2729-
else if( transport.contentWindow.stop ){ transport.contentWindow.stop(); }
2730-
else { transport.contentWindow.document.execCommand('Stop'); }
2731-
}
2732-
catch (er) {}
2733-
}
2734-
xhr = null;
2735-
};
2730+
// get form-data & transport
2731+
var
2732+
form = xhr.getElementsByTagName('form')[0]
2733+
, transport = xhr.getElementsByTagName('iframe')[0]
2734+
;
27362735

2737-
// append form-data
2738-
var form = xhr.getElementsByTagName('form')[0];
27392736
form.appendChild(data);
27402737

27412738
api.log(form.parentNode.innerHTML);
@@ -2746,12 +2743,52 @@
27462743
// keep a reference to node-transport
27472744
_this.xhr.node = xhr;
27482745

2749-
// jsonp-callack
2750-
window[uid] = function (status, statusText, response){
2751-
_this.readyState = 4;
2752-
_this.responseText = response;
2753-
_this.end(status, statusText);
2754-
xhr = null;
2746+
var
2747+
onPostMessage = function (evt){
2748+
if( url.indexOf(evt.origin) != -1 ){
2749+
try {
2750+
var result = api.parseJSON(evt.data);
2751+
if( result.id == uid ){
2752+
complete(result.status, result.statusText, result.response);
2753+
}
2754+
} catch( err ){
2755+
complete(0, err.message);
2756+
}
2757+
}
2758+
},
2759+
2760+
// jsonp-callack
2761+
complete = window[uid] = function (status, statusText, response){
2762+
_this.readyState = 4;
2763+
_this.responseText = response;
2764+
_this.end(status, statusText);
2765+
2766+
api.event.off(window, 'message', onPostMessage);
2767+
window[uid] = xhr = transport = transport.onload = null;
2768+
}
2769+
;
2770+
2771+
_this.xhr.abort = function (){
2772+
try {
2773+
if( transport.stop ){ transport.stop(); }
2774+
else if( transport.contentWindow.stop ){ transport.contentWindow.stop(); }
2775+
else { transport.contentWindow.document.execCommand('Stop'); }
2776+
}
2777+
catch (er) {}
2778+
complete(0, "abort");
2779+
};
2780+
2781+
api.event.on(window, 'message', onPostMessage);
2782+
2783+
transport.onload = function (){
2784+
try {
2785+
var
2786+
win = transport.contentWindow
2787+
, doc = win.document
2788+
, result = win.result || api.parseJSON(doc.body.innerHTML)
2789+
;
2790+
complete(result.status, result.statusText, result.response);
2791+
} catch (e){}
27552792
};
27562793

27572794
// send
@@ -2760,6 +2797,9 @@
27602797
form = null;
27612798
}
27622799
else {
2800+
// Clean url
2801+
url = url.replace(/([a-z]+)=(\?)&?/i, '');
2802+
27632803
// html5
27642804
if (this.xhr && this.xhr.aborted) {
27652805
api.log("Error: already aborted");

dist/FileAPI.html5.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/FileAPI.js

+62-22
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,8 @@
10071007

10081008
upload: function (options){
10091009
options = _extend({
1010-
prepare: api.F
1010+
jsonp: 'callback'
1011+
, prepare: api.F
10111012
, beforeupload: api.F
10121013
, upload: api.F
10131014
, fileupload: api.F
@@ -2711,31 +2712,27 @@
27112712
}
27122713

27132714
if( data.nodeName ){
2715+
var jsonp = options.jsonp;
2716+
2717+
// prepare callback in GET
2718+
url = url.replace(/([a-z]+)=(\?)/i, '$1='+uid);
2719+
27142720
// legacy
27152721
options.upload(options, _this);
27162722

27172723
xhr = document.createElement('div');
27182724
xhr.innerHTML = '<form target="'+ uid +'" action="'+ url +'" method="POST" enctype="multipart/form-data" style="position: absolute; top: -1000px; overflow: hidden; width: 1px; height: 1px;">'
27192725
+ '<iframe name="'+ uid +'" src="javascript:false;"></iframe>'
2720-
+ '<input value="'+ uid +'" name="callback" type="hidden"/>'
2726+
+ (jsonp && (options.url.indexOf('=?') == -1) ? '<input value="'+ uid +'" name="'+jsonp+'" type="hidden"/>' : '')
27212727
+ '</form>'
27222728
;
27232729

2724-
_this.xhr.abort = function (){
2725-
var transport = xhr.getElementsByTagName('iframe')[0];
2726-
if( transport ){
2727-
try {
2728-
if( transport.stop ){ transport.stop(); }
2729-
else if( transport.contentWindow.stop ){ transport.contentWindow.stop(); }
2730-
else { transport.contentWindow.document.execCommand('Stop'); }
2731-
}
2732-
catch (er) {}
2733-
}
2734-
xhr = null;
2735-
};
2730+
// get form-data & transport
2731+
var
2732+
form = xhr.getElementsByTagName('form')[0]
2733+
, transport = xhr.getElementsByTagName('iframe')[0]
2734+
;
27362735

2737-
// append form-data
2738-
var form = xhr.getElementsByTagName('form')[0];
27392736
form.appendChild(data);
27402737

27412738
api.log(form.parentNode.innerHTML);
@@ -2746,12 +2743,52 @@
27462743
// keep a reference to node-transport
27472744
_this.xhr.node = xhr;
27482745

2749-
// jsonp-callack
2750-
window[uid] = function (status, statusText, response){
2751-
_this.readyState = 4;
2752-
_this.responseText = response;
2753-
_this.end(status, statusText);
2754-
xhr = null;
2746+
var
2747+
onPostMessage = function (evt){
2748+
if( url.indexOf(evt.origin) != -1 ){
2749+
try {
2750+
var result = api.parseJSON(evt.data);
2751+
if( result.id == uid ){
2752+
complete(result.status, result.statusText, result.response);
2753+
}
2754+
} catch( err ){
2755+
complete(0, err.message);
2756+
}
2757+
}
2758+
},
2759+
2760+
// jsonp-callack
2761+
complete = window[uid] = function (status, statusText, response){
2762+
_this.readyState = 4;
2763+
_this.responseText = response;
2764+
_this.end(status, statusText);
2765+
2766+
api.event.off(window, 'message', onPostMessage);
2767+
window[uid] = xhr = transport = transport.onload = null;
2768+
}
2769+
;
2770+
2771+
_this.xhr.abort = function (){
2772+
try {
2773+
if( transport.stop ){ transport.stop(); }
2774+
else if( transport.contentWindow.stop ){ transport.contentWindow.stop(); }
2775+
else { transport.contentWindow.document.execCommand('Stop'); }
2776+
}
2777+
catch (er) {}
2778+
complete(0, "abort");
2779+
};
2780+
2781+
api.event.on(window, 'message', onPostMessage);
2782+
2783+
transport.onload = function (){
2784+
try {
2785+
var
2786+
win = transport.contentWindow
2787+
, doc = win.document
2788+
, result = win.result || api.parseJSON(doc.body.innerHTML)
2789+
;
2790+
complete(result.status, result.statusText, result.response);
2791+
} catch (e){}
27552792
};
27562793

27572794
// send
@@ -2760,6 +2797,9 @@
27602797
form = null;
27612798
}
27622799
else {
2800+
// Clean url
2801+
url = url.replace(/([a-z]+)=(\?)&?/i, '');
2802+
27632803
// html5
27642804
if (this.xhr && this.xhr.aborted) {
27652805
api.log("Error: already aborted");

dist/FileAPI.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)