r8878@llin: dpavlin | 2005-11-14 18:56:54 +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                                                 case 'radio':\r
279                                                         if (iwfAttribute(el, 'checked') || el.checked){\r
280                                                                 val = iwfAttribute(el, 'value') || el.value;\r
281                                                         }\r
282                                                         break;\r
283                                                 case 'button':\r
284                                                         if (el == ctl){\r
285                                                                 val = iwfAttribute(el, 'value');\r
286                                                         }\r
287                                                         break;\r
288                                                 case 'submit':\r
289                                                         if (el == ctl){\r
290                                                                 val = iwfAttribute(el, 'value');\r
291                                                         }\r
292                                                         break;\r
293                                                 case 'text':\r
294                                                 default:\r
295                                                         val = iwfAttribute(el, 'value');\r
296                                                         break;\r
297                                                 case 'file':\r
298                                                         iwfLog('TODO: implement <input type="file"> in _iwfGetFormData', true);\r
299                                                         val = iwfAttribute(el, 'value');\r
300                                                         break;\r
301                                                 case 'image':\r
302                                                         iwfLog('TODO: implement <input type="image"> in _iwfGetFormData', true);\r
303                                                         val = iwfAttribute(el, 'value');\r
304                                                         break;\r
305                                                 case 'reset':\r
306                                                         iwfLog('TODO: implement <input type="reset"> in _iwfGetFormData', true);\r
307                                                         break;\r
308                                                 case 'hidden':\r
309                                                         val = iwfAttribute(el, 'value');\r
310                                                         break;\r
311                                         }\r
312                                         break;\r
313                                 case 'textarea':\r
314                                         val = iwfAttribute(el, 'innerText') || el.value;\r
315                                         break;\r
316                                 case 'button':\r
317                                         if (el == ctl){\r
318                                                 val = iwfAttribute(el, 'innerText') || el.value;\r
319                                         }\r
320                                         break;\r
321                                 case 'select':\r
322                                         for(var j=0;j<el.options.length;j++){\r
323                                                 if (iwfAttribute(el.options[j], 'selected') == 'true'){\r
324                                                         if (!val){\r
325                                                                 val = iwfAttribute(el.options[j], 'value');\r
326                                                         } else {\r
327                                                                 val += '+' + iwfAttribute(el.options[j], 'value');\r
328                                                         }\r
329                                                 }\r
330                                         }\r
331                         }\r
332 \r
333                         if (val){\r
334                                 if (output.length > 0){\r
335                                         output += '&';\r
336                                 }\r
337                                 output += escape(nm) + '=' + escape(val);\r
338                         }\r
339                 }\r
340         }\r
341         if (output.length == 0){\r
342                 return null;\r
343         } else {\r
344                 return output;\r
345         }\r
346 }\r
347 \r
348 function _iwfResponseReceived(doc){\r
349 iwfLog('iframeloaded');\r
350         var xmlDoc = new iwfXmlDoc(doc.innerHTML);\r
351 }\r
352 \r
353 function _iwfResponseHandler(origText, callback, tgt){\r
354         var doc = new iwfXmlDoc(origText);\r
355         if (!doc.response){\r
356                 // not in our default xml format.\r
357                 // just throw out the xml to the callback, if any\r
358                 if (callback){\r
359                         callback(doc);\r
360                 } else {\r
361                         iwfLog("IWF Ajax Error: No callback defined for non-standard response:\n" + origText, true);\r
362                 }\r
363         } else {\r
364                 if (doc.response.debugging == 'true'){\r
365                         iwfLoggingEnabled = true;\r
366                         iwfLog("IWF Ajax Debugging:\nParsed response:\n\n" + doc.response.outerXml(true), true);\r
367                         iwfShowLog();\r
368                 }\r
369                 for(var i=0; i< doc.response.childNodes.length; i++){\r
370                         var node = doc.response.childNodes[i];\r
371                         if (node.nodeName.indexOf("#") != 0){\r
372 //iwfLog('node.target=' + node.target + '\ntgt=' + tgt);\r
373                                 if (!tgt) {\r
374                                         // server target is ignored if a client target exists.\r
375                                         tgt = node.target;\r
376                                 }\r
377                                 if (node.errorCode && iwfToInt(node.errorCode, true) != 0){\r
378                                         // an error occurred.\r
379                                         _iwfOnRequestError(node.errorCode, node.errorMessage);\r
380                                 } else {\r
381                                         if (!node.type){\r
382                                                 node.type = "";\r
383                                         }\r
384                                         switch(node.type.toLowerCase()){\r
385                                                 case "html":\r
386                                                 case "xhtml":\r
387                                                         var innerHtml = node.innerHtml();\r
388 //iwfLog('parsed html response:\n\n' + innerHtml);\r
389                                                         _iwfInsertHtml(innerHtml, tgt);\r
390                                                         break;\r
391                                                 case "javascript":\r
392                                                 case "js":\r
393                                                         var bomb = true;\r
394                                                         if (node.childNodes.length == 1){\r
395                                                                 var js = node.childNodes[0];\r
396                                                                 if (js.nodeName == '#cdata' || js.nodeName == '#comment'){\r
397                                                                         bomb = false;\r
398                                                                         var code = js.getText();\r
399                                                                         eval(code);\r
400                                                                 }\r
401                                                         }\r
402                                                         if (bomb){\r
403                                                                 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
404                                                         }\r
405                                                         break;\r
406                                                 case "xml":\r
407                                                         if (callback){\r
408                                                                 callback(node);\r
409                                                         }\r
410                                                         break;\r
411                                                 case "debug":\r
412                                                         iwfLog("IWF Debug: <action> type identified as 'debug'.\nXml received for current action:\n\n" + node.outerXml(), true);\r
413                                                         break;\r
414                                                 default:\r
415                                                         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
416                                                         break;\r
417                                         }\r
418                                 }\r
419                         }\r
420                 }\r
421         }\r
422 \r
423 }\r
424 \r
425 function _iwfInsertHtml(html, parentNodeId){\r
426         if(!parentNodeId){\r
427                 parentNodeId = 'iwfContent';\r
428                 iwfLog("IWF Ajax Warning: <action> with a type of 'html' does not have its target attribute specified, so using the default of 'iwfContent'.");\r
429         }\r
430 \r
431         if(!parentNodeId){\r
432                         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
433         } else {\r
434                 var el = iwfGetById(parentNodeId);\r
435                 if (!el){\r
436                         if (parentNodeId == 'body'){\r
437                                 el = iwfGetByTagName('body');\r
438                                 if (!el || el.length == 0){\r
439                                         iwfLog("IWF Ajax Error: Could not locate the tag named 'body'", true);\r
440                                         return;\r
441                                 } else {\r
442                                         el = el[0];\r
443                                 }\r
444                         } else {\r
445                                         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
446                                         return;\r
447                         }\r
448                 }\r
449 \r
450 //iwfLog(iwfElementToString(el));\r
451 //iwfLog(html);\r
452 \r
453                 // trying to shove a <form> node inside another <form> node is a bad thing.\r
454                 // make sure we don't do that here.\r
455                 var re = /<form/i;\r
456                 var match = re.exec(html);\r
457                 if (match && document.forms.length > 0){\r
458                         // our html to inject contains a form node.\r
459                         // bubble up the chain until we find a <form> node, or we have no parents\r
460                         var elParent = el;\r
461                         while (elParent && elParent.tagName.toLowerCase() != 'form'){\r
462                                 elParent = iwfGetParent(elParent);\r
463                         }\r
464 \r
465                         if (elParent && elParent.tagName.toLowerCase() == 'form'){\r
466                                 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
467                         }\r
468                 }\r
469 \r
470 \r
471                 el.innerHTML = html;\r
472 \r
473 \r
474                 // if there is a script element, we have to explicitly add it to the body element,\r
475                 // as IE and firefox just don't like it when you try to add it as part of the innerHTML\r
476                 // property.  Go figure.\r
477 \r
478                 var i = 0;\r
479                 // don't stomp on any existing scripts...\r
480                 while (iwfGetById('iwfScript' + i)){\r
481                         i++;\r
482                 }\r
483 \r
484                 var scriptStart = html.indexOf("<script");\r
485                 while(scriptStart > -1){\r
486                         scriptStart = html.indexOf(">", scriptStart) + 1;\r
487 \r
488                         // copy contents of script into a default holder\r
489                         var scriptEnd = html.indexOf("</script>", scriptStart);\r
490                         var scriptHtml = html.substr(scriptStart, scriptEnd - scriptStart);\r
491 \r
492                         var re = /^\s*<!--/;\r
493                         var match = re.exec(scriptHtml);\r
494                         if (!match){\r
495                                 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
496                         }\r
497 \r
498                         // this code is the worst hack in this entire framework.\r
499                         // the code in the try portion should work anywhere -- but\r
500                         // IE barfs when you try to set the innerHTML on a script element.\r
501                         // not only that, but IE won't parse script unless a visible element\r
502                         // is contained in the innerHTML when it is set, so we need the <code>IE hack here</code>\r
503                         // and it cannot be removed.\r
504                         // I don't understand why creating a new node and setting its innerHTML causes the browsers\r
505                         // to parse and execute the script, but it does.\r
506                         // Note there is a major leak here, as we do not try to reuse existing iwfScriptXXXX elements\r
507                         // in case they are in use by other targets.  To clean these up, simply call iwfCleanScripts\r
508                         // periodically.  This is so app-dependent, I didn't want to try to keep track of everything\r
509                         // and possibly miss a case, causing really weird results that only show up occassionally.\r
510                         //\r
511                         // Plus I'm getting lazy. :)\r
512                         //\r
513                         try {\r
514                                 //! moz (DOM)\r
515                                 var elScript = iwfGetOrCreateById('iwfScript' + i, 'script');\r
516                                 elScript.type = 'text/javascript';\r
517                                 elScript.defer = 'true';\r
518                                 elScript.innerHTML = scriptHtml;\r
519 \r
520                                 iwfAppendChild('body', elScript);\r
521 \r
522                         } catch(e){\r
523 //iwfLog("IE Hack for injecting script tag...", true);\r
524                                 //! IE hack\r
525                                 // 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
526                                 // My guess is the visible element causes the page to at least partially re-render, which in turn kicks off any script parsing\r
527                                 // code in IE.\r
528                                 var elDiv = iwfGetOrCreateById('iwfScript' + i, '<div style="display:none"></div>', 'body');\r
529                                 elDiv.innerHTML = '<code>IE hack here</code><script id="iwfScript' + i + '" defer="true">' + scriptHtml + '</script' + '>';\r
530                         }\r
531 \r
532                         i++;\r
533 \r
534                         scriptStart = html.indexOf("<script", scriptEnd+8);\r
535                 }\r
536         }\r
537 }\r
538 \r
539 function iwfCleanScripts(){\r
540         var i = 0;\r
541         while(iwfRemoveNode('iwfScript' + (i++)));\r
542 \r
543 }\r
544 \r
545 \r
546 \r
547 var _iwfTotalRequests = 0;\r
548 var _iwfPendingRequests = 0;\r
549 var _iwfRequestTicker = null;\r
550 var _iwfRequestTickCount = 0;\r
551 var _iwfRequestTickDuration = 100;\r
552 \r
553 \r
554 // TODO: make the styles applied be configurable variables at the top of this file.\r
555 function _iwfGetBusyBar(inner){\r
556         var b = iwfGetById('iwfBusy');\r
557         if (!b){\r
558                 b = iwfGetOrCreateById('iwfBusy', 'div', 'body');\r
559                 if(b.style){\r
560                         b.style.position = 'absolute';\r
561                         b.style.border = '1px solid black';\r
562                         b.style.backgroundColor = '#efefef';\r
563                         b.style.textAlign = 'center';\r
564                 }\r
565                 iwfWidth(b, 100);\r
566                 iwfHeight(b, 20);\r
567                 iwfZIndex(b, 9999);\r
568 \r
569                 iwfX(b, 0);\r
570                 iwfY(b, 0);\r
571 \r
572 //              iwfX(b, iwfClientWidth() - iwfWidth(b)-5);\r
573 //              iwfY(b, iwfClientHeight() - iwfHeight(b)-5);\r
574 \r
575                 iwfHide(b);\r
576         }\r
577 \r
578 \r
579 \r
580         var bb = iwfGetById('iwfBusyBar');\r
581         if(!bb){\r
582                 bb = iwfGetOrCreateById('iwfBusyBar', 'div', b);\r
583                 bb.style.backgroundColor = 'navy';\r
584                 bb.style.color = 'white';\r
585                 bb.style.textAlign = 'center';\r
586                 iwfWidth(bb, 1);\r
587                 iwfHeight(bb, 20);\r
588                 iwfX(bb, 0);\r
589                 iwfY(bb, 0);\r
590         }\r
591 \r
592         if(inner){\r
593                 return bb;\r
594         } else {\r
595                 return b;\r
596         }\r
597 \r
598 }\r
599 \r
600 function _iwfOnRequestStart(){\r
601         _iwfPendingRequests++;\r
602         _iwfTotalRequests++;\r
603 \r
604         _iwfRequestTickDuration = 100;\r
605 \r
606         if (!_iwfRequestTicker){\r
607                 _iwfRequestTickCount = 0;\r
608                 if (window.iwfOnRequestStart){\r
609                         _iwfRequestTickDuration = iwfOnRequestStart();\r
610                 } else if (_iwfShowGuiProgress) {\r
611                         // use gui busy implementation\r
612                         var bb = _iwfGetBusyBar(true);\r
613                         iwfWidth(bb, 1);\r
614                         bb.innerHTML = '0%';\r
615                         iwfShow(_iwfGetBusyBar(false));\r
616                 } else {\r
617                         // use default busy implementation...\r
618                         window.status = 'busy.';\r
619                 }\r
620                 if (!_iwfRequestTickDuration){\r
621                         _iwfRequestTickDuration = 100;\r
622                 }\r
623                 _iwfRequestTicker = setInterval(_iwfOnRequestTick, _iwfRequestTickDuration);\r
624         }\r
625 }\r
626 \r
627 function _iwfOnRequestTick(){\r
628         _iwfRequestTickCount++;\r
629         if (window.iwfOnRequestTick){\r
630                 iwfOnRequestTick(_iwfRequestTickCount, _iwfRequestTickDuration, _iwfPendingRequests);\r
631         } else if (!window.iwfOnRequestStart) {\r
632                 if (_iwfShowGuiProgress) {\r
633                         // use gui busy implementation\r
634                         var bar = _iwfGetBusyBar(true);\r
635                         if(bar){\r
636                                 var w = iwfWidth(bar) + 1;\r
637                                 if (w > 95){\r
638                                         w = 95;\r
639                                 }\r
640                                 iwfWidth(bar, w);\r
641                                 bar.innerHTML = "loading " + iwfIntFormat(w) + "%";\r
642                         }\r
643                 } else {\r
644                         // use default busy implementation...\r
645                         window.status = 'busy...............................................'.substr(0, (_iwfRequestTickCount % 45) + 5);\r
646                 }\r
647         } else {\r
648                 // they didn't define a tick function,\r
649                 // but they did define a start one, so do nothing.\r
650         }\r
651 }\r
652 \r
653 function _iwfOnRequestEnd(){\r
654         _iwfPendingRequests--;\r
655         if (_iwfPendingRequests < 1){\r
656                 _iwfPendingRequests = 0;\r
657                 _iwfTotalRequests = 0;\r
658                 clearInterval(_iwfRequestTicker);\r
659                 _iwfRequestTicker = null;\r
660                 if (window.iwfOnRequestEnd){\r
661                         iwfOnRequestEnd();\r
662                 } else if (!window.iwfOnRequestStart) {\r
663                         if (_iwfShowGuiProgress) {\r
664                         // use gui busy implementation\r
665                                 var bar = _iwfGetBusyBar(true);\r
666                                 if(bar){\r
667                                         iwfWidth(bar, 100);\r
668                                         bar.innerHTML = "Done";\r
669                                         iwfHideGentlyDelay(_iwfGetBusyBar(false), 15, 500);\r
670                                 }\r
671                         } else {\r
672                                 // use default busy implementation...\r
673                                 window.status = 'done.';\r
674                         }\r
675                 } else {\r
676                         // they didn't define an end function,\r
677                         // but they did define a start one, so do nothing.\r
678                 }\r
679 \r
680         } else {\r
681                 if (window.iwfOnRequestProgress){\r
682                         iwfOnRequestProgress(_iwfPendingRequests, _iwfTotalRequests);\r
683                 } else if (!window.iwfOnRequestStart) {\r
684                         if (_iwfShowGuiProgress) {\r
685                         // use gui busy implementation\r
686                                 var pct = (1 - (_iwfPendingRequests/_iwfTotalRequests)) * 100;\r
687                                 if (pct > 100){\r
688                                         pct = 100;\r
689                                 }\r
690                                 var bar = _iwfGetBusyBar(true);\r
691                                 if(bar){\r
692                                         iwfWidth(bar, pct);\r
693                                         bar.innerHTML = "loading " + iwfIntFormat(pct) + "%";\r
694                                 }\r
695                         } else {\r
696                                 // use default busy implementation...\r
697                                 window.status = 'Remaining: ' + _iwfPendingRequests;\r
698                         }\r
699                 } else {\r
700                         // they didn't define an end function,\r
701                         // but they did define a start one, so do nothing.\r
702                 }\r
703         }\r
704 }\r
705 \r
706 function _iwfOnRequestError(code, msg, text){\r
707         iwfLog("Error " + code + ": " + msg + ":\n\n" + text);\r
708         if (window.iwfOnRequestError){\r
709                 iwfOnRequestError(code, msg, text);\r
710         } else {\r
711                 alert("Error " + code + ": " + msg + ":\n\n" + text);\r
712         }\r
713 }\r
714 \r
715 // -----------------------------------\r
716 // End: AJAX Request and Response\r
717 // -----------------------------------\r