r9065@llin: dpavlin | 2005-11-23 01:15:39 +0100
[webpac2] / web / iwf / iwfajax.js
1 // =========================================================================\r
2 /// IWF - Interactive Website Framework.  Javascript library for creating\r
3 /// responsive thin client interfaces.\r
4 ///\r
5 /// Copyright (C) 2005 Brock Weaver brockweaver@users.sourceforge.net\r
6 ///\r
7 ///     This library is free software; you can redistribute it and/or modify\r
8 /// it under the terms of the GNU Lesser General Public License as published\r
9 /// by the Free Software Foundation; either version 2.1 of the License, or\r
10 /// (at your option) any later version.\r
11 ///\r
12 ///     This library is distributed in the hope that it will be useful, but\r
13 /// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
14 /// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public\r
15 /// License for more details.\r
16 ///\r
17 ///    You should have received a copy of the GNU Lesser General Public License\r
18 /// along with this library; if not, write to the Free Software Foundation,\r
19 /// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
20 ///\r
21 /// Brock Weaver\r
22 /// brockweaver@users.sourceforge.net\r
23 /// 1605 NW Maple Pl\r
24 /// Ankeny, IA 50021\r
25 ///\r
26 //! http://iwf.sourceforge.net/\r
27 // --------------------------------------------------------------------------\r
28 //! NOTE: To minimize file size, strip all fluffy comments (except the LGPL, of course!)\r
29 //! using the following regex (global flag and multiline on):\r
30 //!            ^\t*//([^/!].*|$)\r
31 //\r
32 // This reduces file size by about 30%, give or take.\r
33 //\r
34 //!  To rip out only logging statements (commented or uncommented):\r
35 //!            ^/{0,2}iwfLog.*\r
36 // --------------------------------------------------------------------------\r
37 \r
38 \r
39 // --------------------------------------------------------------------------\r
40 //\r
41 //! iwfajax.js\r
42 //\r
43 // Thread-safe background xml request via XmlHttpRequest object\r
44 //\r
45 //! Dependencies:\r
46 //! iwfxml.js\r
47 //! iwfcore.js\r
48 //! iwfgui.js (optional -- pretty progress bar)\r
49 //\r
50 //! Brock Weaver - brockweaver@users.sourceforge.net\r
51 //! v 0.2 - 2005-11-14\r
52 //! core bug patch\r
53 // --------------------------------------------------------------------------\r
54 //! v 0.1 - 2005-06-05\r
55 //! Initial release.\r
56 //\r
57 //! Known Issues:\r
58 //!  AddToHistory does not work\r
59 //!  Iframe not implemented\r
60 //\r
61 // =========================================================================\r
62 \r
63 \r
64 \r
65 \r
66 // show progress bar if they included iwfgui.js, window.status otherwise.\r
67 var _iwfShowGuiProgress = iwfExists(window.iwfShow);\r
68 \r
69 \r
70 \r
71 \r
72 \r
73 \r
74 // -----------------------------------\r
75 // Begin: Dependency Check\r
76 // -----------------------------------\r
77 \r
78 if (!window.iwfGetById || !window.iwfXmlDoc){\r
79         iwfLog("IWF Dependency Error: iwfajax.js is dependent upon both iwfcore.js and iwfxml.js, so you *must* reference those files first.\n\nExample:\n\n<script type='text/javascript' src='iwfcore.js'></script>\n<script type='text/javascript' src='iwfxml.js'></script>\n<script type='text/javascript' src='iwfajax.js'></script>", true);\r
80 }\r
81 \r
82 // -----------------------------------\r
83 // End: Dependency Check\r
84 // -----------------------------------\r
85 \r
86 // -----------------------------------\r
87 // Begin: AJAX Request and Response\r
88 // -----------------------------------\r
89 \r
90 function iwfRequest(urlOrForm, targetElementOnResponse, addToHistory, callback){\r
91 \r
92         // we use a javascript feature here called "inner functions"\r
93         // using these means the local variables retain their values after the outer function\r
94         // has returned.  this is useful for thread safety, so\r
95         // reassigning the onreadystatechange function doesn't stomp over earlier requests.\r
96 \r
97         function iwfBindCallback(){\r
98                 if (req.readyState == 4) {\r
99                         _iwfOnRequestEnd();\r
100                         if (req.status == 200 || req.status == 0) {\r
101 //iwfLog('exact response from server:\n\n' + req.responseText);\r
102                                 _iwfResponseHandler(req.responseText, localCallback, localTarget);\r
103                         } else {\r
104                                 _iwfOnRequestError(req.status, req.statusText, req.responseText);\r
105                         }\r
106                         return;\r
107                 }\r
108         }\r
109 \r
110         // determine how to hit the server...\r
111         var url = null;\r
112         var method = 'GET';\r
113         var postdata = null;\r
114         var isFromForm = true;\r
115         var contentType = 'application/x-www-form-urlencoded';\r
116 \r
117         if (iwfIsString(urlOrForm)){\r
118 \r
119                 // if we get here, they either specified the url or the name of the form.\r
120                 // either way, flag so we return nothing.\r
121                 isFromForm = false;\r
122 \r
123                 var frm = iwfGetForm(urlOrForm);\r
124                 if (!frm){\r
125                         // is a url.\r
126                         url = urlOrForm;\r
127                         method = 'GET';\r
128                         postdata = null;\r
129                 } else {\r
130                         // is name of a form.\r
131                         // fill with the form object.\r
132                         urlOrForm = frm;\r
133                 }\r
134 \r
135         }\r
136 \r
137         // use a local variable to hold our callback and target until the inner function is called...\r
138         var localCallback = callback;\r
139         var localTarget = targetElementOnResponse;\r
140 \r
141         if (!iwfIsString(urlOrForm)){\r
142 \r
143                 var ctl = null;\r
144 \r
145 \r
146                 // is a form or a control in the form.\r
147                 if (iwfExists(urlOrForm.form)){\r
148                         // is a control in the form. jump up to the form.\r
149                         ctl = urlOrForm;\r
150                         urlOrForm = urlOrForm.form;\r
151                 }\r
152 \r
153 \r
154                 // if they passed a form and no local target, lookup the form.iwfTarget attribute and use it if possible\r
155                 if (!localTarget){\r
156                                 localTarget = iwfAttribute(urlOrForm, 'iwfTarget');\r
157                 }\r
158 \r
159                 if (localTarget){\r
160                         var elTgt = iwfGetOrCreateByNameWithinForm(urlOrForm, 'iwfTarget', 'input', 'hidden');\r
161                         if (elTgt){\r
162                                 iwfAttribute(elTgt, 'value', localTarget);\r
163                                 iwfRemoveAttribute(elTgt, 'disabled');\r
164                         }\r
165                 }\r
166 \r
167 \r
168                 url = urlOrForm.action;\r
169                 method = urlOrForm.method.toUpperCase();\r
170                 switch(method){\r
171                         case "POST":\r
172                                 postdata = _iwfGetFormData(urlOrForm, url, ctl);\r
173 \r
174                                 // we also need to properly set the content-type header...\r
175                                 var frm = iwfGetForm(urlOrForm);\r
176                                 if (frm){\r
177                                         var enc = iwfAttribute(frm, 'encoding');\r
178                                         if (!enc){\r
179                                                 enc = iwfAttribute(frm, 'enctype');\r
180                                         }\r
181                                         if (enc){\r
182                                                 contentType = enc;\r
183                                         }\r
184                                 }\r
185 \r
186                                 break;\r
187                         case "GET":\r
188                         default:\r
189                                 url = _iwfGetFormData(urlOrForm, url, ctl);\r
190                                 break;\r
191                 }\r
192         }\r
193 \r
194         // prevent any browser caching of our url by requesting a unique url everytime...\r
195         url += ((url.indexOf('?') > -1) ? '&' : '?') + 'iwfRequestId=' + new Date().valueOf();\r
196 \r
197 //iwfLog("url = " + url);\r
198 //iwfLog("method = " + method);\r
199 //iwfLog("postdata = " + postdata);\r
200 //iwfLog("contenttype = " + contentType);\r
201 \r
202 \r
203         var req = null;\r
204         if (!addToHistory){\r
205 //iwfLog("using XHR to perform request...");\r
206                 // use XHR to perform the request, as this will\r
207                 // prevent the browser from adding it to history.\r
208                 req = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");\r
209 \r
210                 // bind our callback\r
211                 req.onreadystatechange = iwfBindCallback;\r
212 \r
213                 // show progress if it's not already visible...\r
214                 _iwfOnRequestStart();\r
215 \r
216                 // hit the server\r
217                 req.open(method, url, true);\r
218                 req.setRequestHeader('Content-Type', contentType);\r
219                 req.send(postdata);\r
220         } else {\r
221                 // use an IFRAME element to perform the request,\r
222                 // as this will cause the browser to add it to history.\r
223                 // TODO: make this work!!!\r
224 iwfLog("using IFRAME to perform request...");\r
225 iwfLog('request and add to history not implemented yet!!!', true);\r
226                 return;\r
227 \r
228                 var el = iwfGetById("iwfHistoryFrame");\r
229                 if (!el){\r
230                         iwfLog("To enable history tracking in IWF, you must add an invisible IFRAME element to your page:\n<IFRAME id='iwfHistoryFrame' style='display:none'></IFRAME>", true);\r
231                 }\r
232 \r
233                 el.src = url;\r
234 \r
235                 // show progress if it's not already visible...\r
236                 _iwfOnRequestStart();\r
237 \r
238 \r
239         }\r
240 \r
241         // if this is called from the form.onsubmit event, make sure the form doesn't submit...\r
242 \r
243         if (isFromForm){\r
244                 return false;\r
245         } else {\r
246                 // return absolutely nothing so anchor tags don't hork the current page\r
247         }\r
248 \r
249 }\r
250 \r
251 function _iwfGetFormData(form, url, ctl){\r
252 \r
253         var method = form.method;\r
254         if (!method) method = "get";\r
255 \r
256         var output = null;\r
257 \r
258         if (method == 'get'){\r
259                 output = url + ((url.indexOf('?') > -1) ? '&' : '?');\r
260         } else {\r
261                 output = '';\r
262         }\r
263 \r
264 \r
265         // if there is a target specified in the <form> tag,\r
266         // copy its contents to a hidden <input type='hidden'> tag.\r
267 \r
268 //iwfLog("total elements in form named '" + form.name + "': " + form.elements.length);\r
269         for(var i=0;i<form.elements.length;i++){\r
270                 var el = form.elements[i];\r
271                 var nm = iwfAttribute(el, 'name');\r
272                 var val = null;\r
273                 if (!iwfAttribute(el, 'disabled') && nm){\r
274                         switch (el.tagName.toLowerCase()){\r
275                                 case 'input':\r
276                                         switch(iwfAttribute(el, 'type')){\r
277                                                 case 'checkbox':\r
278                                                         if (iwfAttribute(el, 'checked')){\r
279                                                                 val = 'on';\r
280                                                         }\r
281                                                 case 'radio':\r
282                                                         if (iwfAttribute(el, 'checked')){\r
283                                                                 val = iwfAttribute(el, 'value');\r
284                                                         }\r
285                                                         break;\r
286                                                 case 'button':\r
287                                                         if (el == ctl){\r
288                                                                 val = iwfAttribute(el, 'value');\r
289                                                         }\r
290                                                         break;\r
291                                                 case 'submit':\r
292                                                         if (el == ctl){\r
293                                                                 val = iwfAttribute(el, 'value');\r
294                                                         }\r
295                                                         break;\r
296                                                 case 'text':\r
297                                                 default:\r
298                                                         val = iwfAttribute(el, 'value');\r
299                                                         break;\r
300                                                 case 'file':\r
301                                                         iwfLog('TODO: implement <input type="file"> in _iwfGetFormData', true);\r
302                                                         val = iwfAttribute(el, 'value');\r
303                                                         break;\r
304                                                 case 'image':\r
305                                                         iwfLog('TODO: implement <input type="image"> in _iwfGetFormData', true);\r
306                                                         val = iwfAttribute(el, 'value');\r
307                                                         break;\r
308                                                 case 'reset':\r
309                                                         iwfLog('TODO: implement <input type="reset"> in _iwfGetFormData', true);\r
310                                                         break;\r
311                                                 case 'hidden':\r
312                                                         val = iwfAttribute(el, 'value');\r
313                                                         break;\r
314                                         }\r
315                                         break;\r
316                                 case 'textarea':\r
317                                         val = iwfAttribute(el, 'innerText') || el.value;\r
318                                         break;\r
319                                 case 'button':\r
320                                         if (el == ctl){\r
321                                                 val = iwfAttribute(el, 'innerText') || el.value;\r
322                                         }\r
323                                         break;\r
324                                 case 'select':\r
325                                         for(var j=0;j<el.options.length;j++){\r
326                                                 if (iwfAttribute(el.options[j], 'selected') == 'true'){\r
327                                                         if (!val){\r
328                                                                 val = iwfAttribute(el.options[j], 'value');\r
329                                                         } else {\r
330                                                                 val += '+' + iwfAttribute(el.options[j], 'value');\r
331                                                         }\r
332                                                 }\r
333                                         }\r
334                         }\r
335 \r
336                         if (val){\r
337                                 if (output.length > 0){\r
338                                         output += '&';\r
339                                 }\r
340                                 output += escape(nm) + '=' + escape(val);\r
341                         }\r
342                 }\r
343         }\r
344         if (output.length == 0){\r
345                 return null;\r
346         } else {\r
347                 return output;\r
348         }\r
349 }\r
350 \r
351 function _iwfResponseReceived(doc){\r
352 iwfLog('iframeloaded');\r
353         var xmlDoc = new iwfXmlDoc(doc.innerHTML);\r
354 }\r
355 \r
356 function _iwfResponseHandler(origText, callback, tgt){\r
357         var doc = new iwfXmlDoc(origText);\r
358         if (!doc.response){\r
359                 // not in our default xml format.\r
360                 // just throw out the xml to the callback, if any\r
361                 if (callback){\r
362                         callback(doc);\r
363                 } else {\r
364                         iwfLog("IWF Ajax Error: No callback defined for non-standard response:\n" + origText, true);\r
365                 }\r
366         } else {\r
367                 if (doc.response.debugging == 'true'){\r
368                         iwfLoggingEnabled = true;\r
369                         iwfLog("IWF Ajax Debugging:\nParsed response:\n\n" + doc.response.outerXml(true), true);\r
370                         iwfShowLog();\r
371                 }\r
372                 for(var i=0; i< doc.response.childNodes.length; i++){\r
373                         var node = doc.response.childNodes[i];\r
374                         if (node.nodeName.indexOf("#") != 0){\r
375 //iwfLog('node.target=' + node.target + '\ntgt=' + tgt);\r
376                                 if (!tgt) {\r
377                                         // server target is ignored if a client target exists.\r
378                                         tgt = node.target;\r
379                                 }\r
380                                 if (node.errorCode && iwfToInt(node.errorCode, true) != 0){\r
381                                         // an error occurred.\r
382                                         _iwfOnRequestError(node.errorCode, node.errorMessage);\r
383                                 } else {\r
384                                         if (!node.type){\r
385                                                 node.type = "";\r
386                                         }\r
387                                         switch(node.type.toLowerCase()){\r
388                                                 case "html":\r
389                                                 case "xhtml":\r
390                                                         var innerHtml = node.innerHtml();\r
391 //iwfLog('parsed html response:\n\n' + innerHtml);\r
392                                                         _iwfInsertHtml(innerHtml, tgt);\r
393                                                         break;\r
394                                                 case "javascript":\r
395                                                 case "js":\r
396                                                         var bomb = true;\r
397                                                         if (node.childNodes.length == 1){\r
398                                                                 var js = node.childNodes[0];\r
399                                                                 if (js.nodeName == '#cdata' || js.nodeName == '#comment'){\r
400                                                                         bomb = false;\r
401                                                                         var code = js.getText();\r
402                                                                         eval(code);\r
403                                                                 }\r
404                                                         }\r
405                                                         if (bomb){\r
406                                                                 iwfLog("IWF Ajax Error: When an <action> is defined of type javascript, it content must be contained by either a Comment (<!-- -->) or CDATA (<![CDATA[  ]]>).\nCDATA is the more appropriate manner, as this is the xml-compliant one.\nHowever, COMMENT is also allowed as this is html-compliant, such as within a <script> element.\n\n<action> xml returned:\n\n" + node.outerXml(), true);\r
407                                                         }\r
408                                                         break;\r
409                                                 case "xml":\r
410                                                         if (callback){\r
411                                                                 callback(node);\r
412                                                         }\r
413                                                         break;\r
414                                                 case "debug":\r
415                                                         iwfLog("IWF Debug: <action> type identified as 'debug'.\nXml received for current action:\n\n" + node.outerXml(), true);\r
416                                                         break;\r
417                                                 default:\r
418                                                         iwfLog('IWF Ajax Error: <action> type of "' + node.type + '" is not a valid option.\n\nValid options:\n\'html\' or \'xhtml\' = parse as html and inject into element with the id specified by the target attribute\n\'javascript\' or \'js\' = parse as javascript and execute\n\'xml\' = parse as xml and call the callback specified when iwfRequest() was called\n\'debug\' = parse as xml and log/alert the result\n\n<action> xml returned:\n\n' + node.outerXml(), true);\r
419                                                         break;\r
420                                         }\r
421                                 }\r
422                         }\r
423                 }\r
424         }\r
425 \r
426 }\r
427 \r
428 function _iwfInsertHtml(html, parentNodeId){\r
429         if(!parentNodeId){\r
430                 parentNodeId = 'iwfContent';\r
431                 iwfLog("IWF Ajax Warning: <action> with a type of 'html' does not have its target attribute specified, so using the default of 'iwfContent'.");\r
432         }\r
433 \r
434         if(!parentNodeId){\r
435                         iwfLog("IWF Ajax Error: <action> node with a type of 'html' does not have its target attribute specified to a valid element.\nPlease specify the id of the element into which the contents of the <action> node should be placed.\nTo fill the entire page, simply specify 'body'.", true);\r
436         } else {\r
437                 var el = iwfGetById(parentNodeId);\r
438                 if (!el){\r
439                         if (parentNodeId == 'body'){\r
440                                 el = iwfGetByTagName('body');\r
441                                 if (!el || el.length == 0){\r
442                                         iwfLog("IWF Ajax Error: Could not locate the tag named 'body'", true);\r
443                                         return;\r
444                                 } else {\r
445                                         el = el[0];\r
446                                 }\r
447                         } else {\r
448                                         iwfLog('IWF Ajax Error: Could not locate element with id of ' + parentNodeId + ' into which the following html should be placed:\n\n' + html, true);\r
449                                         return;\r
450                         }\r
451                 }\r
452 \r
453 //iwfLog(iwfElementToString(el));\r
454 //iwfLog(html);\r
455 \r
456                 // trying to shove a <form> node inside another <form> node is a bad thing.\r
457                 // make sure we don't do that here.\r
458                 var re = /<form/i;\r
459                 var match = re.exec(html);\r
460                 if (match && document.forms.length > 0){\r
461                         // our html to inject contains a form node.\r
462                         // bubble up the chain until we find a <form> node, or we have no parents\r
463                         var elParent = el;\r
464                         // I have doubts about adding elParent.tagName here\r
465                         // but I don't have better idea. -dpavlin\r
466                         while (elParent && elParent.tagName && elParent.tagName.toLowerCase() != 'form'){\r
467                                 elParent = iwfGetParent(elParent);\r
468                         }\r
469 \r
470                         if (elParent && elParent.tagName && elParent.tagName.toLowerCase() == 'form'){\r
471                                 iwfLog('IWF Ajax Error: Attempting to inject html which contains a <form> node into a target element which is itself a <form> node, or is already contained by a <form> node.\nThis is bad html, and will not work appropriately on some major browsers.', true);\r
472                         }\r
473                 }\r
474 \r
475 \r
476                 el.innerHTML = html;\r
477 \r
478 \r
479                 // if there is a script element, we have to explicitly add it to the body element,\r
480                 // as IE and firefox just don't like it when you try to add it as part of the innerHTML\r
481                 // property.  Go figure.\r
482 \r
483                 var i = 0;\r
484                 // don't stomp on any existing scripts...\r
485                 while (iwfGetById('iwfScript' + i)){\r
486                         i++;\r
487                 }\r
488 \r
489                 var scriptStart = html.indexOf("<script");\r
490                 while(scriptStart > -1){\r
491                         scriptStart = html.indexOf(">", scriptStart) + 1;\r
492 \r
493                         // copy contents of script into a default holder\r
494                         var scriptEnd = html.indexOf("</script>", scriptStart);\r
495                         var scriptHtml = html.substr(scriptStart, scriptEnd - scriptStart);\r
496 \r
497                         var re = /^\s*<!--/;\r
498                         var match = re.exec(scriptHtml);\r
499                         if (!match){\r
500                                 iwfLog("IWF Ajax Error: Developer, you *must* put the <!-- and //--> 'safety net' around your script within all <script> tags.\nThe offending <script> tag contains the following code:\n\n" + scriptHtml + "\n\nThis requirement is due to how IWF injects the html so the browser is able to actually parse the script and make its contents available for execution.", true);\r
501                         }\r
502 \r
503                         // this code is the worst hack in this entire framework.\r
504                         // the code in the try portion should work anywhere -- but\r
505                         // IE barfs when you try to set the innerHTML on a script element.\r
506                         // not only that, but IE won't parse script unless a visible element\r
507                         // is contained in the innerHTML when it is set, so we need the <code>IE hack here</code>\r
508                         // and it cannot be removed.\r
509                         // I don't understand why creating a new node and setting its innerHTML causes the browsers\r
510                         // to parse and execute the script, but it does.\r
511                         // Note there is a major leak here, as we do not try to reuse existing iwfScriptXXXX elements\r
512                         // in case they are in use by other targets.  To clean these up, simply call iwfCleanScripts\r
513                         // periodically.  This is so app-dependent, I didn't want to try to keep track of everything\r
514                         // and possibly miss a case, causing really weird results that only show up occassionally.\r
515                         //\r
516                         // Plus I'm getting lazy. :)\r
517                         //\r
518                         try {\r
519                                 //! moz (DOM)\r
520                                 var elScript = iwfGetOrCreateById('iwfScript' + i, 'script');\r
521                                 elScript.type = 'text/javascript';\r
522                                 elScript.defer = 'true';\r
523                                 elScript.innerHTML = scriptHtml;\r
524 \r
525                                 iwfAppendChild('body', elScript);\r
526 \r
527                         } catch(e){\r
528 //iwfLog("IE Hack for injecting script tag...", true);\r
529                                 //! IE hack\r
530                                 // IE needs a visible tag within a non-script element to have scripting apply... Don't ask me why, ask the IE team why.\r
531                                 // My guess is the visible element causes the page to at least partially re-render, which in turn kicks off any script parsing\r
532                                 // code in IE.\r
533                                 var elDiv = iwfGetOrCreateById('iwfScript' + i, '<div style="display:none"></div>', 'body');\r
534                                 elDiv.innerHTML = '<code>IE hack here</code><script id="iwfScript' + i + '" defer="true">' + scriptHtml + '</script' + '>';\r
535                         }\r
536 \r
537                         i++;\r
538 \r
539                         scriptStart = html.indexOf("<script", scriptEnd+8);\r
540                 }\r
541         }\r
542 }\r
543 \r
544 function iwfCleanScripts(){\r
545         var i = 0;\r
546         while(iwfRemoveNode('iwfScript' + (i++)));\r
547 \r
548 }\r
549 \r
550 \r
551 \r
552 var _iwfTotalRequests = 0;\r
553 var _iwfPendingRequests = 0;\r
554 var _iwfRequestTicker = null;\r
555 var _iwfRequestTickCount = 0;\r
556 var _iwfRequestTickDuration = 100;\r
557 \r
558 \r
559 // TODO: make the styles applied be configurable variables at the top of this file.\r
560 function _iwfGetBusyBar(inner){\r
561         var b = iwfGetById('iwfBusy');\r
562         if (!b){\r
563                 b = iwfGetOrCreateById('iwfBusy', 'div', 'body');\r
564                 if(b.style){\r
565                         b.style.position = 'absolute';\r
566                         b.style.border = '1px solid black';\r
567                         b.style.backgroundColor = '#efefef';\r
568                         b.style.textAlign = 'center';\r
569                 }\r
570                 iwfWidth(b, 100);\r
571                 iwfHeight(b, 20);\r
572                 iwfZIndex(b, 9999);\r
573 \r
574                 iwfX(b, 0);\r
575                 iwfY(b, 0);\r
576 \r
577 //              iwfX(b, iwfClientWidth() - iwfWidth(b)-5);\r
578 //              iwfY(b, iwfClientHeight() - iwfHeight(b)-5);\r
579 \r
580                 iwfHide(b);\r
581         }\r
582 \r
583 \r
584 \r
585         var bb = iwfGetById('iwfBusyBar');\r
586         if(!bb){\r
587                 bb = iwfGetOrCreateById('iwfBusyBar', 'div', b);\r
588                 bb.style.backgroundColor = 'navy';\r
589                 bb.style.color = 'white';\r
590                 bb.style.textAlign = 'center';\r
591                 iwfWidth(bb, 1);\r
592                 iwfHeight(bb, 20);\r
593                 iwfX(bb, 0);\r
594                 iwfY(bb, 0);\r
595         }\r
596 \r
597         if(inner){\r
598                 return bb;\r
599         } else {\r
600                 return b;\r
601         }\r
602 \r
603 }\r
604 \r
605 function _iwfOnRequestStart(){\r
606         _iwfPendingRequests++;\r
607         _iwfTotalRequests++;\r
608 \r
609         _iwfRequestTickDuration = 100;\r
610 \r
611         if (!_iwfRequestTicker){\r
612                 _iwfRequestTickCount = 0;\r
613                 if (window.iwfOnRequestStart){\r
614                         _iwfRequestTickDuration = iwfOnRequestStart();\r
615                 } else if (_iwfShowGuiProgress) {\r
616                         // use gui busy implementation\r
617                         var bb = _iwfGetBusyBar(true);\r
618                         iwfWidth(bb, 1);\r
619                         bb.innerHTML = '0%';\r
620                         iwfShow(_iwfGetBusyBar(false));\r
621                 } else {\r
622                         // use default busy implementation...\r
623                         window.status = 'busy.';\r
624                 }\r
625                 if (!_iwfRequestTickDuration){\r
626                         _iwfRequestTickDuration = 100;\r
627                 }\r
628                 _iwfRequestTicker = setInterval(_iwfOnRequestTick, _iwfRequestTickDuration);\r
629         }\r
630 }\r
631 \r
632 function _iwfOnRequestTick(){\r
633         _iwfRequestTickCount++;\r
634         if (window.iwfOnRequestTick){\r
635                 iwfOnRequestTick(_iwfRequestTickCount, _iwfRequestTickDuration, _iwfPendingRequests);\r
636         } else if (!window.iwfOnRequestStart) {\r
637                 if (_iwfShowGuiProgress) {\r
638                         // use gui busy implementation\r
639                         var bar = _iwfGetBusyBar(true);\r
640                         if(bar){\r
641                                 var w = iwfWidth(bar) + 1;\r
642                                 if (w > 95){\r
643                                         w = 95;\r
644                                 }\r
645                                 iwfWidth(bar, w);\r
646                                 bar.innerHTML = "loading " + iwfIntFormat(w) + "%";\r
647                         }\r
648                 } else {\r
649                         // use default busy implementation...\r
650                         window.status = 'busy...............................................'.substr(0, (_iwfRequestTickCount % 45) + 5);\r
651                 }\r
652         } else {\r
653                 // they didn't define a tick function,\r
654                 // but they did define a start one, so do nothing.\r
655         }\r
656 }\r
657 \r
658 function _iwfOnRequestEnd(){\r
659         _iwfPendingRequests--;\r
660         if (_iwfPendingRequests < 1){\r
661                 _iwfPendingRequests = 0;\r
662                 _iwfTotalRequests = 0;\r
663                 clearInterval(_iwfRequestTicker);\r
664                 _iwfRequestTicker = null;\r
665                 if (window.iwfOnRequestEnd){\r
666                         iwfOnRequestEnd();\r
667                 } else if (!window.iwfOnRequestStart) {\r
668                         if (_iwfShowGuiProgress) {\r
669                         // use gui busy implementation\r
670                                 var bar = _iwfGetBusyBar(true);\r
671                                 if(bar){\r
672                                         iwfWidth(bar, 100);\r
673                                         bar.innerHTML = "Done";\r
674                                         iwfHideGentlyDelay(_iwfGetBusyBar(false), 15, 500);\r
675                                 }\r
676                         } else {\r
677                                 // use default busy implementation...\r
678                                 window.status = 'done.';\r
679                         }\r
680                 } else {\r
681                         // they didn't define an end function,\r
682                         // but they did define a start one, so do nothing.\r
683                 }\r
684 \r
685         } else {\r
686                 if (window.iwfOnRequestProgress){\r
687                         iwfOnRequestProgress(_iwfPendingRequests, _iwfTotalRequests);\r
688                 } else if (!window.iwfOnRequestStart) {\r
689                         if (_iwfShowGuiProgress) {\r
690                         // use gui busy implementation\r
691                                 var pct = (1 - (_iwfPendingRequests/_iwfTotalRequests)) * 100;\r
692                                 if (pct > 100){\r
693                                         pct = 100;\r
694                                 }\r
695                                 var bar = _iwfGetBusyBar(true);\r
696                                 if(bar){\r
697                                         iwfWidth(bar, pct);\r
698                                         bar.innerHTML = "loading " + iwfIntFormat(pct) + "%";\r
699                                 }\r
700                         } else {\r
701                                 // use default busy implementation...\r
702                                 window.status = 'Remaining: ' + _iwfPendingRequests;\r
703                         }\r
704                 } else {\r
705                         // they didn't define an end function,\r
706                         // but they did define a start one, so do nothing.\r
707                 }\r
708         }\r
709 }\r
710 \r
711 function _iwfOnRequestError(code, msg, text){\r
712         iwfLog("Error " + code + ": " + msg + ":\n\n" + text);\r
713         if (window.iwfOnRequestError){\r
714                 iwfOnRequestError(code, msg, text);\r
715         } else {\r
716                 alert("Error " + code + ": " + msg + ":\n\n" + text);\r
717         }\r
718 }\r
719 \r
720 // -----------------------------------\r
721 // End: AJAX Request and Response\r
722 // -----------------------------------\r