Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

XHR Level 2 responseType of arrayBuffer and Blob #2433

Open
wants to merge 3 commits into from

5 participants

@leegee

This pull request in response to the below mails on the MT users' list.

The change is that a new option has been added to Requestjs, 'responseType.' Valid values are not checked, but passed directly to the xhr object just after it has been open()ed.

A callback could not be used to do this, as the xhr object is never exposed in an existing callback, and exposing it seemed contrary to the spirit of the code. Furthermore, this is base functionality of XHR, at level two, and is required for requests of HTML5 audio data via the Web Audio API (at least), so without this support, MooTools cannot be used with HTML5 Web Audio.

Please let me know what you think.

On 08/10/2012 05:09, Barry van Oudtshoorn wrote:

This sounds like it'd be something that could reasonably be exposed as an option on the Request class, so my recommendation would be to alter that class and send a pull request. No guarantee that it'll be accepted, of course, but this is certainly the way that I'd want to interact with this in MooTools. It's a pretty fundamental operation on XHR, to be honest, so I think it's worthwhile.

On 07/10/12 17:22, Lee Goddard wrote:

I'm making XHR requets with reponseType set to 'arraybuffer', so that I can receive binary data to pass to a Web Audio API audio context's decodeAudioData() method.

As far as I know, this cannot be done with MooTools as it stands, because although I could sub-class Request and adjust the onStateChange() and success(), access is required to the private XHR so that the responseType can be set after the requested is open()ed.

Over-riding the send() method seems like a bad idea, as I'd have to keep it updated with any change made to the core.

The only solution I can see is to expose the currently-private xhr object, but I guess it is private for a reason.

Does anyone have any suggestions, please?

TIA
Lee

@arian
Owner

:+1: would be good to bring more XHR 2 features in.

@DimitarChristoff
Collaborator

seems cool. i like it. :+1: still, you can easily create your own Request subclass with this func in. it seems like too much of an edgecase

@leegee

Dimitar,

Thing is that MT is falling behind in the world of XHR, and if I start creating my own custom Request sub-classes, I lose the benefit of using a globally-distributed library. I already have four projects with my own custom Request sub-class, and I'm not happy explaining to people why that is necessary.

This patch may not be good enough, but XHR Level 2 must be supported in MooTools if the library is survive in the world of HTML5, and unless Request is to be rewritten, I thought the approach I took did the least harm.

@cpojer
Owner

I like this a lot. @leegee would you mind amending your commit with proper MooTools coding standards? (There are too many spaces in the documentation code example and an else block belongs on the same line with the closing parenthesis of the previous block and the opening parenthesis of the else block).

Also, it seems to my like you could shorten the code block around defining the response. If you don't know what to do feel free to join #mootools on IRC and ping me :)

@leegee

Will do, thank you.

Source/Request/Request.js
@@ -74,11 +74,21 @@ var Request = this.Request = new Class({
if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
clearTimeout(this.timer);
- this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
- if (this.options.isSuccess.call(this, this.status))
- this.success(this.response.text, this.response.xml);
- else
- this.failure();
+ if (this.options.responseType
+ && (this.options.responseType == 'arraybuffer' || this.options.responseType == 'blob') ){
@arian Owner
arian added a note

Just put it on one line. Also there is an erroneous space at ) ){

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Source/Request/Request.js
@@ -74,11 +74,21 @@ var Request = this.Request = new Class({
if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
clearTimeout(this.timer);
- this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
- if (this.options.isSuccess.call(this, this.status))
- this.success(this.response.text, this.response.xml);
- else
- this.failure();
+ if (this.options.responseType
+ && (this.options.responseType == 'arraybuffer' || this.options.responseType == 'blob') ){
+ this.response = {};
+ this.response[this.options.responseType] = this.xhr.response || '';
+ if (this.options.isSuccess.call(this, this.status))
@arian Owner
arian added a note

Add curly brackets around ifs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Source/Request/Request.js
((4 lines not shown))
- this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
- if (this.options.isSuccess.call(this, this.status))
- this.success(this.response.text, this.response.xml);
- else
- this.failure();
+ if (this.options.responseType
+ && (this.options.responseType == 'arraybuffer' || this.options.responseType == 'blob') ){
+ this.response = {};
+ this.response[this.options.responseType] = this.xhr.response || '';
+ if (this.options.isSuccess.call(this, this.status))
+ this.success(this.response[this.options.responseType]);
+ else
+ this.failure();
+ } else {
+ this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
+ if (this.options.isSuccess.call(this, this.status))
@arian Owner
arian added a note

idem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Docs/Request/Request.md
((5 lines not shown))
console.log(parseInt(loaded / total * 100, 10));
}
});
myRequest.send();
+ var mySound = new Request({
+ method: 'get',
@arian Owner
arian added a note

remove the extra spaces between : and 'get'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@arian
Owner

I added some comments, sorry for the nitpicking, but if you fix that we can pull it :smile:

@leegee
@ibolmo ibolmo modified the milestone: 1.6, 1.5
@ibolmo ibolmo added the enhancement label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 8, 2012
  1. @leegee
Commits on Jan 4, 2013
  1. @leegee

    Whitespace formatting

    leegee authored
Commits on Jan 18, 2013
  1. @leegee
This page is out of date. Refresh to see the latest.
Showing with 32 additions and 7 deletions.
  1. +14 −1 Docs/Request/Request.md
  2. +18 −6 Source/Request/Request.js
View
15 Docs/Request/Request.md
@@ -30,6 +30,7 @@ An XMLHttpRequest Wrapper.
* timeout - (*integer*: defaults to 0) In conjunction with `onTimeout` event, it determines the amount of milliseconds before considering a connection timed out. (It's suggested to not use timeout with big files and only when knowing what's expected.)
* headers - (*object*) An object to use in order to set the request headers.
* urlEncoded - (*boolean*: defaults to *true*) If set to true, the content-type header is set to www-form-urlencoded + encoding
+* responseType - (*string*: defaults to *null*, may be *arrayBuffer* or *blob*) Provides access to the XHR Level 2 *responseType*, allowing requests of binary data.
* encoding - (*string*: defaults to 'utf-8') The encoding to be set in the request header.
* noCache - (*boolean*; defaults to *false*) If *true*, appends a unique *noCache* value to the request to prevent caching. (IE has a bad habit of caching ajax request values. Including this script and setting the *noCache* value to true will prevent it from caching. The server should ignore the *noCache* value.)
* isSuccess - (*function*) Overrides the built-in isSuccess function.
@@ -80,17 +81,29 @@ Fired when the Request is making progresses in the download or upload. (This is
url: 'image.jpg',
onProgress: function(event, xhr){
var loaded = event.loaded, total = event.total;
-
console.log(parseInt(loaded / total * 100, 10));
}
});
myRequest.send();
+ var mySound = new Request({
+ method: 'get',
+ url: 'squarepusher.wav',
+ responseType: 'arraybuffer',
+ onSuccess: function(res){
+ myAudioContext.decodeAudioData(res, function(buffer){
+ if (buffer) myAudioBuffer = buffer;
+ });
+ }
+ }).send();
+
### See Also:
- [MDC: nsIDOMProgressEvent](https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIDOMProgressEvent)
+ - [W3C: XHR Level 2](http://www.w3.org/TR/XMLHttpRequest/)
+
#### complete
Fired when the Request is completed.
View
24 Source/Request/Request.js
@@ -74,11 +74,22 @@ var Request = this.Request = new Class({
if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
clearTimeout(this.timer);
- this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
- if (this.options.isSuccess.call(this, this.status))
- this.success(this.response.text, this.response.xml);
- else
- this.failure();
+ if (this.options.responseType && (this.options.responseType == 'arraybuffer' || this.options.responseType == 'blob')){
+ this.response = {};
+ this.response[this.options.responseType] = this.xhr.response || '';
+ if (this.options.isSuccess.call(this, this.status)){
+ this.success(this.response[this.options.responseType]);
+ } else {
+ this.failure();
+ }
+ } else {
+ this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
+ if (this.options.isSuccess.call(this, this.status)){
+ this.success(this.response.text, this.response.xml);
+ } else {
+ this.failure();
+ }
+ }
},
isSuccess: function(){
@@ -91,6 +102,7 @@ var Request = this.Request = new Class({
},
processScripts: function(text){
+ if (typeof text != 'string') return text;
if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return Browser.exec(text);
return text.stripScripts(this.options.evalScripts);
},
@@ -198,7 +210,7 @@ var Request = this.Request = new Class({
xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password);
if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true;
-
+ if (this.options.responseType) xhr.responseType = this.options.responseType;
xhr.onreadystatechange = this.onStateChange.bind(this);
Object.each(this.headers, function(value, key){
Something went wrong with that request. Please try again.