/* classe API */ function API(target){ this.target = target; } API.prototype = { xhr: [], // tableau d'objets pour les requêtes ajax buffer: null, // Contiendra le buffer pour debugger si erreur de parsage error: { // error constants '-1': 'Invalid target format: "METHOD module/method"', '-2': 'XHR error', '-3': 'Invalid JSON response', }, /* transaction avec le serveur (http://{host}/api/) * * @param pTarget URI cible, format "HTTP_METHOD uri/uri/uri" * @param pArgs Le tableu d'arguments passé en POST (attribut<->postfield) à http://{host}/api/ * @param pHandler Fonction qui s'éxécutera lors de la réponse (1 argument -> réponse) * @param pToken Optionnel, token d'auth pour l'api * *************************************************************************************************** * * @usecase * 1. api.call( * 2. "PUT newspaper/article/4" * 2. { content: "New article content" }, * 3. function(resp){ * 4. alert(resp.error); * 5. } * 6. ); * */ call: function(pTarget, pArgs, pHandler, pToken=null){ /* (1) Check @pHandler (for dispatching errors) ---------------------------------------------------------*/ /* (1) Check if is a Function */ if( !(pHandler instanceof Function) ) throw new Error("3rd argument must be a function, but is of type '"+typeof(pHandler)+"' !"); /* (2) Check @pTarget ---------------------------------------------------------*/ /* (1) Check format */ if( !/^([A-Z]+) (.+)/i.test(pTarget) ){ pHandler({ error: -1, ErrorDescription: this.error['-1'] }); return false; } /* (2) Store locally data */ var lHttpMethod = RegExp.$1; var lUri = RegExp.$2; /* (3) Manage xhr stack ---------------------------------------------------------*/ /* (1) Pop ended requests */ for( var i = 0, il = this.xhr.length ; i < il ; i++ ) if( this.xhr[i].readyState == 4 ) // if over this.xhr.splice(i, 1); /* (4) Create XHR request ---------------------------------------------------------*/ /* (1) Push a new entry -> fetch its index */ this.xhr.push(null); i = this.xhr.length-1; /* (2) Create XHR object */ this.xhr[i] = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHttpRequest'); /* (5) Bind response event ---------------------------------------------------------*/ var self = this; // to access the buffer this.xhr[i].onreadystatechange = function(){ /* (1) If request over */ if( this.readyState == 4 ){ /* (2) Update buffer (for debug) */ self.buffer = this.responseText; /* (3) If request success */ if( [0, 200, 417].indexOf(this.status) > -1 ){ /* (3.1) Create default response (if JSON error) */ var response = {error:-3, ErrorDescription: self.error['-3']}; /* (3.2) Try to parse JSON */ try{ response = JSON.parse(this.responseText); }catch(e){} /* (3.3) Launch @pHandler with response */ pHandler(response); /* (4) If request error */ }else pHandler({ error:-2, ErrorDescription: self.error['-2'] }); } }.bind(this.xhr[i]); /* (6) Create form data ---------------------------------------------------------*/ /* (1) Create virtual form */ var form = new FormData(); /* (2) Add attributes */ for( var key in pArgs ){ // {2.1} If a file -> send as it // if( pArgs[key] instanceof File ) form.append(key, pArgs[key]); // {2.2} Else -> JSON stringify // else form.append(key, JSON.stringify(pArgs[key])); } /* (7) Finish & send request ---------------------------------------------------------*/ /* (1) Open the XHR */ this.xhr[i].open(lHttpMethod, this.target+lUri, true); /* (2) Manage optional token */ if( pToken != null ) this.xhr[i].setRequestHeader('Authorization', 'Digest '+pToken); /* (3) Custom header to notify we're using Ajax */ this.xhr[i].setRequestHeader('X-Requested-With', 'XMLHttpRequest'); /* (4) Make the call */ this.xhr[i].send( form ); } };