Subversion Repositories wimsdev

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.         DynAPI Distribution
  3.         IOElement Class
  4.  
  5.         The DynAPI Distribution is distributed under the terms of the GNU LGPL license.
  6.  
  7.         requires: dynapi.api.DynLayer
  8.  
  9.         // pages loaded must include this code:
  10.         <script>
  11.                 if (parent.dynapi) parent.IOElement.notify(this);
  12.         </script>
  13. */
  14.  
  15. function IOElement(hiddenThreads,useXFrames) {
  16.         this.DynLayer = DynLayer;
  17.         this.DynLayer();
  18.        
  19.         this._elmID = this.id+'elm';
  20.         this._requests = {};    // [url,data,fn,method,elmThread,timer,cargo]
  21.         this._cargoID='';
  22.         this._requestList = [];
  23.         this._requestIndex = -1;
  24.         this._retryID=null;
  25.         this._transactions = {};
  26.  
  27.         this._singleThread=false;      
  28.         this._elmBusy=[];
  29.         this._elmThread=null;
  30.         this._maxThreads=(hiddenThreads>=1 && hiddenThreads<=8)? hiddenThreads : 1;
  31.         this._hidden = (hiddenThreads)? true : false;
  32.  
  33.         this.isSync=false;
  34.         this.failTime = 50000;
  35.        
  36.         // create XFrame window
  37.         if(useXFrames && dynapi.ua.ns4) {
  38.                 this._winXFrames=window.open("about:blank",null,'left=3000,top=3000,width=100,height=100,scrollbars=no,status=no,toolbar=no');
  39.                 this._winXFrames.blur(); // hide the new window
  40.                 var wxf=this._winXFrames;
  41.                 dynapi.onUnload(function() { // tidy up
  42.                         if(wxf.open && !wxf.closed) wxf.close();
  43.                 });
  44.         }
  45.  
  46.         if (this._hidden) {
  47.                 var o = this;
  48.                 o.setLocation(1,1);// Strange! ns4 requires that the x,y be set in order to load the java applet inside the layer
  49.                 o.setVisible(false);
  50.                 dynapi.document.addChild(o);
  51.         }
  52.  
  53.         this.onPreCreate(IOElement.fnPrecreate);
  54.         this.onCreate(IOElement.fnCreate);
  55. };
  56.  
  57. IOElement.fnPrecreate = function() {
  58.         var t,r=['*'],html=[];
  59.         if (this._hidden) {
  60.                 if (this._winXFrames) html = ['<frame src="about:blank" name="',this._elmID,'" scrolling="none">'];
  61.                 else if (dynapi.ua.ns4) html = ['<ilayer name="',this._elmID,'" visibility="hide" width=0 height=0></ilayer>'];
  62.                 else html = ['<iframe name="',this._elmID,'" style="width:0px; height:0px; visibility:hidden"></iframe>'];
  63.                 t=html.join('')
  64.                 this._elmThread=this._elmID;
  65.                 this._elmBusy[this._elmID]=false;
  66.                 for(var i=1;i<this._maxThreads;i++){ // setup additional threads
  67.                         r[i]='*';// for XFrames
  68.                         html[1]=this._elmID+'x'+i;
  69.                         t+=html.join('');
  70.                         this._elmBusy[this._elmID+'x'+i]=false; // flag as not busy
  71.                 }
  72.                 // java-sync frame
  73.                 html[1]=this._elmID+'Sync';
  74.                 t+=html.join('');
  75.         }else{
  76.                 if (this._winXFrames) t = '<frame src="about:blank" name="',this._elmID,'" scrolling="none">';
  77.                 else if (dynapi.ua.ns4) t = '<ilayer width='+this.w+' height='+this.h+' name="'+this._elmID+'" visibility="inherit"></ilayer>';
  78.                 else t = '<iframe name="'+this._elmID+'" width='+this.w+' height='+this.h+' scrolling="no" frameborder="no" marginwidth=0 marginheight=0 style="overflow:hidden;"></iframe>';
  79.                 this._elmThread=this._elmID; this._elmBusy[this._elmID]=false;
  80.         }
  81.  
  82.         if (!this._winXFrames) this.html=t;
  83.         else{
  84.                 var src='<html><head><title>DynAPI XFrame</title></head>\n'
  85.                 +'<frameset rows="'+r.join(',')+',0">\n'+t
  86.                 +'</frameset></html>\n'
  87.                 this._winXFrames.document.open();
  88.                 this._winXFrames.document.write(src);
  89.                 this._winXFrames.document.close();
  90.                 this._winXFrames.top.dynapi=dynapi;
  91.                 this._winXFrames.top.IOElement=IOElement;
  92.         }
  93. };
  94. IOElement.fnCreate = function() {
  95.         if (this._SyncFn) window.setTimeout(this+'._initSync()',100);
  96.         if (this.getScope()) {
  97.                 if (this._requestList.length>0) {
  98.                         this._setRequestTimeout(100);                          
  99.                 }
  100.         }
  101. };
  102.  
  103. var p = dynapi.setPrototype('IOElement','DynLayer');
  104. p.getVariable = function(name) {
  105.         var v=this.getScope()[name];
  106.         if (IOElement.SODA) v=IOElement.ws_SODA2Var(v);
  107.         return v;
  108. };
  109. p.getScope = function(thread) {
  110.         var scope;
  111.         if (!thread) thread=this._elmThread;
  112.         if (this._winXFrames && this._winXFrames.top) scope = this._winXFrames.top.frames[thread];     
  113.         else if (dynapi.ua.ns4) scope = this.doc.layers[thread];
  114.         else scope = window.frames[thread];
  115.         if (!scope) return alert('IOElement Error: no load element');
  116.         else return scope;
  117. };
  118. p.getCargoID=function(){return this._cargoID}
  119. p.getCargo=function(dontRemove){
  120.         if(!this._cargoID) return null;
  121.         var c=this._requests[this._cargoID][6];
  122.         if(!dontRemove) {
  123.                 // normall cargo are removed from storage
  124.                 this._requests[this._cargoID][6]=null;
  125.         }
  126.         return c;
  127. };
  128. p.isBusy = function(){
  129.         for (var i in this._elmBusy){
  130.                 if (this._elmBusy[i]==false) return false;
  131.         };return true
  132. };
  133. p.cancel= function(id){
  134.         id=(id)? id:this._retryID;
  135.         var req=this._requests[id];
  136.         if(req){
  137.                 this._elmBusy[req[4]]=false;
  138.                 delete this._requests[id];
  139.                 this._clearScope();
  140.                 return true;
  141.         }
  142. };
  143. p.cancelAll=function(){
  144.         this._requests={};
  145.         for (var i in this._elmBusy){
  146.                 this.elmThread=i;
  147.                 this._clearScope();
  148.         }
  149. };
  150. p.retry=function(id){
  151.         id=this._retryID=((id)? id:this._retryID);
  152.         var req=this._requests[id];
  153.         if(req) {
  154.                 this._setRequestTimeout(50,id);
  155.                 return true;
  156.         }
  157. };
  158. p.setTimeout = function(ms){
  159.         if(!isNaN(ms))this.failTime=ms;
  160. }
  161. p.useSingleThread = function(b){
  162.         this._singleThread=b;
  163. };
  164. p.get = function(url,data,fn,cargo) {
  165.         if(fn==false && this.isSync) return this._syncRequest(url,data,'get');
  166.         else return this._asyncRequest(url,data,fn,'get',cargo);
  167. };
  168. p.post = function(url,data,fn,cargo) {
  169.         if(fn==false && this.isSync) return this._syncRequest(url,data,'post');
  170.         return this._asyncRequest(url,data,fn,'post',cargo);
  171. };
  172. p.upload=function(url,form,fn,cargo){   // file upload
  173.         return this._asyncRequest(url,form,fn,'upload',cargo);
  174. };
  175. p._asyncRequest = function(url,data,fn,method,cargo) {
  176.         var i,l,src;
  177.         var id = this._getRandomID(); // create random load ID to ensure no caching    
  178.         dynapi.debug.print("IOElement "+method+" request");
  179.         if (typeof(url)=="string") this._requests[id] = [url,data,fn,method,null,null,cargo];
  180.         else if (method=="get") {
  181.                 for (i=0;i<url.length;i++) {  // support loading several files, attach handler to last file
  182.                         src = url[i];
  183.                         if (i<url.length-1) this._requests[id] = [src,null,null,method,null,null,cargo];
  184.                         else this._requests[id] = [src,data,fn,method,null,null];
  185.                 }
  186.         }
  187.  
  188.         l=this._requestList.length
  189.         this._requestList[l] = id;
  190.         if (this._created) this._setRequestTimeout(20);
  191.         return id
  192. };
  193. p._doRequest = function(id) {
  194.         if (this.isBusy()) {this._setRequestTimeout(200,id);return;}
  195.         else {
  196.                 if (this._requestIndex<this._requestList.length-1 || id) {
  197.                         if(!id){ // <- direct request - used by the retry() method
  198.                                 this._requestIndex++;
  199.                                 id = this._requestList[this._requestIndex];
  200.                         }
  201.                         var i,t,cont=false;
  202.                         var r = this._requests[id];
  203.                         if(r) {
  204.                                 var url = r[0];
  205.                                 var data = r[1];
  206.                                 var fn = r[2];
  207.                                 var method = r[3];
  208.                                 var elm = this._getFreeElm();
  209.                                 cont=(elm)? true:false;
  210.                         }
  211.                         if(!cont) {
  212.                                 this._setRequestTimeout(200,id);
  213.                                 return;
  214.                         }
  215.                        
  216.                         r[4]=this._elmThread;
  217.                         if (url.indexOf('http')!=0) {
  218.                                 if (url.substr(0,1)=='/') url = 'http://'+dynapi.frame.document.domain+url;
  219.                                 else url = dynapi.documentPath+url;
  220.                         }
  221.  
  222.                         url += (url.indexOf('?')==-1)? '?' : '&';
  223.                         url += 'IORequestID='+id+'&IOElementID='+this.id+'&IOMethod='+method;
  224.  
  225.                         t=this+'._notify("'+id+'","'+url+'",false)';
  226.                        
  227.                         // add eval code to transaction records
  228.                         if(!dynapi.ua.ns4) this._transactions[id]=[0,t];
  229.                        
  230.                         r[5] = window.setTimeout(t,this.failTime);
  231.  
  232.                         // reset document - this will help to prevent cross-domain access errors
  233.                         if (dynapi.ua.def) elm.document.location.href = 'about:blank';
  234.  
  235.                         if (method=="get" || (dynapi.ua.ns4 && !this._winXFrames)) {
  236.                                 if (data) {
  237.                                         for (i in data) {
  238.                                                 if(i) url += '&'+i+'='+escape(data[i]);
  239.                                         }
  240.                                 }
  241.                                 if (this._winXFrames) elm.location.href=url;
  242.                                 else if (dynapi.ua.ns4) elm.src = url;
  243.                                 else elm.document.location.href = url;
  244.                         }else if(method=='upload') {
  245.                                 var f=data;
  246.                                 f.action=url;
  247.                                 f.encoding='multipart/form-data';
  248.                                 f.method='post';
  249.                                 f.target=this._elmThread;
  250.                                 f.submit();
  251.                         }else {
  252.                                 var str = '<html><body><form name="ioDataForm" action="'+url+'" method="post" enctype="application/x-www-form-urlencoded">';
  253.                                 if (data) {
  254.                                         for (i in data) {
  255.                                                 if(i) str += '<input name="'+i+'" type="hidden">';
  256.                                         }
  257.                                 }
  258.                                 str += '</form></body></html>';
  259.  
  260.                                 elm.document.open();
  261.                                 elm.document.write(str);
  262.                                 elm.document.close();
  263.  
  264.                                 var f = elm.document.forms['ioDataForm'];
  265.                                 if (!f) return alert("IOElement Error: no form element found");
  266.                                 if (f && data) {
  267.                                         for (i in data) {
  268.                                                 if(i) f[i].value = data[i];
  269.                                         }
  270.                                 }
  271.                                 f.submit();
  272.                         }
  273.                        
  274.                         // begin transaction - data sent but awaiting reply
  275.                         // to-do work on a way to detech if caller is in the same domain as
  276.                         if(!dynapi.ua.ns4) {
  277.                                 elm.document._tranState="begin";
  278.                                 this._monitorTransactions();
  279.                         }                      
  280.                         this.invokeEvent("request");
  281.                 }
  282.         }
  283. };
  284. p._clearScope=function(){
  285.         var doc=this.getScope().document
  286.         if(doc){doc.open();doc.write('');doc.close()}
  287. };
  288. p._getFreeElm= function(){
  289.         for (var i in this._elmBusy){
  290.                 if (this._elmBusy[i]==false){
  291.                         this._elmThread=i;this._elmBusy[i]=true;
  292.                         return this.getScope();
  293.                 }else if(this._singleThread) break;
  294.         }
  295. };
  296. p._getRandomID = function(){
  297.         var id = Math.random()+'';  
  298.         return 'io'+id.substring(2);
  299. };
  300. p._monitorTransactions = function(){
  301.         var c,r,tr,id,elm;
  302.         for (id in this._transactions){
  303.                 r=this._requests[id];
  304.                 tr=this._transactions[id];
  305.                 if(r && this._elmBusy[r[4]]) {
  306.                         elm=this.getScope(r[4]);
  307.                         if(elm && elm.document && !elm.document._tranState){
  308.                                 // document completed without proper response from server
  309.                                 tr[0]+=1; // counter.
  310.                                 if(tr[0]>=3){
  311.                                         //three strikes and you're out!
  312.                                         eval(tr[1]);
  313.                                 }
  314.                         }
  315.                 }
  316.         }
  317.         if(id) window.setTimeout(this+'._monitorTransactions()',1000);
  318. };
  319. p._notify = function(id, url, success) {
  320.         var fn,req=this._requests[id]; if(!req)return;
  321.         var s = (success!=null)? success : true;
  322.         // delete transaction record
  323.         delete this._transactions[id];
  324.         if (!this._elmBusy[req[4]] && success) {
  325.                 dynapi.debug.print('IOElement Error: '+id+' '+this._elmID+' '+url);
  326.                 return;
  327.         }
  328.         clearTimeout(req[5]);
  329.         this._elmThread=req[4];
  330.         fn = req[2]; // callback function
  331.         if(!s) this._retryID=id; else this._retryID='';
  332.         this._cargoID=id;
  333.         if (fn) {
  334.                 var r,e = new DynEvent("load",this);
  335.                 if(typeof(fn)=='function') r=fn(e, s);
  336.                 else r=eval(fn);
  337.                 // cancels server response and preserve request object
  338.                 if(r==false) {
  339.                         s=false;
  340.                         this._retryID=id
  341.                 }
  342.         }else{
  343.                 this.invokeEvent("response",null,s)
  344.         }
  345.         this._cargoID='';
  346.         if(s && id!=this._retryID) delete this._requests[id];
  347.         else if(this._hidden) this._clearScope();
  348.         this._elmBusy[req[4]] = false;
  349.         // release document - prevent incomplete progressbar in ie
  350.         if(dynapi.ua.ie) location.href = "javascript:void (document.close())";
  351.         this._doRequest();
  352. };
  353. p._setRequestTimeout=function(interval,id){
  354.         var evl=this+'._doRequest('+((id)? "'"+id+"'":'')+')'; 
  355.         return window.setTimeout(evl,interval);
  356. };
  357. // Helper Methods -------------------------
  358. IOElement.getSharedIO=function(useXFrames){ // Returns a Shared instance of the IOElement object
  359.         if(!IOElement.ShareIO) IOElement.ShareIO=new IOElement(1,useXFrames);
  360.         return IOElement.ShareIO;
  361. };
  362. IOElement.notify = function(elm, fn, success) {  // ds: added success parameter to nicely relay server generated error messages
  363.         if (elm) {
  364.                 var url, id;
  365.                 if (dynapi.ua.ns4 && elm.src) url = elm.src;
  366.                 else if (dynapi.ua.ns4 && elm.location) url = elm.location.href;
  367.                 else url = elm.document.location.href;
  368.                 if (url) {
  369.                         elm.args = dynapi.functions.getURLArguments(url);
  370.                         var id = elm.args["IORequestID"];
  371.                         var obj = DynObject.all[elm.args["IOElementID"]];
  372.                         if (obj!=null && id!=null) {
  373.                                  // transaction completed - server has respond sucessfully
  374.                                 elm.document._tranState="complete";
  375.                                 elm.onload = function() {
  376.                                         if (fn) fn(obj); // send obj fn - rmo
  377.                                         obj._notify(id,url, success);  // ds: success
  378.                                 };
  379.                                 return obj;
  380.                         }
  381.                         else {
  382.                                 return false;
  383.                         }
  384.                 }
  385.         }
  386.         return null;
  387. };
  388. IOElement.URLEncode = function (d){
  389.         d=d.replace(/\s/g,'+').replace(/\%/g,'%25').replace(/\=/g,'%3D');
  390.         d=d.replace(/\&/g,'%26').replace(/\n/g,'%0A').replace(/\r/g,'%0D');
  391.         d=d.replace(/\#/g,'%23').replace(/\\/g,'%5C');
  392.         return d;
  393. };
  394.