fix A/R report
[freeside.git] / httemplate / elements / jsrsClient.js
1 //
2 //  jsrsClient.js - javascript remote scripting client include
3 //  
4 //  Author:  Brent Ashley [jsrs@megahuge.com]
5 //
6 //  make asynchronous remote calls to server without client page refresh
7 //
8 //  see license.txt for copyright and license information
9
10 /*
11 see history.txt for full history
12 2.0  26 Jul 2001 - added POST capability for IE/MOZ
13 2.2  10 Aug 2003 - added Opera support
14 2.3(beta)  10 Oct 2003 - added Konqueror support - **needs more testing**
15 */
16
17 // callback pool needs global scope
18 var jsrsContextPoolSize = 0;
19 var jsrsContextMaxPool = 10;
20 var jsrsContextPool = new Array();
21 var jsrsBrowser = jsrsBrowserSniff();
22 var jsrsPOST = true;
23 var containerName;
24
25 // constructor for context object
26 function jsrsContextObj( contextID ){
27   
28   // properties
29   this.id = contextID;
30   this.busy = true;
31   this.callback = null;
32   this.container = contextCreateContainer( contextID );
33   
34   // methods
35   this.GET = contextGET;
36   this.POST = contextPOST;
37   this.getPayload = contextGetPayload;
38   this.setVisibility = contextSetVisibility;
39 }
40
41 //  method functions are not privately scoped 
42 //  because Netscape's debugger chokes on private functions
43 function contextCreateContainer( containerName ){
44   // creates hidden container to receive server data 
45   var container;
46   switch( jsrsBrowser ) {
47     case 'NS':
48       container = new Layer(100);
49       container.name = containerName;
50       container.visibility = 'hidden';
51       container.clip.width = 100;
52       container.clip.height = 100;
53       break;
54     
55     case 'IE':
56       document.body.insertAdjacentHTML( "afterBegin", '<span id="SPAN' + containerName + '"></span>' );
57       var span = document.all( "SPAN" + containerName );
58       var html = '<iframe name="' + containerName + '" src=""></iframe>';
59       span.innerHTML = html;
60       span.style.display = 'none';
61       container = window.frames[ containerName ];
62       break;
63       
64     case 'MOZ':  
65       var span = document.createElement('SPAN');
66       span.id = "SPAN" + containerName;
67       document.body.appendChild( span );
68       var iframe = document.createElement('IFRAME');
69       iframe.name = containerName;
70       iframe.id = containerName;
71       span.appendChild( iframe );
72       container = iframe;
73       break;
74
75     case 'OPR':  
76       var span = document.createElement('SPAN');
77       span.id = "SPAN" + containerName;
78       document.body.appendChild( span );
79       var iframe = document.createElement('IFRAME');
80       iframe.name = containerName;
81       iframe.id = containerName;
82       span.appendChild( iframe );
83       container = iframe;
84       break;
85
86     case 'KONQ':  
87       var span = document.createElement('SPAN');
88       span.id = "SPAN" + containerName;
89       document.body.appendChild( span );
90       var iframe = document.createElement('IFRAME');
91       iframe.name = containerName;
92       iframe.id = containerName;
93       span.appendChild( iframe );
94       container = iframe;
95
96       // Needs to be hidden for Konqueror, otherwise it'll appear on the page
97       span.style.display = none;
98       iframe.style.display = none;
99       iframe.style.visibility = hidden;
100       iframe.height = 0;
101       iframe.width = 0;
102
103       break;
104   }
105   return container;
106 }
107
108 function contextPOST( rsPage, func, parms ){
109
110   var d = new Date();
111   var unique = d.getTime() + '' + Math.floor(1000 * Math.random());
112   var doc = (jsrsBrowser == "IE" ) ? this.container.document : this.container.contentDocument;
113   doc.open();
114   doc.write('<html><body>');
115   doc.write('<form name="jsrsForm" method="post" target="" ');
116   doc.write(' action="' + rsPage + '?U=' + unique + '">');
117   doc.write('<input type="hidden" name="C" value="' + this.id + '">');
118
119   // func and parms are optional
120   if (func != null){
121   doc.write('<input type="hidden" name="F" value="' + func + '">');
122
123     if (parms != null){
124       if (typeof(parms) == "string"){
125         // single parameter
126         doc.write( '<input type="hidden" name="P0" '
127                  + 'value="[' + jsrsEscapeQQ(parms) + ']">');
128       } else {
129         // assume parms is array of strings
130         for( var i=0; i < parms.length; i++ ){
131           doc.write( '<input type="hidden" name="P' + i + '" '
132                    + 'value="[' + jsrsEscapeQQ(parms[i]) + ']">');
133         }
134       } // parm type
135     } // parms
136   } // func
137
138   doc.write('</form></body></html>');
139   doc.close();
140   doc.forms['jsrsForm'].submit();
141 }
142
143 function contextGET( rsPage, func, parms ){
144
145   // build URL to call
146   var URL = rsPage;
147
148   // always send context
149   URL += "?C=" + this.id;
150
151   // func and parms are optional
152   if (func != null){
153     URL += "&F=" + escape(func);
154
155     if (parms != null){
156       if (typeof(parms) == "string"){
157         // single parameter
158         URL += "&P0=[" + escape(parms+'') + "]";
159       } else {
160         // assume parms is array of strings
161         for( var i=0; i < parms.length; i++ ){
162           URL += "&P" + i + "=[" + escape(parms[i]+'') + "]";
163         }
164       } // parm type
165     } // parms
166   } // func
167
168   // unique string to defeat cache
169   var d = new Date();
170   URL += "&U=" + d.getTime();
171  
172   // make the call
173   switch( jsrsBrowser ) {
174     case 'NS':
175       this.container.src = URL;
176       break;
177     case 'IE':
178       this.container.document.location.replace(URL);
179       break;
180     case 'MOZ':
181       this.container.src = '';
182       this.container.src = URL; 
183       break;
184     case 'OPR':
185       this.container.src = '';
186       this.container.src = URL; 
187       break;
188     case 'KONQ':
189       this.container.src = '';
190       this.container.src = URL; 
191       break;
192   }  
193 }
194
195 function contextGetPayload(){
196   switch( jsrsBrowser ) {
197     case 'NS':
198       return this.container.document.forms['jsrs_Form'].elements['jsrs_Payload'].value;
199     case 'IE':
200       return this.container.document.forms['jsrs_Form']['jsrs_Payload'].value;
201     case 'MOZ':
202       return window.frames[this.container.name].document.forms['jsrs_Form']['jsrs_Payload'].value; 
203     case 'OPR':
204       var textElement = window.frames[this.container.name].document.getElementById("jsrs_Payload");
205     case 'KONQ':
206       var textElement = window.frames[this.container.name].document.getElementById("jsrs_Payload");
207       return textElement.value;
208   }  
209 }
210
211 function contextSetVisibility( vis ){
212   switch( jsrsBrowser ) {
213     case 'NS':
214       this.container.visibility = (vis)? 'show' : 'hidden';
215       break;
216     case 'IE':
217       document.all("SPAN" + this.id ).style.display = (vis)? '' : 'none';
218       break;
219     case 'MOZ':
220       document.getElementById("SPAN" + this.id).style.visibility = (vis)? '' : 'hidden';
221     case 'OPR':
222       document.getElementById("SPAN" + this.id).style.visibility = (vis)? '' : 'hidden';
223       this.container.width = (vis)? 250 : 0;
224       this.container.height = (vis)? 100 : 0;
225       break;
226   }  
227 }
228
229 // end of context constructor
230
231 function jsrsGetContextID(){
232   var contextObj;
233   for (var i = 1; i <= jsrsContextPoolSize; i++){
234     contextObj = jsrsContextPool[ 'jsrs' + i ];
235     if ( !contextObj.busy ){
236       contextObj.busy = true;      
237       return contextObj.id;
238     }
239   }
240   // if we got here, there are no existing free contexts
241   if ( jsrsContextPoolSize <= jsrsContextMaxPool ){
242     // create new context
243     var contextID = "jsrs" + (jsrsContextPoolSize + 1);
244     jsrsContextPool[ contextID ] = new jsrsContextObj( contextID );
245     jsrsContextPoolSize++;
246     return contextID;
247   } else {
248     alert( "jsrs Error:  context pool full" );
249     return null;
250   }
251 }
252
253 function jsrsExecute( rspage, callback, func, parms, visibility ){
254   // call a server routine from client code
255   //
256   // rspage      - href to asp file
257   // callback    - function to call on return 
258   //               or null if no return needed
259   //               (passes returned string to callback)
260   // func        - sub or function name  to call
261   // parm        - string parameter to function
262   //               or array of string parameters if more than one
263   // visibility  - optional boolean to make container visible for debugging
264
265   // get context
266   var contextObj = jsrsContextPool[ jsrsGetContextID() ];
267   contextObj.callback = callback;
268
269   var vis = (visibility == null)? false : visibility;
270   contextObj.setVisibility( vis );
271
272   if ( jsrsPOST && ((jsrsBrowser == 'IE') || (jsrsBrowser == 'MOZ'))){
273     contextObj.POST( rspage, func, parms );
274   } else {
275     contextObj.GET( rspage, func, parms );
276   }  
277   
278   return contextObj.id;
279 }
280
281 function jsrsLoaded( contextID ){
282   // get context object and invoke callback
283   var contextObj = jsrsContextPool[ contextID ];
284   if( contextObj.callback != null){
285     contextObj.callback( jsrsUnescape( contextObj.getPayload() ), contextID );
286   }
287   // clean up and return context to pool
288   contextObj.callback = null;
289   contextObj.busy = false;
290 }
291
292 function jsrsError( contextID, str ){
293   alert( unescape(str) );
294   jsrsContextPool[ contextID ].busy = false
295 }
296
297 function jsrsEscapeQQ( thing ){
298   return thing.replace(/'"'/g, '\\"');
299 }
300
301 function jsrsUnescape( str ){
302   // payload has slashes escaped with whacks
303   return str.replace( /\\\//g, "/" );
304 }
305
306 function jsrsBrowserSniff(){
307   if (document.layers) return "NS";
308   if (document.all) {
309                 // But is it really IE?
310                 // convert all characters to lowercase to simplify testing
311                 var agt=navigator.userAgent.toLowerCase();
312                 var is_opera = (agt.indexOf("opera") != -1);
313                 var is_konq = (agt.indexOf("konqueror") != -1);
314                 if(is_opera) {
315                         return "OPR";
316                 } else {
317                         if(is_konq) {
318                                 return "KONQ";
319                         } else {
320                                 // Really is IE
321                                 return "IE";
322                         }
323                 }
324   }
325   if (document.getElementById) return "MOZ";
326   return "OTHER";
327 }
328
329 /////////////////////////////////////////////////
330 //
331 // user functions
332
333 function jsrsArrayFromString( s, delim ){
334   // rebuild an array returned from server as string
335   // optional delimiter defaults to ~
336   var d = (delim == null)? '~' : delim;
337   return s.split(d);
338 }
339
340 function jsrsDebugInfo(){
341   // use for debugging by attaching to f1 (works with IE)
342   // with onHelp = "return jsrsDebugInfo();" in the body tag
343   var doc = window.open().document;
344   doc.open;
345   doc.write( 'Pool Size: ' + jsrsContextPoolSize + '<br><font face="arial" size="2"><b>' );
346   for( var i in jsrsContextPool ){
347     var contextObj = jsrsContextPool[i];
348     doc.write( '<hr>' + contextObj.id + ' : ' + (contextObj.busy ? 'busy' : 'available') + '<br>');
349     doc.write( contextObj.container.document.location.pathname + '<br>');
350     doc.write( contextObj.container.document.location.search + '<br>');
351     doc.write( '<table border="1"><tr><td>' + contextObj.container.document.body.innerHTML + '</td></tr></table>' );
352   }
353   doc.write('</table>');
354   doc.close();
355   return false;
356 }