1// Compat.js 2/** 3 * Compat functions 4 * @category HTML 5 * @package AJAX 6 * @author Joshua Eichorn <[email protected]> 7 * @copyright 2005 Joshua Eichorn 8 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 9 */ 10/** 11 * Functions for compatibility with older browsers 12 */ 13if (!String.fromCharCode && !String.prototype.fromCharCode) { 14 String.prototype.fromCharCode = function(code) 15 { 16 var h = code.toString(16); 17 if (h.length == 1) { 18 h = '0' + h; 19 } 20 return unescape('%' + h); 21 } 22} 23if (!String.charCodeAt && !String.prototype.charCodeAt) { 24 String.prototype.charCodeAt = function(index) 25 { 26 var c = this.charAt(index); 27 for (i = 1; i < 256; i++) { 28 if (String.fromCharCode(i) == c) { 29 return i; 30 } 31 } 32 } 33} 34// http://www.crockford.com/javascript/remedial.html 35if (!Array.splice && !Array.prototype.splice) { 36 Array.prototype.splice = function(s, d) 37 { 38 var max = Math.max, 39 min = Math.min, 40 a = [], // The return value array 41 e, // element 42 i = max(arguments.length - 2, 0), // insert count 43 k = 0, 44 l = this.length, 45 n, // new length 46 v, // delta 47 x; // shift count 48 49 s = s || 0; 50 if (s < 0) { 51 s += l; 52 } 53 s = max(min(s, l), 0); // start point 54 d = max(min(typeof d == 'number' ? d : l, l - s), 0); // delete count 55 v = i - d; 56 n = l + v; 57 while (k < d) { 58 e = this[s + k]; 59 if (!e) { 60 a[k] = e; 61 } 62 k += 1; 63 } 64 x = l - s - d; 65 if (v < 0) { 66 k = s + i; 67 while (x) { 68 this[k] = this[k - v]; 69 k += 1; 70 x -= 1; 71 } 72 this.length = n; 73 } else if (v > 0) { 74 k = 1; 75 while (x) { 76 this[n - k] = this[l - k]; 77 k += 1; 78 x -= 1; 79 } 80 } 81 for (k = 0; k < i; ++k) { 82 this[s + k] = arguments[k + 2]; 83 } 84 return a; 85 } 86} 87if (!Array.push && !Array.prototype.push) { 88 Array.prototype.push = function() 89 { 90 for (var i = 0, startLength = this.length; i < arguments.length; i++) { 91 this[startLength + i] = arguments[i]; 92 } 93 return this.length; 94 } 95} 96if (!Array.pop && !Array.prototype.pop) { 97 Array.prototype.pop = function() 98 { 99 return this.splice(this.length - 1, 1)[0]; 100 } 101} 102if (window.ActiveXObject && window['DOMParser'] == 'undefined') { 103 window.DOMParser = new function() {}; 104 DOMParser.prototype = { 105 parseFromString: function(str, contentType) { 106 var xmlDocument = new ActiveXObject('Microsoft.XMLDOM'); 107 xmlDocument.loadXML(str); 108 return xmlDocument; 109 } 110 }; 111 112 window.XMLSerializer = new function() {}; 113 XMLSerializer.prototype = { 114 serializeToString: function(root) { 115 return root.xml || root.outerHTML; 116 } 117 }; 118} 119// Main.js 120/** 121 * JavaScript library for use with HTML_AJAX 122 * 123 * This library is free software; you can redistribute it and/or 124 * modify it under the terms of the GNU Lesser General Public 125 * License as published by the Free Software Foundation; either 126 * version 2.1 of the License, or (at your option) any later version. 127 * 128 * This library is distributed in the hope that it will be useful, 129 * but WITHOUT ANY WARRANTY; without even the implied warranty of 130 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 131 * Lesser General Public License for more details. 132 * 133 * You should have received a copy of the GNU Lesser General Public 134 * License along with this library; if not, write to:
135 * Free Software Foundation, Inc., 136 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 137 * 138 * @category HTML 139 * @package Ajax 140 * @author Joshua Eichorn <[email protected]> 141 * @author Arpad Ray <[email protected]> 142 * @author David Coallier <[email protected]> 143 * @author Elizabeth Smith <[email protected]> 144 * @copyright 2005 Joshua Eichorn, Arpad Ray, David Coallier, Elizabeth Smith 145 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 146 */ 147 148/** 149 * HTML_AJAX static methods, this is the main proxyless api, it also handles global error and event handling 150 */ 151var HTML_AJAX = { 152 version: '0.5.6', 153 defaultServerUrl: false, 154 defaultEncoding: 'JSON', 155 queues: false, 156 clientPools: {}, 157 // get an HttpClient, supply a name to use the pool of that name or the default if it isn't found 158 httpClient: function(name) { 159 if (name) { 160 if (this.clientPools[name]) { 161 return this.clientPools[name].getClient(); 162 } 163 } 164 return this.clientPools['default'].getClient(); 165 }, 166 // Pushing the given request to queue specified by it, in default operation this will immediately make a request 167 // request might be delayed or never happen depending on the queue setup 168 // making a sync request to a non immediate queue will cause you problems so just don't do it 169 makeRequest: function(request) { 170 if (!HTML_AJAX.queues[request.queue]) { 171 var e = new Error('Unknown Queue: '+request.queue); 172 if (HTML_AJAX.onError) { 173 HTML_AJAX.onError(e); 174 return false; 175 } 176 else { 177 throw(e); 178 } 179 } 180 else { 181 var qn = request.queue; 182 var q = HTML_AJAX.queues[qn]; 183 184 HTML_AJAX.queues[request.queue].addRequest(request); 185 return HTML_AJAX.queues[request.queue].processRequest(); 186 } 187 }, 188 // get a serializer object for a specific encoding 189 serializerForEncoding: function(encoding) { 190 for(var i in HTML_AJAX.contentTypeMap) { 191 if (encoding == HTML_AJAX.contentTypeMap[i] || encoding == i) { 192 return eval("new HTML_AJAX_Serialize_"+i+";"); 193 } 194 } 195 return new HTML_AJAX_Serialize_Null(); 196 }, 197 fullcall: function(url,encoding,className,method,callback,args, options) { 198 var serializer = HTML_AJAX.serializerForEncoding(encoding); 199 200 var request = new HTML_AJAX_Request(serializer); 201 if (callback) { 202 request.isAsync = true; 203 } 204 request.requestUrl = url; 205 request.className = className; 206 request.methodName = method; 207 request.callback = callback; 208 request.args = args; 209 if (options) { 210 for(var i in options) { 211 request[i] = options[i]; 212 } 213 if (options.grab) { 214 if (!request.args || !request.args.length) { 215 request.requestType = 'GET'; 216 } 217 } 218 } 219 220 return HTML_AJAX.makeRequest(request); 221 }, 222 callPhpCallback: function(phpCallback, jsCallback, url) { 223 var args = new Array(); 224 for (var i = 3; i < arguments.length; i++) { 225 args.push(arguments[i]); 226 } 227 if (HTML_AJAX_Util.getType(phpCallback[0]) == 'object') { 228 jsCallback(phpCallback[0][phpCallback[1]](args)); 229 return; 230 } 231 if (!url) { 232 url = HTML_AJAX.defaultServerUrl; 233 } 234 HTML_AJAX.fullcall(url, HTML_AJAX.defaultEncoding, 235 false, false, jsCallback, args, {phpCallback: phpCallback}); 236 }, 237 call: function(className,method,callback) { 238 var args = new Array(); 239 for(var i = 3; i < arguments.length; i++) { 240 args.push(arguments[i]); 241 } 242 return HTML_AJAX.fullcall(HTML_AJAX.defaultServerUrl,HTML_AJAX.defaultEncoding,className,method,callback,args); 243 }, 244 grab: function(url,callback,options) { 245 if (!options) { 246 options = {grab:true}; 247 } 248 else { 249 options['grab'] = true; 250 } 251 return HTML_AJAX.fullcall(url,'Null',false,null,callback, '', options); 252 }, 253 post: function(url,payload,callback,options) { 254 var serializer = 'Null'; 255 if (HTML_AJAX_Util.getType(payload) == 'object') { 256 serializer = 'Urlencoded'; 257 } 258 return HTML_AJAX.fullcall(url,serializer,false,null,callback, payload, options); 259 }, 260 replace: function(id) { 261 var callback = function(result) { 262 HTML_AJAX_Util.setInnerHTML(HTML_AJAX_Util.getElement(id),result); 263 } 264 if (arguments.length == 2) { 265 // grab replacement 266 HTML_AJAX.grab(arguments[1],callback); 267 } 268 else { 269 // call replacement 270 var args = new Array(); 271 for(var i = 3; i < arguments.length; i++) { 272 args.push(arguments[i]); 273 } 274 HTML_AJAX.fullcall(HTML_AJAX.defaultServerUrl,HTML_AJAX.defaultEncoding,arguments[1],arguments[2],callback,args, {grab:true}); 275 } 276 }, 277 append: function(id) { 278 var callback = function(result) { 279 HTML_AJAX_Util.setInnerHTML(HTML_AJAX_Util.getElement(id),result,'append'); 280 } 281 if (arguments.length == 2) { 282 // grab replacement 283 HTML_AJAX.grab(arguments[1],callback); 284 } 285 else { 286 // call replacement 287 var args = new Array(); 288 for(var i = 3; i < arguments.length; i++) { 289 args.push(arguments[i]); 290 } 291 HTML_AJAX.fullcall(HTML_AJAX.defaultServerUrl,HTML_AJAX.defaultEncoding,arguments[1],arguments[2],callback,args, {grab:true}); 292 } 293 }, 294 // override to add top level loading notification (start) 295 Open: function(request) { 296 }, 297 // override to add top level loading notification (finish) 298 Load: function(request) { 299 }, 300 /* 301 // A really basic error handler 302 onError: function(e) { 303 msg = ""; 304 for(var i in e) { 305 msg += i+':'+e[i]+"\n"; 306 } 307 alert(msg); 308 }, 309 */ 310 // Class postfix to content-type map 311 contentTypeMap: { 312 'JSON': 'application/json', 313 'Null': 'text/plain', 314 'Error': 'application/error', 315 'PHP': 'application/php-serialized', 316 'HA' : 'application/html_ajax_action', 317 'Urlencoded': 'application/x-www-form-urlencoded' 318 }, 319 // used internally to make queues work, override Load or onError to perform custom events when a request is complete 320 // fires on success and error 321 requestComplete: function(request,error) { 322 for(var i in HTML_AJAX.queues) { 323 if (HTML_AJAX.queues[i].requestComplete) { 324 HTML_AJAX.queues[i].requestComplete(request,error); 325 } 326 } 327 }, 328 329 // turns a form into a urlencoded string 330 formEncode: function(form, array_format) { 331 form = HTML_AJAX_Util.getElement(form); 332 var el, inpType, value, name; 333 var out = (array_format) ? {} : ''; 334 var inputTags = form.getElementsByTagName('INPUT'); 335 var selectTags = form.getElementsByTagName('SELECT'); 336 var buttonTags = form.getElementsByTagName('BUTTON'); 337 var textareaTags = form.getElementsByTagName('TEXTAREA'); 338 var arrayRegex = /(.+)%5B%5D/; 339
340 var validElement = function (element) { 341 if (!element || !element.getAttribute) { 342 return false; 343 } 344 el = element; 345 name = HTML_AJAX_Util.encodeUrl(el.getAttribute('name')); 346 if (!name) { 347 // no element name so skip 348 return false; 349 } 350 if (element.disabled) { 351 return false; 352 } 353 354 if (!array_format) { 355 value = HTML_AJAX_Util.encodeUrl(el.value); 356 } else { 357 value = el.value; 358 } 359 360 inpType = el.getAttribute('type'); 361 return true; 362 } 363 364 inputLoop: 365 for (var i=0; i < inputTags.length; i++) { 366 if (!validElement(inputTags[i])) { 367 continue; 368 } 369 if (inpType == 'checkbox' || inpType == 'radio') { 370 if (!el.checked) { 371 // unchecked radios/checkboxes don't get submitted 372 continue inputLoop; 373 } 374 var arr_var = arrayRegex.exec(name); 375 if (array_format && arr_var) { 376 if (!out[arr_var[1]]) { 377 out[arr_var[1]] = new Array(); 378 } 379 out[arr_var[1]].push(value); 380 continue inputLoop; 381 } 382 } 383 // add element to output array 384 if (array_format) { 385 out[name] = value; 386 } else { 387 out += name + '=' + value + '&'; 388 } 389 } // end inputLoop 390 391 selectLoop: 392 for (var i=0; i<selectTags.length; i++) { 393 if (!validElement(selectTags[i])) { 394 continue selectLoop; 395 } 396 var options = el.options; 397 for (var z=0; z<options.length; z++){ 398 var option=options[z]; 399 if(option.selected){ 400 if (array_format) { 401 if (el.type == 'select-one') { 402 out[name] = option.value; 403 //only one item can be selected 404 continue selectLoop; 405 } else { 406 if (!out[name]) { 407 out[name] = new Array(); 408 } 409 out[name].push(option.value); 410 } 411 } else { 412 out += name + '=' + option.value + '&'; 413 if (el.type == 'select-one') { 414 continue selectLoop; 415 } 416 } 417 } 418 } 419 } // end selectLoop 420 421 buttonLoop: 422 for (var i=0; i<buttonTags.length; i++) { 423 if (!validElement(buttonTags[i])) { 424 continue; 425 } 426 // add element to output array
427 if (array_format) { 428 out[name] = value; 429 } else { 430 out += name + '=' + value + '&'; 431 } 432 } // end buttonLoop 433 434 textareaLoop: 435 for (var i=0; i<textareaTags.length; i++) { 436 if (!validElement(textareaTags[i])) { 437 continue; 438 } 439 // add element to output array 440 if (array_format) { 441 out[name] = value; 442 } else { 443 out += name + '=' + value + '&'; 444 } 445 } // end textareaLoop 446 447 return out; 448 }, 449 // submits a form through ajax. both arguments can be either DOM nodes or IDs, if the target is omitted then the form is set to be the target 450 formSubmit: function (form, target, options) 451 { 452 form = HTML_AJAX_Util.getElement(form); 453 if (!form) { 454 // let the submit be processed normally 455 return false; 456 } 457 458 var out = HTML_AJAX.formEncode(form); 459 target = HTML_AJAX_Util.getElement(target); 460 if (!target) { 461 target = form; 462 } 463 try 464 { 465 var action = form.attributes['action'].value; 466 } 467 catch(e){} 468 if(action == undefined) 469 { 470 action = form.getAttribute('action'); 471 } 472 473 var callback = false; 474 if (HTML_AJAX_Util.getType(target) == 'function') { 475 callback = target; 476 } 477 else { 478 callback = function(result) { 479 // result will be undefined if HA_Action is returned, so skip the replace 480 if (typeof result != 'undefined') { 481 HTML_AJAX_Util.setInnerHTML(target,result); 482 } 483 } 484 } 485 486 var serializer = HTML_AJAX.serializerForEncoding('Null'); 487 var request = new HTML_AJAX_Request(serializer); 488 request.isAsync = true; 489 request.callback = callback; 490 491 switch (form.getAttribute('method').toLowerCase()) { 492 case 'post': 493 var headers = {}; 494 headers['Content-Type'] = 'application/x-www-form-urlencoded'; 495 request.customHeaders = headers; 496 request.requestType = 'POST'; 497 request.requestUrl = action; 498 request.args = out; 499 break; 500 default: 501 if (action.indexOf('?') == -1) { 502 out = '?' + out.substr(0, out.length - 1); 503 } 504 request.requestUrl = action+out; 505 request.requestType = 'GET'; 506 } 507 508 if(options) { 509 for(var i in options) { 510 request[i] = options[i]; 511 } 512 } 513 514 if (request.isAsync == false) { 515 return HTML_AJAX.makeRequest(request); 516 } 517 else { 518 HTML_AJAX.makeRequest(request); 519 return true; 520 } 521 }, // end formSubmit() 522 makeFormAJAX: function(form,target,options) { 523 form = HTML_AJAX_Util.getElement(form); 524 var preSubmit = false; 525 if(typeof form.onsubmit != 'undefined') { 526 preSubmit = form.onsubmit; 527 form.onsubmit = function() {}; 528 } 529 form.HAOptions = options; 530 var handler = function(e) { 531 var form = HTML_AJAX_Util.eventTarget(e); 532 533 var valid = true; 534 if (preSubmit) { 535 valid = preSubmit(); 536 } 537 if (valid) { 538 HTML_AJAX.formSubmit(form,target,form.HAOptions); 539 } 540 // cancel submission in IE 541 e.returnValue = false; 542 // cancel submission in FF 543 if (e.preventDefault) { 544 e.preventDefault(); 545 } 546 } 547 HTML_AJAX_Util.registerEvent(form,'submit',handler); 548 } 549} 550 551 552 553 554// small classes that I don't want to put in there own file 555 556function HTML_AJAX_Serialize_Null() {} 557HTML_AJAX_Serialize_Null.prototype = { 558 contentType: 'text/plain; charset=utf-8', 559 serialize: function(input) { 560 return new String(input).valueOf(); 561 }, 562 563 unserialize: function(input) { 564 return new String(input).valueOf(); 565 } 566} 567 568function HTML_AJAX_Serialize_XML() {} 569HTML_AJAX_Serialize_XML.prototype = { 570 contentType: 'application/xml; charset=utf-8', 571 serialize: function(input) { 572 var xml = ''; 573 if(typeof(input) == 'object' && input) 574 { 575 for (var i = 0;i<input.length;i++) 576 { 577 xml += new XMLSerializer().serializeToString(input[i]); 578 } 579 } 580 return xml; 581 }, 582 583 unserialize: function(input) { 584 return input; 585 } 586} 587 588// serialization class for JSON, wrapper for JSON.stringify in json.js 589function HTML_AJAX_Serialize_JSON() {} 590HTML_AJAX_Serialize_JSON.prototype = { 591 contentType: 'application/json; charset=utf-8', 592 serialize: function(input) { 593 return HTML_AJAX_JSON.stringify(input); 594 }, 595 unserialize: function(input) { 596 try { 597 return eval('('+input+')'); 598 } catch(e) { 599 // sometimes JSON encoded input isn't created properly, if eval of it fails we use the more forgiving but slower parser so will at least get something 600 return HTML_AJAX_JSON.parse(input); 601 } 602 } 603} 604 605function HTML_AJAX_Serialize_Error() {} 606HTML_AJAX_Serialize_Error.prototype = { 607 contentType: 'application/error; charset=utf-8', 608 serialize: function(input) { 609 var ser = new HTML_AJAX_Serialize_JSON(); 610 return ser.serialize(input); 611 }, 612 unserialize: function(input) { 613 var ser = new HTML_AJAX_Serialize_JSON(); 614 var data = new ser.unserialize(input); 615 616 var e = new Error('PHP Error: '+data.errStr); 617 for(var i in data) { 618 e[i] = data[i]; 619 } 620 throw e; 621 } 622} 623 624// Processing Queues 625 626// simple queue, just processes the request immediately 627function HTML_AJAX_Queue_Immediate() {} 628HTML_AJAX_Queue_Immediate.prototype = { 629 request: false, 630 addRequest: function(request) { 631 this.request = request; 632 }, 633 processRequest: function() { 634 var client = HTML_AJAX.httpClient(); 635 client.request = this.request;
636 return client.makeRequest(); 637 } 638} 639 640 641 642// create a default queue, has to happen after the Queue class has been defined 643HTML_AJAX.queues = new Object(); 644HTML_AJAX.queues['default'] = new HTML_AJAX_Queue_Immediate(); 645 646// Queue.js 647/** 648 * Various processing queues, use when you want to control how multiple requests are made 649 * @category HTML 650 * @package AJAX 651 * @author Joshua Eichorn <[email protected]> 652 * @copyright 2005 Joshua Eichorn 653 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 654 */ 655 656// Single Buffer queue with interval 657// works by attempting to send a request every x miliseconds 658// if an item is currently in the queue when a new item is added it will be replaced 659// simple queue, just processes the request immediately 660// the first request starts the interval timer 661function HTML_AJAX_Queue_Interval_SingleBuffer(interval,singleOutstandingRequest) { 662 this.interval = interval; 663 if (singleOutstandingRequest) { 664 this.singleOutstandingRequest = true; 665 } 666} 667HTML_AJAX_Queue_Interval_SingleBuffer.prototype = { 668 request: false, 669 _intervalId: false, 670 singleOutstandingRequest: false, 671 client: false, 672 addRequest: function(request) { 673 this.request = request; 674 }, 675 processRequest: function() { 676 if (!this._intervalId) { 677 this.runInterval(); 678 this.start(); 679 } 680 }, 681 start: function() { 682 var self = this; 683 this._intervalId = setInterval(function() { self.runInterval() },this.interval); 684 }, 685 stop: function() { 686 clearInterval(this._intervalId); 687 }, 688 runInterval: function() { 689 if (this.request) { 690 if (this.singleOutstandingRequest && this.client) { 691 this.client.abort(); 692 } 693 this.client = HTML_AJAX.httpClient(); 694 this.client.request = this.request; 695 this.request = false; 696 this.client.makeRequest(); 697 } 698 } 699} 700 701// Requests return in the same order they were called 702// this helps handle high latency situations 703function HTML_AJAX_Queue_Ordered() { } 704HTML_AJAX_Queue_Ordered.prototype = { 705 request: false, 706 order: 0, 707 current: 0, 708 callbacks: {}, 709 interned: {}, 710 addRequest: function(request) { 711 request.order = this.order; 712 this.request = request; 713 this.callbacks[this.order] = this.request.callback; 714 var self = this; 715 this.request.callback = function(result) { 716 self.processCallback(result,request.order); 717 } 718 }, 719 processRequest: function() { 720 var client = HTML_AJAX.httpClient(); 721 client.request = this.request; 722 client.makeRequest(); 723 this.order++; 724 }, 725 requestComplete: function(request,e) { 726 // something when wrong with the request lets stop waiting for it 727 if (e) { 728 this.current++; 729 } 730 }, 731 processCallback: function(result,order) { 732 if (order == this.current) { 733 this.callbacks[order](result); 734 this.current++; 735 } 736 else { 737 this.interned[order] = result; 738 } 739 while (this.interned[this.current]) { 740 this.callbacks[this.current](this.interned[this.current]); 741 this.current++; 742 } 743} 744} 745 746// Make a single request at once, canceling and currently outstanding requests when a new one is made 747function HTML_AJAX_Queue_Single() { 748} 749HTML_AJAX_Queue_Single.prototype = { 750 request: false, 751 client: false, 752 addRequest: function(request) { 753 this.request = request; 754 }, 755 processRequest: function() { 756 if (this.request) { 757 if (this.client) { 758 this.client.abort(); 759 } 760 this.client = HTML_AJAX.httpClient(); 761 this.client.request = this.request; 762 this.request = false; 763 this.client.makeRequest(); 764 } 765 } 766} 767 768/** 769 * Priority queue 770 * 771 * @author Arpad Ray <[email protected]> 772 */ 773function HTML_AJAX_Queue_Priority_Item(item, time) { 774 this.item = item; 775 this.time = time; 776} 777HTML_AJAX_Queue_Priority_Item.prototype = { 778 compareTo: function (other) { 779 var ret = this.item.compareTo(other.item); 780 if (ret == 0) { 781 ret = this.time - other.time; 782 } 783 return ret; 784 } 785} 786 787function HTML_AJAX_Queue_Priority_Simple(interval) { 788 this.interval = interval; 789 this.idleMax = 10; // keep the interval going with an empty queue for 10 intervals 790 this.requestTimeout = 5; // retry uncompleted requests after 5 seconds 791 this.checkRetryChance = 0.1; // check for uncompleted requests to retry on 10% of intervals 792 this._intervalId = 0; 793 this._requests = []; 794 this._removed = []; 795 this._len = 0; 796 this._removedLen = 0; 797 this._idle = 0; 798} 799HTML_AJAX_Queue_Priority_Simple.prototype = { 800 isEmpty: function () { 801 return this._len == 0; 802 }, 803 addRequest: function (request) { 804 request = new HTML_AJAX_Queue_Priority_Item(request, new Date().getTime()); 805 ++this._len; 806 if (this.isEmpty()) { 807 this._requests[0] = request; 808 return; 809 } 810 for (i = 0; i < this._len - 1; i++) { 811 if (request.compareTo(this._requests[i]) < 0) { 812 this._requests.splice(i, 1, request, this._requests[i]); 813 return; 814 } 815 } 816 this._requests.push(request); 817 }, 818 peek: function () { 819 return (this.isEmpty() ? false : this._requests[0]); 820 }, 821 requestComplete: function (request) { 822 for (i = 0; i < this._removedLen; i++) { 823 if (this._removed[i].item == request) { 824 this._removed.splice(i, 1); 825 --this._removedLen; 826 out('removed from _removed'); 827 return true; 828 } 829 } 830 return false;
831 }, 832 processRequest: function() { 833 if (!this._intervalId) { 834 this._runInterval(); 835 this._start(); 836 } 837 this._idle = 0; 838 }, 839 _runInterval: function() { 840 if (Math.random() < this.checkRetryChance) { 841 this._doRetries(); 842 } 843 if (this.isEmpty()) { 844 if (++this._idle > this.idleMax) { 845 this._stop(); 846 } 847 return; 848 } 849 var client = HTML_AJAX.httpClient(); 850 if (!client) { 851 return; 852 } 853 var request = this.peek(); 854 if (!request) { 855 this._requests.splice(0, 1); 856 return; 857 } 858 client.request = request.item; 859 client.makeRequest(); 860 this._requests.splice(0, 1); 861 --this._len; 862 this._removed[this._removedLen++] = new HTML_AJAX_Queue_Priority_Item(request, new Date().getTime()); 863 }, 864 _doRetries: function () { 865 for (i = 0; i < this._removedLen; i++) { 866 if (this._removed[i].time + this._requestTimeout < new Date().getTime()) { 867 this.addRequest(request.item); 868 this._removed.splice(i, 1); 869 --this._removedLen; 870 return true; 871 } 872 } 873 }, 874 _start: function() { 875 var self = this; 876 this._intervalId = setInterval(function() { self._runInterval() }, this.interval); 877 }, 878 _stop: function() { 879 clearInterval(this._intervalId); 880 this._intervalId = 0; 881 } 882}; 883// clientPool.js 884HTML_AJAX_Client_Pool = function(maxClients, startingClients) 885{ 886 this.maxClients = maxClients; 887 this._clients = []; 888 this._len = 0; 889 while (--startingClients > 0) { 890 this.addClient(); 891 } 892} 893 894HTML_AJAX_Client_Pool.prototype = { 895 isEmpty: function() 896 { 897 return this._len == 0; 898 }, 899 addClient: function() 900 { 901 if (this.maxClients != 0 && this._len > this.maxClients) { 902 return false; 903 } 904 var key = this._len++; 905 this._clients[key] = new HTML_AJAX_HttpClient(); 906 return this._clients[key]; 907 }, 908 getClient: function () 909 { 910 for (var i = 0; i < this._len; i++) { 911 if (!this._clients[i].callInProgress() && this._clients[i].callbackComplete) { 912 return this._clients[i]; 913 } 914 } 915 var client = this.addClient(); 916 if (client) { 917 return client; 918 } 919 return false; 920 }, 921 removeClient: function (client) 922 { 923 for (var i = 0; i < this._len; i++) { 924 if (!this._clients[i] == client) { 925 this._clients.splice(i, 1); 926 return true; 927 } 928 } 929 return false; 930 }, 931 clear: function () 932 { 933 this._clients = []; 934 this._len = 0; 935 } 936}; 937 938// create a default client pool with unlimited clients 939HTML_AJAX.clientPools['default'] = new HTML_AJAX_Client_Pool(0); 940// IframeXHR.js 941/** 942 * XMLHttpRequest Iframe fallback 943 * 944 * http://lxr.mozilla.org/seamonkey/source/extensions/xmlextras/tests/ - should work with these 945 * 946 * @category HTML 947 * @package AJAX 948 * @author Elizabeth Smith <[email protected]> 949 * @copyright 2005 Elizabeth Smith 950 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 951 */ 952HTML_AJAX_IframeXHR_instances = new Object(); 953function HTML_AJAX_IframeXHR() 954{ 955 this._id = 'HAXHR_iframe_' + new Date().getTime(); 956 HTML_AJAX_IframeXHR_instances[this._id] = this; 957} 958HTML_AJAX_IframeXHR.prototype = { 959// Data not sent with text/xml Content-Type will only be available via the responseText property 960 961 // properties available in safari/mozilla/IE xmlhttprequest object 962 onreadystatechange: null, // Event handler for an event that fires at every state change 963 readyState: 0, // Object status integer: 0 = uninitialized 1 = loading 2 = loaded 3 = interactive 4 = complete 964 responseText: '', // String version of data returned from server process 965 responseXML: null, // DOM-compatible document object of data returned from server process 966 status: 0, // Numeric code returned by server, such as 404 for "Not Found" or 200 for "OK" 967 statusText: '', // String message accompanying the status code 968 iframe: true, // flag for iframe 969 970 //these are private properties used internally to keep track of stuff 971 _id: null, // iframe id, unique to object(hopefully) 972 _url: null, // url sent by open 973 _method: null, // get or post 974 _async: null, // sync or async sent by open 975 _headers: new Object(), //request headers to send, actually sent as form vars 976 _response: new Object(), //response headers received 977 _phpclass: null, //class to send 978 _phpmethod: null, //method to send 979 _history: null, // opera has to have history munging 980 981 // Stops the current request 982 abort: function() 983 { 984 var iframe = document.getElementById(this._id); 985 if (iframe) { 986 document.body.removeChild(iframe); 987 } 988 if (this._timeout) { 989 window.clearTimeout(this._timeout); 990 } 991 this.readyState = 1; 992 if (typeof(this.onreadystatechange) == "function") { 993 this.onreadystatechange(); 994 } 995 }, 996 997 // This will send all headers in this._response and will include lastModified and contentType if not already set 998 getAllResponseHeaders: function() 999 { 1000 var string = ''; 1001 for (i in this._response) { 1002 string += i + ' : ' + this._response[i] + "\n"; 1003 } 1004 return string; 1005 }, 1006 1007 // This will use lastModified and contentType if they're not set 1008 getResponseHeader: function(header) 1009 { 1010 return (this._response[header] ? this._response[header] : null); 1011 }, 1012 1013 // Assigns a label/value pair to the header to be sent with a request 1014 setRequestHeader: function(label, value) { 1015 this._headers[label] = value; 1016 return; }, 1017 1018 // Assigns destination URL, method, and other optional attributes of a pending request 1019 open: function(method, url, async, username, password) 1020 { 1021 if (!document.body) { 1022 throw('CANNOT_OPEN_SEND_IN_DOCUMENT_HEAD'); 1023 } 1024 //exceptions for not enough arguments 1025 if (!method || !url) { 1026 throw('NOT_ENOUGH_ARGUMENTS:METHOD_URL_REQUIRED'); 1027 } 1028 //get and post are only methods accepted 1029 this._method = (method.toUpperCase() == 'POST' ? 'POST' : 'GET'); 1030 this._decodeUrl(url); 1031 this._async = async; 1032 if(!this._async && document.readyState && !window.opera) { 1033 throw('IE_DOES_NOT_SUPPORT_SYNC_WITH_IFRAMEXHR'); 1034 } 1035 //set status to loading and call onreadystatechange 1036 this.readyState = 1; 1037 if(typeof(this.onreadystatechange) == "function") { 1038 this.onreadystatechange(); 1039 } 1040 }, 1041
1042 // Transmits the request, optionally with postable string or DOM object data 1043 send: function(content) 1044 { 1045 //attempt opera history munging 1046 if (window.opera) { 1047 this._history = window.history.length; 1048 } 1049 //create a "form" for the contents of the iframe 1050 var form = '<html><body><form method="' 1051 + (this._url.indexOf('px=') < 0 ? this._method : 'post') 1052 + '" action="' + this._url + '">'; 1053 //tell iframe unwrapper this IS an iframe 1054 form += '<input name="Iframe_XHR" value="1" />'; 1055 //class and method 1056 if (this._phpclass != null) { 1057 form += '<input name="Iframe_XHR_class" value="' + this._phpclass + '" />'; 1058 } 1059 if (this._phpmethod != null) { 1060 form += '<input name="Iframe_XHR_method" value="' + this._phpmethod + '" />'; 1061 } 1062 // fake headers 1063 for (label in this._headers) { 1064 form += '<textarea name="Iframe_XHR_headers[]">' + label +':'+ this._headers[label] + '</textarea>'; 1065 } 1066 // add id 1067 form += '<textarea name="Iframe_XHR_id">' + this._id + '</textarea>'; 1068 if (content != null && content.length > 0) { 1069 form += '<textarea name="Iframe_XHR_data">' + content + '</textarea>'; 1070 } 1071 form += '<input name="Iframe_XHR_HTTP_method" value="' + this._method + '" />'; 1072 form += '<s'+'cript>document.forms[0].submit();</s'+'cript></form></body></html>'; 1073 form = "javascript:document.write('" + form.replace(/\'/g,"\\'") + "');void(0);"; 1074 this.readyState = 2; 1075 if (typeof(this.onreadystatechange) == "function") { 1076 this.onreadystatechange(); 1077 } 1078 // try to create an iframe with createElement and append node 1079 try { 1080 var iframe = document.createElement('iframe'); 1081 iframe.id = this._id; 1082 // display: none will fail on some browsers 1083 iframe.style.visibility = 'hidden'; 1084 // for old browsers with crappy css 1085 iframe.style.border = '0'; 1086 iframe.style.width = '0'; 1087 iframe.style.height = '0'; 1088 1089 if (document.all) { 1090 // MSIE, opera 1091 iframe.src = form; 1092 document.body.appendChild(iframe); 1093 } else { 1094 document.body.appendChild(iframe); 1095 iframe.src = form; 1096 } 1097 } catch(exception) { 1098 // dom failed, write the sucker manually 1099 var html = '<iframe src="' + form +'" id="' + this._id + '" style="visibility:hidden;border:0;height:0;width:0;"></iframe>'; 1100 document.body.innerHTML += html; 1101 } 1102 if (this._async == true) { 1103 //avoid race state if onload is called first 1104 if (this.readyState < 3) { 1105 this.readyState = 3; 1106 if(typeof(this.onreadystatechange) == "function") { 1107 this.onreadystatechange(); 1108 } 1109 } 1110 } else { 1111 //we force a while loop for sync, it's ugly but hopefully it works 1112 while (this.readyState != 4) { 1113 //just check to see if we can up readyState 1114 if (this.readyState < 3) { 1115 this.readyState = 3; 1116 if(typeof(this.onreadystatechange) == "function") { 1117 this.onreadystatechange(); 1118 } 1119 } 1120 } 1121 } 1122 }, 1123 1124 // attached as an onload function to the iframe to trigger when we're done 1125 isLoaded: function(headers, data) 1126 { 1127 this.readyState = 4; 1128 //set responseText, Status, StatusText 1129 this.status = 200; 1130 this.statusText = 'OK'; 1131 this.responseText = data; 1132 this._response = headers; 1133 if (!this._response['Last-Modified']) { 1134 string += 'Last-Modified : ' + document.getElementById(this._id).lastModified + "\n"; 1135 } 1136 if (!this._response['Content-Type']) { 1137 string += 'Content-Type : ' + document.getElementById(this._id).contentType + "\n"; 1138 } 1139 // if this is xml populate responseXML accordingly 1140 if (this._response['Content-Type'] == 'application/xml') 1141 { 1142 return new DOMParser().parseFromString(this.responseText, 'application/xml'); 1143 } 1144 //attempt opera history munging in opera 8+ - this is a REGRESSION IN OPERA 1145 if (window.opera && window.opera.version) { 1146 //go back current history - old history 1147 window.history.go(this._history - window.history.length); 1148 } 1149 if (typeof(this.onreadystatechange) == "function") { 1150 this.onreadystatechange(); 1151 } 1152 document.body.removeChild(document.getElementById(this._id)); 1153 }, 1154 1155 // strip off the c and m from the url send...yuck 1156 _decodeUrl: function(querystring) 1157 { 1158 //opera 7 is too stupid to do a relative url...go figure 1159 var url = unescape(location.href); 1160 url = url.substring(0, url.lastIndexOf("/") + 1); 1161 var item = querystring.split('?'); 1162 //rip off any path info and append to path above <- relative paths (../) WILL screw this 1163 this._url = url + item[0].substring(item[0].lastIndexOf("/") + 1,item[0].length); 1164 if(item[1]) { 1165 item = item[1].split('&'); 1166 for (i in item) { 1167 var v = item[i].split('='); 1168 if (v[0] == 'c') { 1169 this._phpclass = v[1]; 1170 } else if (v[0] == 'm') { 1171 this._phpmethod = v[1]; 1172 } 1173 } 1174 } 1175 if (!this._phpclass || !this._phpmethod) { 1176 var cloc = window.location.href; 1177 this._url = cloc + (cloc.indexOf('?') >= 0 ? '&' : '?') + 'px=' + escape(HTML_AJAX_Util.absoluteURL(querystring)); 1178 } 1179 } 1180}
1181// serializer/UrlSerializer.js 1182// {{{ HTML_AJAX_Serialize_Urlencoded 1183/** 1184 * URL-encoding serializer 1185 * 1186 * This class can be used to serialize and unserialize data in a 1187 * format compatible with PHP's handling of HTTP query strings. 1188 * Due to limitations of the format, all input is serialized as an 1189 * array or a string. See examples/serialize.url.examples.php 1190 * 1191 * @version 0.0.1 1192 * @copyright 2005 Arpad Ray <[email protected]> 1193 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 1194 * 1195 * See Main.js for Author/license details 1196 */ 1197function HTML_AJAX_Serialize_Urlencoded() {} 1198HTML_AJAX_Serialize_Urlencoded.prototype = { 1199 contentType: 'application/x-www-form-urlencoded; charset=UTF-8', 1200 base: '_HTML_AJAX', 1201 _keys: [], 1202 error: false, 1203 message: "", 1204 cont: "", 1205 // {{{ serialize 1206 /** 1207 * Serializes a variable 1208 * 1209 * @param mixed inp the variable to serialize 1210 * @return string a string representation of the input, 1211 * which can be reconstructed by unserialize() 1212 */ 1213 serialize: function(input, _internal) { 1214 if (typeof input == 'undefined') { 1215 return ''; 1216 } 1217 if (!_internal) { 1218 this._keys = []; 1219 } 1220 var ret = '', first = true; 1221 for (i = 0; i < this._keys.length; i++) { 1222 ret += (first ? HTML_AJAX_Util.encodeUrl(this._keys[i]) : '[' + HTML_AJAX_Util.encodeUrl(this._keys[i]) + ']'); 1223 first = false; 1224 } 1225 ret += '='; 1226 switch (HTML_AJAX_Util.getType(input)) { 1227 case 'string': 1228 case 'number': 1229 ret += HTML_AJAX_Util.encodeUrl(input.toString()); 1230 break; 1231 case 'boolean': 1232 ret += (input ? '1' : '0'); 1233 break; 1234 case 'array': 1235 case 'object': 1236 ret = ''; 1237 for (i in input) { 1238 this._keys.push(i); 1239 ret += this.serialize(input[i], true) + '&'; 1240 this._keys.pop(); 1241 } 1242 ret = ret.substr(0, ret.length - 1); 1243 } 1244 return ret; 1245 }, 1246 // }}} 1247 // {{{ unserialize 1248 /** 1249 * Reconstructs a serialized variable 1250 * 1251 * @param string inp the string to reconstruct 1252 * @return array an array containing the variable represented by the input string, or void on failure 1253 */ 1254 unserialize: function(input) { 1255 if (!input.length || input.length == 0) { 1256 // null 1257 return; 1258 } 1259 if (!/^(\w+(\[[^\[\]]*\])*=[^&]*(&|$))+$/.test(input)) { 1260 this.raiseError("invalidly formed input", input); 1261 return; 1262 } 1263 input = input.split("&"); 1264 var pos, key, keys, val, _HTML_AJAX = []; 1265 if (input.length == 1) { 1266 return HTML_AJAX_Util.decodeUrl(input[0].substr(this.base.length + 1)); 1267 } 1268 for (var i in input) { 1269 pos = input[i].indexOf("="); 1270 if (pos < 1 || input[i].length - pos - 1 < 1) { 1271 this.raiseError("input is too short", input[i]); 1272 return; 1273 } 1274 key = HTML_AJAX_Util.decodeUrl(input[i].substr(0, pos)); 1275 val = HTML_AJAX_Util.decodeUrl(input[i].substr(pos + 1)); 1276 key = key.replace(/\[((\d*\D+)+)\]/g, '["$1"]'); 1277 keys = key.split(']'); 1278 for (j in keys) { 1279 if (!keys[j].length || keys[j].length == 0) { 1280 continue; 1281 } 1282 try { 1283 if (eval('typeof ' + keys[j] + ']') == 'undefined') { 1284 var ev = keys[j] + ']=[];'; 1285 eval(ev); 1286 } 1287 } catch (e) { 1288 this.raiseError("error evaluating key", ev); 1289 return; 1290 } 1291 } 1292 try { 1293 eval(key + '="' + val + '";'); 1294 } catch (e) { 1295 this.raiseError("error evaluating value", input); 1296 return; 1297 } 1298 } 1299 return _HTML_AJAX; 1300 }, 1301 // }}} 1302 // {{{ getError 1303 /** 1304 * Gets the last error message 1305 * 1306 * @return string the last error message from unserialize() 1307 */ 1308 getError: function() { 1309 return this.message + "\n" + this.cont; 1310 }, 1311 // }}} 1312 // {{{ raiseError 1313 /** 1314 * Raises an eror (called by unserialize().) 1315 * 1316 * @param string message the error message 1317 * @param string cont the remaining unserialized content 1318 */ 1319 raiseError: function(message, cont) { 1320 this.error = 1; 1321 this.message = message; 1322 this.cont = cont; 1323 } 1324 // }}} 1325} 1326// }}}
1327// serializer/phpSerializer.js 1328// {{{ HTML_AJAX_Serialize_PHP 1329/** 1330 * PHP serializer 1331 * 1332 * This class can be used to serialize and unserialize data in a 1333 * format compatible with PHP's native serialization functions. 1334 * 1335 * @version 0.0.3 1336 * @copyright 2005 Arpad Ray <[email protected]> 1337 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 1338 * 1339 * See Main.js for Author/license details 1340 */ 1341 1342function HTML_AJAX_Serialize_PHP() {} 1343HTML_AJAX_Serialize_PHP.prototype = { 1344 error: false, 1345 message: "", 1346 cont: "", 1347 defaultEncoding: 'UTF-8', 1348 contentType: 'application/php-serialized; charset: UTF-8', 1349 // {{{ serialize 1350 /** 1351 * Serializes a variable 1352 * 1353 * @param mixed inp the variable to serialize 1354 * @return string a string representation of the input, 1355 * which can be reconstructed by unserialize() 1356 * @author Arpad Ray <[email protected]> 1357 * @author David Coallier <[email protected]> 1358 */ 1359 serialize: function(inp) { 1360 var type = HTML_AJAX_Util.getType(inp); 1361 var val; 1362 switch (type) { 1363 case "undefined": 1364 val = "N"; 1365 break; 1366 case "boolean": 1367 val = "b:" + (inp ? "1" : "0"); 1368 break; 1369 case "number": 1370 val = (Math.round(inp) == inp ? "i" : "d") + ":" + inp; 1371 break; 1372 case "string": 1373 val = "s:" + inp.length + ":\"" + inp + "\""; 1374 break; 1375 case "array": 1376 val = "a"; 1377 case "object": 1378 if (type == "object") { 1379 var objname = inp.constructor.toString().match(/(\w+)\(\)/); 1380 if (objname == undefined) { 1381 return; 1382 } 1383 objname[1] = this.serialize(objname[1]); 1384 val = "O" + objname[1].substring(1, objname[1].length - 1); 1385 } 1386 var count = 0; 1387 var vals = ""; 1388 var okey; 1389 for (key in inp) { 1390 okey = (key.match(/^[0-9]+$/) ? parseInt(key) : key); 1391 vals += this.serialize(okey) + 1392 this.serialize(inp[key]); 1393 count++; 1394 } 1395 val += ":" + count + ":{" + vals + "}"; 1396 break; 1397 } 1398 if (type != "object" && type != "array") val += ";"; 1399 return val; 1400 }, 1401 // }}} 1402 // {{{ unserialize 1403 /** 1404 * Reconstructs a serialized variable 1405 * 1406 * @param string inp the string to reconstruct 1407 * @return mixed the variable represented by the input string, or void on failure 1408 */ 1409 unserialize: function(inp) { 1410 this.error = 0; 1411 if (inp == "" || inp.length < 2) { 1412 this.raiseError("input is too short"); 1413 return; 1414 } 1415 var val, kret, vret, cval; 1416 var type = inp.charAt(0); 1417 var cont = inp.substring(2); 1418 var size = 0, divpos = 0, endcont = 0, rest = "", next = ""; 1419 1420 switch (type) { 1421 case "N": // null 1422 if (inp.charAt(1) != ";") { 1423 this.raiseError("missing ; for null", cont); 1424 } 1425 // leave val undefined 1426 rest = cont; 1427 break; 1428 case "b": // boolean 1429 if (!/[01];/.test(cont.substring(0,2))) { 1430 this.raiseError("value not 0 or 1, or missing ; for boolean", cont); 1431 } 1432 val = (cont.charAt(0) == "1"); 1433 rest = cont.substring(1); 1434 break; 1435 case "s": // string 1436 val = ""; 1437 divpos = cont.indexOf(":"); 1438 if (divpos == -1) { 1439 this.raiseError("missing : for string", cont); 1440 break; 1441 } 1442 size = parseInt(cont.substring(0, divpos)); 1443 if (size == 0) { 1444 if (cont.length - divpos < 4) { 1445 this.raiseError("string is too short", cont); 1446 break; 1447 } 1448 rest = cont.substring(divpos + 4); 1449 break; 1450 } 1451 if ((cont.length - divpos - size) < 4) { 1452 this.raiseError("string is too short", cont); 1453 break; 1454 } 1455 if (cont.substring(divpos + 2 + size, divpos + 4 + size) != "\";") { 1456 this.raiseError("string is too long, or missing \";", cont); 1457 } 1458 val = cont.substring(divpos + 2, divpos + 2 + size); 1459 rest = cont.substring(divpos + 4 + size); 1460 break; 1461 case "i": // integer 1462 case "d": // float 1463 var dotfound = 0; 1464 for (var i = 0; i < cont.length; i++) { 1465 cval = cont.charAt(i); 1466 if (isNaN(parseInt(cval)) && !(type == "d" && cval == "." && !dotfound++)) { 1467 endcont = i; 1468 break; 1469 } 1470 } 1471 if (!endcont || cont.charAt(endcont) != ";") { 1472 this.raiseError("missing or invalid value, or missing ; for int/float", cont); 1473 } 1474 val = cont.substring(0, endcont); 1475 val = (type == "i" ? parseInt(val) : parseFloat(val)); 1476 rest = cont.substring(endcont + 1); 1477 break; 1478 case "a": // array 1479 if (cont.length < 4) { 1480 this.raiseError("array is too short", cont); 1481 return; 1482 } 1483 divpos = cont.indexOf(":", 1); 1484 if (divpos == -1) { 1485 this.raiseError("missing : for array", cont); 1486 return; 1487 } 1488 size = parseInt(cont.substring(0, divpos)); 1489 cont = cont.substring(divpos + 2); 1490 val = new Array(); 1491 if (cont.length < 1) { 1492 this.raiseError("array is too short", cont); 1493 return; 1494 } 1495 for (var i = 0; i < size; i++) { 1496 kret = this.unserialize(cont, 1); 1497 if (this.error || kret[0] == undefined || kret[1] == "") { 1498 this.raiseError("missing or invalid key, or missing value for array", cont); 1499 return; 1500 } 1501 vret = this.unserialize(kret[1], 1); 1502 if (this.error) { 1503 this.raiseError("invalid value for array", cont); 1504 return; 1505 } 1506 val[kret[0]] = vret[0]; 1507 cont = vret[1]; 1508 } 1509 if (cont.charAt(0) != "}") { 1510 this.raiseError("missing ending }, or too many values for array", cont); 1511 return; 1512 } 1513 rest = cont.substring(1); 1514 break; 1515 case "O": // object 1516 divpos = cont.indexOf(":"); 1517 if (divpos == -1) { 1518 this.raiseError("missing : for object", cont); 1519 return; 1520 } 1521 size = parseInt(cont.substring(0, divpos)); 1522 var objname = cont.substring(divpos + 2, divpos + 2 + size); 1523 if (cont.substring(divpos + 2 + size, divpos + 4 + size) != "\":") { 1524 this.raiseError("object name is too long, or missing \":", cont); 1525 return; 1526 } 1527 var objprops = this.unserialize("a:" + cont.substring(divpos + 4 + size), 1); 1528 if (this.error) { 1529 this.raiseError("invalid object properties", cont); 1530 return; 1531 } 1532 rest = objprops[1]; 1533 var objout = "function " + objname + "(){"; 1534 for (key in objprops[0]) { 1535 objout += "this." + key + "=objprops[0]['" + key + "'];"; 1536 } 1537 objout += "}val=new " + objname + "();"; 1538 eval(objout); 1539 break; 1540 default: 1541 this.raiseError("invalid input type", cont); 1542 } 1543 return (arguments.length == 1 ? val : [val, rest]); 1544 }, 1545 // }}} 1546 // {{{ getError 1547 /** 1548 * Gets the last error message 1549 * 1550 * @return string the last error message from unserialize() 1551 */ 1552 getError: function() { 1553 return this.message + "\n" + this.cont; 1554 }, 1555 // }}} 1556 // {{{ raiseError 1557 /** 1558 * Raises an eror (called by unserialize().) 1559 * 1560 * @param string message the error message 1561 * @param string cont the remaining unserialized content 1562 */ 1563 raiseError: function(message, cont) { 1564 this.error = 1; 1565 this.message = message; 1566 this.cont = cont; 1567 } 1568 // }}} 1569} 1570// }}} 1571 1572// Dispatcher.js 1573/** 1574 * Class that is used by generated stubs to make actual AJAX calls 1575 * 1576 * @category HTML 1577 * @package AJAX 1578 * @author Joshua Eichorn <[email protected]> 1579 * @copyright 2005 Joshua Eichorn 1580 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 1581 */ 1582function HTML_AJAX_Dispatcher(className,mode,callback,serverUrl,serializerType) 1583{ 1584 this.className = className; 1585 this.mode = mode; 1586 this.callback = callback; 1587 this.serializerType = serializerType; 1588 1589 if (serverUrl) { 1590 this.serverUrl = serverUrl 1591 } 1592 else { 1593 this.serverUrl = window.location; 1594 } 1595} 1596 1597HTML_AJAX_Dispatcher.prototype = { 1598 /** 1599 * Queue to use when making a request 1600 */ 1601 queue: 'default', 1602 1603 /** 1604 * Timeout for async calls 1605 */ 1606 timeout: 20000, 1607 1608 /** 1609 * Default request priority 1610 */ 1611 priority: 0, 1612 1613 /** 1614 * Request options 1615 */ 1616 options: {}, 1617 1618 /** 1619 * Make an ajax call 1620 * 1621 * @param string callName 1622 * @param Array args arguments to the report method 1623 */ 1624 doCall: function(callName,args) 1625 {
1626 var request = new HTML_AJAX_Request(); 1627 request.requestUrl = this.serverUrl; 1628 request.className = this.className; 1629 request.methodName = callName; 1630 request.timeout = this.timeout; 1631 request.contentType = this.contentType; 1632 request.serializer = eval('new HTML_AJAX_Serialize_'+this.serializerType); 1633 request.queue = this.queue; 1634 request.priority = this.priority; 1635 1636 for(var i in this.options) { 1637 request[i] = this.options[i]; 1638 } 1639 1640 for(var i=0; i < args.length; i++) { 1641 request.addArg(i,args[i]); 1642 }; 1643 1644 if ( this.mode == "async" ) { 1645 request.isAsync = true; 1646 if (this.callback[callName]) { 1647 var self = this; 1648 request.callback = function(result) { self.callback[callName](result); } 1649 } 1650 1651 } else { 1652 request.isAsync = false; 1653 } 1654 1655 return HTML_AJAX.makeRequest(request); 1656 }, 1657 1658 Sync: function() 1659 { 1660 this.mode = 'sync'; 1661 }, 1662 1663 Async: function(callback) 1664 { 1665 this.mode = 'async'; 1666 if (callback) { 1667 this.callback = callback; 1668 } 1669 } 1670}; 1671// HttpClient.js 1672/** 1673 * XMLHttpRequest Wrapper 1674 * @category HTML 1675 * @package AJAX 1676 * @author Joshua Eichorn <[email protected]> 1677 * @copyright 2005 Joshua Eichorn 1678 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 1679 */ 1680function HTML_AJAX_HttpClient() { } 1681HTML_AJAX_HttpClient.prototype = { 1682 // request object 1683 request: null, 1684 1685 // timeout id 1686 _timeoutId: null, 1687 1688 callbackComplete: true, 1689 1690 // has this request been aborted 1691 aborted: false, 1692 1693 // method to initialize an xmlhttpclient 1694 init:function() 1695 { 1696 try { 1697 // Mozilla / Safari 1698 //this.xmlhttp = new HTML_AJAX_IframeXHR(); //uncomment these two lines to test iframe 1699 //return; 1700 this.xmlhttp = new XMLHttpRequest(); 1701 } catch (e) { 1702 // IE 1703 var XMLHTTP_IDS = new Array( 1704 'MSXML2.XMLHTTP.5.0', 1705 'MSXML2.XMLHTTP.4.0', 1706 'MSXML2.XMLHTTP.3.0', 1707 'MSXML2.XMLHTTP', 1708 'Microsoft.XMLHTTP' ); 1709 var success = false; 1710 for (var i=0;i < XMLHTTP_IDS.length && !success; i++) { 1711 try { 1712 this.xmlhttp = new ActiveXObject(XMLHTTP_IDS[i]); 1713 success = true; 1714 } catch (e) {} 1715 } 1716 if (!success) { 1717 try{ 1718 this.xmlhttp = new HTML_AJAX_IframeXHR(); 1719 this.request.iframe = true; 1720 } catch(e) { 1721 throw new Error('Unable to create XMLHttpRequest.'); 1722 } 1723 } 1724 } 1725 }, 1726 1727 // check if there is a call in progress 1728 callInProgress: function() 1729 { 1730 switch ( this.xmlhttp.readyState ) { 1731 case 1: 1732 case 2: 1733 case 3: 1734 return true; 1735 break; 1736 default: 1737 return false; 1738 break; 1739 } 1740 }, 1741 1742 // make the request defined in the request object 1743 makeRequest: function() 1744 { 1745 if (!this.xmlhttp) { 1746 this.init(); 1747 } 1748 1749 try { 1750 if (this.request.Open) { 1751 this.request.Open(); 1752 } 1753 else if (HTML_AJAX.Open) { 1754 HTML_AJAX.Open(this.request); 1755 } 1756 1757 if (this.request.multipart) { 1758 if (document.all) { 1759 this.iframe = true; 1760 } else { 1761 this.xmlhttp.multipart = true; 1762 } 1763 } 1764 1765 // set onreadystatechange here since it will be reset after a completed call in Mozilla 1766 var self = this; 1767 this.xmlhttp.open(this.request.requestType,this.request.completeUrl(),this.request.isAsync); 1768 if (this.request.customHeaders) { 1769 for (var i in this.request.customHeaders) { 1770 this.xmlhttp.setRequestHeader(i, this.request.customHeaders[i]); 1771 } 1772 } 1773 if (this.request.customHeaders && !this.request.customHeaders['Content-Type']) { 1774 var content = this.request.getContentType(); 1775 var charsetIndex = content.indexOf('; charset=UTF-8'); 1776 if (charsetIndex == -1) { 1777 content += '; charset=UTF-8'; 1778 } 1779 this.xmlhttp.setRequestHeader('Content-Type', content); 1780 } 1781 1782 if (this.request.isAsync) { 1783 if (this.request.callback) { 1784 this.callbackComplete = false; 1785 } 1786 this.xmlhttp.onreadystatechange = function() { self._readyStateChangeCallback(); } 1787 } else { 1788 this.xmlhttp.onreadystatechange = function() {} 1789 } 1790 var payload = this.request.getSerializedPayload(); 1791 if (payload) { 1792 this.xmlhttp.setRequestHeader('Content-Length', payload.length); 1793 } 1794 this.xmlhttp.send(payload); 1795 1796 if (!this.request.isAsync) { 1797 if ( this.xmlhttp.status == 200 ) { 1798 HTML_AJAX.requestComplete(this.request); 1799 if (this.request.Load) { 1800 this.request.Load(); 1801 } else if (HTML_AJAX.Load) { 1802 HTML_AJAX.Load(this.request); 1803 } 1804 1805 return this._decodeResponse(); 1806 } else { 1807 var e = new Error('['+this.xmlhttp.status +'] '+this.xmlhttp.statusText); 1808 e.headers = this.xmlhttp.getAllResponseHeaders(); 1809 this._handleError(e); 1810 } 1811 } 1812 else { 1813 // setup timeout 1814 var self = this; 1815 this._timeoutId = window.setTimeout(function() { self.abort(true); },this.request.timeout); 1816 } 1817 } catch (e) { 1818 this._handleError(e); 1819 } 1820 }, 1821 1822 // abort an inprogress request 1823 abort: function (automatic) 1824 { 1825 if (this.callInProgress()) { 1826 this.aborted = true; 1827 this.xmlhttp.abort(); 1828
1829 if (automatic) { 1830 HTML_AJAX.requestComplete(this.request); 1831 this._handleError(new Error('Request Timed Out: time out was '+this.request.timeout+'ms')); 1832 } 1833 } 1834 }, 1835 1836 // internal method used to handle ready state changes 1837 _readyStateChangeCallback:function() 1838 { 1839 try { 1840 switch(this.xmlhttp.readyState) { 1841 // XMLHTTPRequest.open() has just been called 1842 case 1: 1843 break; 1844 // XMLHTTPRequest.send() has just been called 1845 case 2: 1846 if (this.request.Send) { 1847 this.request.Send(); 1848 } else if (HTML_AJAX.Send) { 1849 HTML_AJAX.Send(this.request); 1850 } 1851 break; 1852 // Fetching response from server in progress 1853 case 3: 1854 if (this.request.Progress) { 1855 this.request.Progress(); 1856 } else if (HTML_AJAX.Progress ) { 1857 HTML_AJAX.Progress(this.request); 1858 } 1859 break; 1860 // Download complete 1861 case 4: 1862 window.clearTimeout(this._timeoutId); 1863 if (this.aborted) { 1864 if (this.request.Load) { 1865 this.request.Load(); 1866 } else if (HTML_AJAX.Load) { 1867 HTML_AJAX.Load(this.request); 1868 } 1869 } 1870 else if (this.xmlhttp.status == 200) { 1871 if (this.request.Load) { 1872 this.request.Load(); 1873 } else if (HTML_AJAX.Load ) { 1874 HTML_AJAX.Load(this.request); 1875 } 1876 1877 var response = this._decodeResponse(); 1878 1879 if (this.request.callback) { 1880 this.request.callback(response); 1881 this.callbackComplete = true; 1882 } 1883 } 1884 else { 1885 var e = new Error('HTTP Error Making Request: ['+this.xmlhttp.status+'] '+this.xmlhttp.statusText); 1886 this._handleError(e); 1887 } 1888 HTML_AJAX.requestComplete(this.request); 1889 break; 1890 } 1891 } catch (e) { 1892 this._handleError(e); 1893 } 1894 }, 1895 1896 // decode response as needed 1897 _decodeResponse: function() { 1898 //try for x-Content-Type first 1899 var content = null; 1900 try { 1901 content = this.xmlhttp.getResponseHeader('X-Content-Type'); 1902 } catch(e) {} 1903 if(!content || content == null) 1904 { 1905 content = this.xmlhttp.getResponseHeader('Content-Type'); 1906 } 1907 //strip anything after ; 1908 if(content.indexOf(';') != -1) 1909 { 1910 content = content.substring(0, content.indexOf(';')); 1911 } 1912 // hook for xml, it doesn't need to be unserialized 1913 if(content == 'application/xml' || content == 'text/xml') 1914 { 1915 return this.xmlhttp.responseXML; 1916 } 1917 var unserializer = HTML_AJAX.serializerForEncoding(content); 1918 //alert(this.xmlhttp.getAllResponseHeaders()); // some sort of debug hook is needed here 1919 return unserializer.unserialize(this.xmlhttp.responseText); 1920 }, 1921 1922 // handle sending an error where it needs to go 1923 _handleError: function(e) 1924 { 1925 HTML_AJAX.requestComplete(this.request,e); 1926 if (this.request.onError) { 1927 this.request.onError(e); 1928 } else if (HTML_AJAX.onError) { 1929 HTML_AJAX.onError(e,this.request); 1930 } 1931 else { 1932 throw e; 1933 } 1934 } 1935} 1936// Request.js 1937/** 1938 * Class that contains everything needed to make a request 1939 * This includes: 1940 * The url were calling
1941 * If were calling a remote method, the class and method name 1942 * The payload, unserialized 1943 * The timeout for async calls 1944 * The callback method 1945 * Optional event handlers: onError, Load, Send 1946 * A serializer instance 1947 * 1948 * @category HTML 1949 * @package AJAX 1950 * @author Joshua Eichorn <[email protected]> 1951 * @copyright 2005 Joshua Eichorn 1952 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 1953 * 1954 * See Main.js for author/license details 1955 */ 1956function HTML_AJAX_Request(serializer) { 1957 this.serializer = serializer; 1958} 1959HTML_AJAX_Request.prototype = { 1960 1961 // Instance of a serializer 1962 serializer: null, 1963 1964 // Is this an async request 1965 isAsync: false, 1966 1967 // HTTP verb 1968 requestType: 'POST', 1969 1970 // The actual URL the request is sent to 1971 requestUrl: '', 1972 1973 // Remote Class 1974 className: null, 1975 1976 // Remote Method 1977 methodName: null, 1978 1979 // Timeout in milliseconds for requests 1980 timeout: 20000, 1981 1982 // unserialized data, for rpc calls use add args, to send raw data just set this directly 1983 args: null, 1984 1985 // async callback method 1986 callback: null, 1987 1988 // Queue to push this request too 1989 queue: 'default', 1990 1991 // default priority 1992 priority: 0, 1993 1994 // a hash of headers to add to add to this request 1995 customHeaders: {'X-Requested-With': 'XMLHttpRequest', 'X-Ajax-Engine': 'HTML_AJAX/0.5.6'}, 1996 1997 // true if this request will be sent using iframes 1998 iframe: false, 1999 2000 // is this a grab request? if so we need to proxy for iframes 2001 grab: false, 2002 2003 // true if this request should expect a multipart response 2004 multipart: false, 2005 2006 // remote callback 2007 phpCallback: false, 2008 2009 /** 2010 * Add an argument for the remote method 2011 * @param string argument name 2012 * @param mixed value 2013 * @return void
2014 * @throws Error code 1004 2015 */ 2016 addArg: function(name, value) 2017 { 2018 if ( !this.args ) { 2019 this.args = []; 2020 } 2021 if (!/[^a-zA-Z_0-9]/.test(name) ) { 2022 this.args[name] = value; 2023 } else { 2024 throw new Error('Invalid parameter name ('+name+')'); 2025 } 2026 }, 2027 2028 /** 2029 * Get the payload in a serialized manner 2030 */ 2031 getSerializedPayload: function() { 2032 return this.serializer.serialize(this.args); 2033 }, 2034 2035 /** 2036 * Get the content type 2037 */ 2038 getContentType: function() { 2039 return this.serializer.contentType; 2040 }, 2041 2042 /** 2043 * Get the complete url, adding in any needed get params for rpc 2044 */ 2045 completeUrl: function() { 2046 if (this.className || this.methodName) { 2047 this.addGet('c', this.className); 2048 this.addGet('m', this.methodName); 2049 } 2050 if (this.phpCallback) { 2051 if (HTML_AJAX_Util.getType(this.phpCallback) == 'array') { 2052 this.phpCallback = this.phpCallback.join('.'); 2053 } 2054 this.addGet('cb', this.phpCallback); 2055 } 2056 if (this.multipart) { 2057 this.addGet('multipart', '1'); 2058 } 2059 return this.requestUrl; 2060 }, 2061 2062 /** 2063 * Compare to another request by priority 2064 */ 2065 compareTo: function(other) { 2066 if (this.priority == other.priority) { 2067 return 0; 2068 } 2069 return (this.priority > other.priority ? 1 : -1); 2070 }, 2071 2072 /** 2073 * Add a GET argument 2074 */ 2075 addGet: function(name, value) { 2076 var url = new String(this.requestUrl); 2077 url += (url.indexOf('?') < 0 ? '?' : '&') + escape(name) + '=' + escape(value); 2078 this.requestUrl = url; 2079 } 2080}
2081// serializer/JSON.js 2082/* 2083Copyright (c) 2005 JSON.org 2084 2085Permission is hereby granted, free of charge, to any person obtaining a copy 2086of this software and associated documentation files (the "Software"), to deal 2087in the Software without restriction, including without limitation the rights 2088to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2089copies of the Software, and to permit persons to whom the Software is 2090furnished to do so, subject to the following conditions: 2091 2092The Software shall be used for Good, not Evil. 2093 2094THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2095IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2096FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2097AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2098LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2099OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2100SOFTWARE. 2101*/ 2102 2103/* 2104 The global object JSON contains two methods. 2105 2106 JSON.stringify(value) takes a JavaScript value and produces a JSON text. 2107 The value must not be cyclical. 2108 2109 JSON.parse(text) takes a JSON text and produces a JavaScript value. It will 2110 throw a 'JSONError' exception if there is an error. 2111*/ 2112var HTML_AJAX_JSON = { 2113 copyright: '(c)2005 JSON.org', 2114 license: 'http://www.crockford.com/JSON/license.html', 2115/* 2116 Stringify a JavaScript value, producing a JSON text. 2117*/ 2118 stringify: function (v) { 2119 var a = []; 2120 2121/* 2122 Emit a string. 2123*/ 2124 function e(s) { 2125 a[a.length] = s; 2126 } 2127 2128/* 2129 Convert a value. 2130*/ 2131 function g(x) { 2132 var c, i, l, v; 2133 2134 switch (typeof x) { 2135 case 'object': 2136 if (x) { 2137 if (x instanceof Array) { 2138 e('['); 2139 l = a.length; 2140 for (i = 0; i < x.length; i += 1) { 2141 v = x[i]; 2142 if (typeof v != 'undefined' && 2143 typeof v != 'function') { 2144 if (l < a.length) { 2145 e(','); 2146 } 2147 g(v); 2148 } 2149 } 2150 e(']'); 2151 return; 2152 } else if (typeof x.valueOf == 'function') { 2153 e('{'); 2154 l = a.length; 2155 for (i in x) { 2156 v = x[i]; 2157 if (typeof v != 'undefined' && 2158 typeof v != 'function' && 2159 (!v || typeof v != 'object' || 2160 typeof v.valueOf == 'function')) { 2161 if (l < a.length) { 2162 e(','); 2163 } 2164 g(i); 2165 e(':'); 2166 g(v); 2167 } 2168 } 2169 return e('}'); 2170 } 2171 } 2172 e('null'); 2173 return; 2174 case 'number': 2175 e(isFinite(x) ? +x : 'null'); 2176 return; 2177 case 'string': 2178 l = x.length; 2179 e('"'); 2180 for (i = 0; i < l; i += 1) { 2181 c = x.charAt(i); 2182 if (c >= ' ') { 2183 if (c == '\\' || c == '"') { 2184 e('\\'); 2185 } 2186 e(c); 2187 } else { 2188 switch (c) { 2189 case '\b': 2190 e('\\b'); 2191 break; 2192 case '\f': 2193 e('\\f'); 2194 break; 2195 case '\n': 2196 e('\\n'); 2197 break; 2198 case '\r': 2199 e('\\r'); 2200 break; 2201 case '\t': 2202 e('\\t'); 2203 break; 2204 default:
2205 c = c.charCodeAt(); 2206 e('\\u00' + Math.floor(c / 16).toString(16) + 2207 (c % 16).toString(16)); 2208 } 2209 } 2210 } 2211 e('"'); 2212 return; 2213 case 'boolean': 2214 e(String(x)); 2215 return; 2216 default: 2217 e('null'); 2218 return; 2219 } 2220 } 2221 g(v); 2222 return a.join(''); 2223 }, 2224/* 2225 Parse a JSON text, producing a JavaScript value. 2226*/ 2227 parse: function (text) { 2228 return 2229(/^(\s+|[,:{}\[\]]|"(\\["\\\/bfnrtu]|[^\x00-\x1f"\\]+)*"|-?\d+(\.\d*)?([eE][+-]?\d+)?|true|false|null)+$/.test(text)) 2230 && 2231 eval('(' + text + ')'); 2232 } 2233};// serializer/haSerializer.js 2234/** 2235 * HTML_AJAX_Serialize_HA - custom serialization 2236 * 2237 * This class is used with the JSON serializer and the HTML_AJAX_Action php class 2238 * to allow users to easily write data handling and dom manipulation related to 2239 * ajax actions directly from their php code 2240 * 2241 * See Main.js for Author/license details 2242 */ 2243function HTML_AJAX_Serialize_HA() { } 2244HTML_AJAX_Serialize_HA.prototype = 2245{ 2246 /**
2247 * Takes data from JSON - which should be parseable into a nice array 2248 * reads the action to take and pipes it to the right method 2249 * 2250 * @param string payload incoming data from php 2251 * @return true on success, false on failure 2252 */ 2253 unserialize: function(payload) 2254 { 2255 var actions = eval(payload); 2256 for(var i = 0; i < actions.length; i++) 2257 { 2258 var action = actions[i]; 2259 switch(action.action) 2260 { 2261 case 'prepend': 2262 this._prependAttr(action.id, action.attributes); 2263 break; 2264 case 'append': 2265 this._appendAttr(action.id, action.attributes); 2266 break; 2267 case 'assign': 2268 this._assignAttr(action.id, action.attributes); 2269 break; 2270 case 'clear': 2271 this._clearAttr(action.id, action.attributes); 2272 break; 2273 case 'create': 2274 this._createNode(action.id, action.tag, action.attributes, action.type); 2275 break; 2276 case 'replace': 2277 this._replaceNode(action.id, action.tag, action.attributes); 2278 break; 2279 case 'remove': 2280 this._removeNode(action.id); 2281 break; 2282 case 'script': 2283 this._insertScript(action.data); 2284 break; 2285 case 'alert': 2286 this._insertAlert(action.data); 2287 break; 2288 } 2289 } 2290 }, 2291 /* Dispatch Methods */ 2292 _prependAttr: function(id, attributes) 2293 { 2294 var node = document.getElementById(id); 2295 this._setAttrs(node, attributes, 'prepend'); 2296 }, 2297 _appendAttr: function(id, attributes) 2298 { 2299 var node = document.getElementById(id); 2300 this._setAttrs(node, attributes, 'append'); 2301 }, 2302 _assignAttr: function(id, attributes) 2303 { 2304 var node = document.getElementById(id); 2305 this._setAttrs(node, attributes); 2306 }, 2307 _clearAttr: function(id, attributes) 2308 { 2309 var node = document.getElementById(id); 2310 for(var i = 0; i < attributes.length; i++) 2311 { 2312 if(attributes[i] == 'innerHTML') 2313 { 2314 HTML_AJAX_Util.setInnerHTML(node, ''); 2315 } 2316 // value can't be removed 2317 else if(attributes[i] == 'value') 2318 { 2319 node.value = ''; 2320 } 2321 // I'd use hasAttribute first but IE is stupid stupid stupid 2322 else 2323 { 2324 try 2325 { 2326 node.removeAttribute(attributes[i]); 2327 } 2328 catch(e) 2329 { 2330 node[i] = undefined; 2331 } 2332 } 2333 } 2334 }, 2335 _createNode: function(id, tag, attributes, type) 2336 { 2337 var newnode = document.createElement(tag); 2338 this._setAttrs(newnode, attributes); 2339 switch(type) 2340 { 2341 case 'append': 2342 document.getElementById(id).appendChild(newnode); 2343 break 2344 case 'prepend': 2345 var parent = document.getElementById(id); 2346 var sibling = parent.firstChild; 2347 parent.insertBefore(newnode, sibling); 2348 break; 2349 case 'insertBefore': 2350 var sibling = document.getElementById(id); 2351 var parent = sibling.parentNode; 2352 parent.insertBefore(newnode, sibling); 2353 break; 2354 //this one is tricky, if it's the last one we use append child...ewww 2355 case 'insertAfter': 2356 var sibling = document.getElementById(id); 2357 var parent = sibling.parentNode; 2358 var next = sibling.nextSibling; 2359 if(next == null) 2360 { 2361 parent.appendChild(newnode); 2362 } 2363 else 2364 { 2365 parent.insertBefore(newnode, next); 2366 } 2367 break; 2368 } 2369 }, 2370 _replaceNode: function(id, tag, attributes) 2371 { 2372 var node = document.getElementById(id); 2373 var parent = node.parentNode; 2374 var newnode = document.createElement(tag); 2375 this._setAttrs(newnode, attributes); 2376 parent.replaceChild(newnode, node); 2377 }, 2378 _removeNode: function(id) 2379 { 2380 var node = document.getElementById(id); 2381 if(node) 2382 { 2383 var parent = node.parentNode; 2384 parent.removeChild(node); 2385 } 2386 }, 2387 _insertScript: function(data) 2388 { 2389 eval(data); 2390 }, 2391 _insertAlert: function(data) 2392 { 2393 alert(data); 2394 }, 2395 /* Helper Methods */ 2396 // should we move this to HTML_AJAX_Util???, just does the - case which we need for style 2397 _camelize: function(instr) 2398 { 2399 var p = instr.split('-'); 2400 var out = p[0]; 2401 for(var i = 1; i < p.length; i++) { 2402 out += p[i].charAt(0).toUpperCase()+p[i].substring(1); 2403 } 2404 return out; 2405 }, 2406 _setAttrs: function(node, attributes, type) 2407 { 2408 switch(type) 2409 { 2410 case 'prepend': 2411 for (var i in attributes) 2412 {
2413 // innerHTML is extremely flakey - use util method for it 2414 if(i == 'innerHTML') 2415 { 2416 HTML_AJAX_Util.setInnerHTML(node, attributes[i], 'append'); 2417 } 2418 //IE doesn't support setAttribute on style so we need to break it out and set each property individually 2419 else if(i == 'style') 2420 { 2421 var styles = []; 2422 if(attributes[i].indexOf(';')) 2423 { 2424 styles = attributes[i].split(';'); 2425 } 2426 else 2427 { 2428 styles.push(attributes[i]); 2429 } 2430 for(var i = 0; i < styles.length; i++) 2431 { 2432 var r = styles[i].match(/^\s*(.+)\s*:\s*(.+)\s*$/); 2433 if(r) 2434 { 2435 node.style[this._camelize(r[1])] = r[2] + node.style[this._camelize(r[1])]; 2436 } 2437 } 2438 } 2439 else 2440 { 2441 try 2442 { 2443 node[i] = attributes[i] + node[i]; 2444 } 2445 catch(e){} 2446 node.setAttribute(i, attributes[i] + node[i]); 2447 } 2448 } 2449 break; 2450 case 'append': 2451 { 2452 for (var i in attributes) 2453 { 2454 // innerHTML is extremely flakey - use util method for it 2455 if(i == 'innerHTML') 2456 { 2457 HTML_AJAX_Util.setInnerHTML(node, attributes[i], 'append'); 2458 } 2459 //IE doesn't support setAttribute on style so we need to break it out and set each property individually 2460 else if(i == 'style') 2461 { 2462 var styles = []; 2463 if(attributes[i].indexOf(';')) 2464 { 2465 styles = attributes[i].split(';'); 2466 } 2467 else 2468 { 2469 styles.push(attributes[i]); 2470 } 2471 for(var i = 0; i < styles.length; i++) 2472 { 2473 var r = styles[i].match(/^\s*(.+)\s*:\s*(.+)\s*$/); 2474 if(r) 2475 { 2476 node.style[this._camelize(r[1])] = node.style[this._camelize(r[1])] + r[2]; 2477 } 2478 } 2479 } 2480 else 2481 { 2482 try 2483 { 2484 node[i] = node[i] + attributes[i]; 2485 } 2486 catch(e){} 2487 node.setAttribute(i, node[i] + attributes[i]); 2488 } 2489 } 2490 break; 2491 } 2492 default: 2493 { 2494 for (var i in attributes) 2495 { 2496 //innerHTML hack bailout 2497 if(i == 'innerHTML') 2498 { 2499 HTML_AJAX_Util.setInnerHTML(node, attributes[i]); 2500 } 2501 else if(i == 'style') 2502 { 2503 var styles = []; 2504 if(attributes[i].indexOf(';')) 2505 { 2506 styles = attributes[i].split(';'); 2507 } 2508 else 2509 { 2510 styles.push(attributes[i]); 2511 } 2512 for(var i = 0; i < styles.length; i++) 2513 { 2514 var r = styles[i].match(/^\s*(.+)\s*:\s*(.+)\s*$/); 2515 if(r) 2516 { 2517 node.style[this._camelize(r[1])] = r[2]; 2518 } 2519 } 2520 } 2521 else 2522 { 2523 try 2524 { 2525 node[i] = attributes[i]; 2526 } 2527 catch(e){} 2528 node.setAttribute(i, attributes[i]); 2529 } 2530 } 2531 } 2532 } 2533 } 2534} 2535// Loading.js 2536/** 2537 * Default loading implementation 2538 * 2539 * @category HTML 2540 * @package Ajax 2541 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 2542 * @copyright 2005 Joshua Eichorn 2543 * see Main.js for license Author details 2544 */ 2545HTML_AJAX.Open = function(request) { 2546 var loading = document.getElementById('HTML_AJAX_LOADING'); 2547 if (!loading) { 2548 loading = document.createElement('div'); 2549 loading.id = 'HTML_AJAX_LOADING'; 2550 loading.innerHTML = 'Loading...'; 2551 2552 loading.style.color = '#fff'; 2553 loading.style.position = 'absolute'; 2554 loading.style.top = 0; 2555 loading.style.right = 0; 2556 loading.style.backgroundColor = '#f00'; 2557 loading.style.border = '1px solid #f99'; 2558 loading.style.width = '80px'; 2559 loading.style.padding = '4px'; 2560 loading.style.fontFamily = 'Arial, Helvetica, sans'; 2561 loading.count = 0; 2562 2563 document.body.insertBefore(loading,document.body.firstChild); 2564 } 2565 else { 2566 if (loading.count == undefined) { 2567 loading.count = 0; 2568 } 2569 } 2570 loading.count++; 2571 if (request.isAsync) { 2572 request.loadingId = window.setTimeout(function() { loading.style.display = 'block'; },500); 2573 } 2574 else { 2575 loading.style.display = 'block'; 2576 } 2577} 2578HTML_AJAX.Load = function(request) { 2579 if (request.loadingId) { 2580 window.clearTimeout(request.loadingId); 2581 } 2582 var loading = document.getElementById('HTML_AJAX_LOADING'); 2583 loading.count--; 2584 2585 if (loading.count == 0) { 2586 loading.style.display = 'none'; 2587 } 2588} 2589// util.js 2590/** 2591 * Utility methods 2592 * 2593 * @category HTML 2594 * @package Ajax 2595 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 2596 * 2597 * See Main.js for author/license details 2598 */ 2599// {{{ HTML_AJAX_Util 2600/** 2601 * All the utilities we will be using thorough the classes 2602 */ 2603var HTML_AJAX_Util = { 2604 // Set the element event 2605 registerEvent: function(element, event, handler) 2606 { 2607 element = this.getElement(element); 2608 if (typeof element.addEventListener != "undefined") { //Dom2 2609 element.addEventListener(event, handler, false); 2610 } else if (typeof element.attachEvent != "undefined") { //IE 5+ 2611 element.attachEvent("on" + event, handler); 2612 } else { 2613 if (element["on" + event] != null) { 2614 var oldHandler = element["on" + event]; 2615 element["on" + event] = function(e) { 2616 oldHander(e); 2617 handler(e); 2618 }; 2619 } else { 2620 element["on" + event] = handler; 2621 } 2622 } 2623 }, 2624 // get the target of an event, automatically checks window.event for ie 2625 eventTarget: function(event) 2626 { 2627 if (!event) var event = window.event; 2628 if (event.target) return event.target; // w3c 2629 if (event.srcElement) return event.srcElement; // ie 5 2630 }, 2631 // gets the type of a variable or its primitive equivalent as a string 2632 getType: function(inp) 2633 { 2634 var type = typeof inp, match; 2635 if(type == 'object' && !inp) 2636 { 2637 return 'null';
2638 } 2639 if (type == "object") { 2640 if(!inp.constructor) 2641 { 2642 return 'object'; 2643 } 2644 var cons = inp.constructor.toString(); 2645 if (match = cons.match(/(\w+)\(/)) { 2646 cons = match[1].toLowerCase(); 2647 } 2648 var types = ["boolean", "number", "string", "array"]; 2649 for (key in types) { 2650 if (cons == types[key]) { 2651 type = types[key]; 2652 break; 2653 } 2654 } 2655 } 2656 return type; 2657 }, 2658 // repeats the input string the number of times given by multiplier. exactly like PHP's str_repeat() 2659 strRepeat: function(inp, multiplier) { 2660 var ret = ""; 2661 while (--multiplier > 0) ret += inp; 2662 return ret; 2663 }, 2664 // encode a string allowing it to be used in a query string of a url 2665 encodeUrl: function(input) { 2666 return encodeURIComponent(input); 2667 }, 2668 // decode a url encoded string 2669 decodeUrl: function(input) { 2670 return decodeURIComponent(input); 2671 }, 2672 // recursive variable dumper similar in output to PHP's var_dump(), the differences being: this function displays JS types and type names; JS doesn't provide an object number like PHP does 2673 varDump: function(inp, printFuncs, _indent, _recursionLevel) 2674 { 2675 if (!_recursionLevel) _recursionLevel = 0; 2676 if (!_indent) _indent = 1; 2677 var tab = this.strRepeat(" ", ++_indent); 2678 var type = this.getType(inp), out = type; 2679 var consrx = /(\w+)\(/; 2680 consrx.compile(); 2681 if (++_recursionLevel > 6) { 2682 return tab + inp + "Loop Detected\n"; 2683 } 2684 switch (type) { 2685 case "boolean": 2686 case "number": 2687 out += "(" + inp.toString() + ")"; 2688 break; 2689 case "string": 2690 out += "(" + inp.length + ") \"" + inp + "\""; 2691 break; 2692 case "function": 2693 if (printFuncs) { 2694 out += inp.toString().replace(/\n/g, "\n" + tab); 2695 } 2696 break; 2697 case "array": 2698 case "object": 2699 var atts = "", attc = 0; 2700 try { 2701 for (k in inp) { 2702 atts += tab + "[" + (/\D/.test(k) ? "\"" + k + "\"" : k) 2703 + "]=>\n" + tab + this.varDump(inp[k], printFuncs, _indent, _recursionLevel); 2704 ++attc; 2705 } 2706 } catch (e) {} 2707 if (type == "object") { 2708 var objname, objstr = inp.toString(); 2709 if (objname = objstr.match(/^\[object (\w+)\]$/)) { 2710 objname = objname[1]; 2711 } else { 2712 try { 2713 objname = inp.constructor.toString().match(consrx)[1]; 2714 } catch (e) { 2715 objname = 'unknown'; 2716 } 2717 } 2718 out += "(" + objname + ") "; 2719 } 2720 out += "(" + attc + ") {\n" + atts + this.strRepeat(" ", _indent - 1) +"}"; 2721 break; 2722 } 2723 return out + "\n"; 2724 }, 2725 // non resursive simple debug printer 2726 quickPrint: function(input,sep) { 2727 if (!sep) { 2728 var sep = "\n"; 2729 } 2730 var type = HTML_AJAX_Util.getType(input); 2731 switch (type) { 2732 case 'string': 2733 return input; 2734 case 'array': 2735 var ret = ""; 2736 for(var i = 0; i < input.length; i++) { 2737 ret += i+':'+input[i]+sep; 2738 } 2739 return ret; 2740 default: 2741 var ret = ""; 2742 for(var i in input) { 2743 ret += i+':'+input[i]+sep; 2744 } 2745 return ret; 2746 } 2747 }, 2748 //compat function for stupid browsers in which getElementsByTag with a * dunna work 2749 getAllElements: function(parentElement) 2750 { 2751 //check for idiot browsers 2752 if( document.all) 2753 { 2754 if(!parentElement) { 2755 var allElements = document.all; 2756 } 2757 else 2758 { 2759 var allElements = [], rightName = new RegExp( parentElement, 'i' ), i; 2760 for( i=0; i<document.all.length; i++ ) { 2761 if( rightName.test( document.all[i].parentElement ) ) 2762 allElements.push( document.all[i] ); 2763 } 2764 } 2765 return allElements; 2766 } 2767 //real browsers just do this 2768 else 2769 { 2770 if (!parentElement) { parentElement = document.body; } 2771 return parentElement.getElementsByTagName('*'); 2772 } 2773 }, 2774 getElementsByProperty: function(property, regex, parentElement) { 2775 var allElements = HTML_AJAX_Util.getAllElements(parentElement); 2776 var items = []; 2777 for(var i=0,j=allElements.length; i<j; i++) 2778 { 2779 if(regex.test(allElements[i][property])) 2780 { 2781 items.push(allElements[i]); 2782 } 2783 } 2784 return items; 2785 }, 2786 getElementsByClassName: function(className, parentElement) { 2787 return HTML_AJAX_Util.getElementsByProperty('className',new RegExp('(^| )' + className + '( |$)'),parentElement); 2788 }, 2789 getElementsById: function(id, parentElement) { 2790 return HTML_AJAX_Util.getElementsByProperty('id',new RegExp(id),parentElement); 2791 }, 2792 getElementsByCssSelector: function(selector,parentElement) { 2793 return cssQuery(selector,parentElement); 2794 }, 2795 htmlEscape: function(inp) { 2796 var div = document.createElement('div'); 2797 var text = document.createTextNode(inp); 2798 div.appendChild(text); 2799 return div.innerHTML; 2800 }, 2801 // return the base of the given absolute url, or the filename if the second argument is true 2802 baseURL: function(absolute, filename) { 2803 var qPos = absolute.indexOf('?'); 2804 if (qPos >= 0) { 2805 absolute = absolute.substr(0, qPos); 2806 } 2807 var slashPos = Math.max(absolute.lastIndexOf('/'), absolute.lastIndexOf('\\')); 2808 if (slashPos < 0) { 2809 return absolute; 2810 } 2811 return (filename ? absolute.substr(slashPos + 1) : absolute.substr(0, slashPos + 1)); 2812 }, 2813 // return the query string from a url 2814 queryString: function(url) { 2815 var qPos = url.indexOf('?'); 2816 if (qPos >= 0) { 2817 return url.substr(qPos+1); 2818 } 2819 }, 2820 // return the absolute path to the given relative url 2821 absoluteURL: function(rel, absolute) { 2822 if (/^https?:\/\//i.test(rel)) { 2823 return rel; 2824 } 2825 if (!absolute) { 2826 var bases = document.getElementsByTagName('base'); 2827 for (i in bases) { 2828 if (bases[i].href) { 2829 absolute = bases[i].href; 2830 break; 2831 } 2832 } 2833 if (!absolute) { 2834 absolute = window.location.href; 2835 } 2836 } 2837 if (rel == '') { 2838 return absolute; 2839 } 2840 if (rel.substr(0, 2) == '//') { 2841 // starts with '//', replace everything but the protocol 2842 var slashesPos = absolute.indexOf('//'); 2843 if (slashesPos < 0) { 2844 return 'http:' + rel; 2845 } 2846 return absolute.substr(0, slashesPos) + rel; 2847 } 2848 var base = this.baseURL(absolute); 2849 var absParts = base.substr(0, base.length - 1).split('/'); 2850 var absHost = absParts.slice(0, 3).join('/') + '/'; 2851 if (rel.substr(0, 1) == '/') { 2852 // starts with '/', append it to the host 2853 return absHost + rel; 2854 } 2855 if (rel.substr(0, 1) == '.' && rel.substr(1, 1) != '.') { 2856 // starts with '.', append it to the base 2857 return base + rel.substr(1); 2858 } 2859 // remove everything upto the path and beyond 2860 absParts.splice(0, 3); 2861 var relParts = rel.split('/'); 2862 var loopStart = relParts.length - 1; 2863 relParts = absParts.concat(relParts); 2864 for (i = loopStart; i < relParts.length;) { 2865 if (relParts[i] == '..') { 2866 if (i == 0) { 2867 return absolute; 2868 } 2869 relParts.splice(i - 1, 2); 2870 --i; 2871 continue; 2872 } 2873 i++; 2874 } 2875 return absHost + relParts.join('/'); 2876 }, 2877 // sets the innerHTML of an element. the third param decides how to write, it replaces by default, others are append|prepend 2878 setInnerHTML: function(node, innerHTML, type) 2879 { 2880 node = this.getElement(node); 2881 2882 if (type != 'append') { 2883 if (type == 'prepend') { 2884 var oldHtml = node.innerHTML; 2885 } 2886 node.innerHTML = ''; 2887 } 2888 var good_browser = (navigator.product == 'Gecko'); 2889 var regex = /^([\s\S]*?)<script([\s\S]*?)>([\s\S]*?)<\/script>([\s\S]*)$/i; 2890 var regex_src = /src=["'](.*?)["']/i; 2891 var matches, id, script, output = '', subject = innerHTML; 2892 var scripts = []; 2893 2894 while (true) { 2895 matches = regex.exec(subject); 2896 if (matches && matches[0]) { 2897 subject = matches[4]; 2898 id = 'ih_' + Math.round(Math.random()*9999) + '_' + Math.round(Math.random()*9999); 2899 2900 var startLen = matches[3].length; 2901 script = matches[3].replace(/document\.write\(([\s\S]*?)\)/ig, 2902 'document.getElementById("' + id + '").innerHTML+=$1'); 2903 2904 output += matches[1]; 2905 if (startLen != script.length) { 2906 output += '<span id="' + id + '"></span>'; 2907 } 2908 2909 output += '<script' + matches[2] + '>
2909' + script + '</script>'; 2910 if (good_browser) { 2911 continue; 2912 } 2913 if (script) { 2914 scripts.push(script); 2915 } 2916 if (regex_src.test(matches[2])) { 2917 var script_el = document.createElement("SCRIPT"); 2918 var atts_regex = /(\w+)=["'](.*?)["']([\s\S]*)$/; 2919 var atts = matches[2]; 2920 for (var i = 0; i < 5; i++) { 2921 var atts_matches = atts_regex.exec(atts); 2922 if (atts_matches && atts_matches[0]) { 2923 script_el.setAttribute(atts_matches[1], atts_matches[2]); 2924 atts = atts_matches[3]; 2925 } else { 2926 break; 2927 } 2928 } 2929 scripts.push(script_el); 2930 } 2931 } else { 2932 output += subject; 2933 break; 2934 } 2935 } 2936 innerHTML = output; 2937 2938 if (good_browser) { 2939 var el = document.createElement('span'); 2940 el.innerHTML = innerHTML; 2941 2942 for(var i = 0; i < el.childNodes.length; i++) { 2943 node.appendChild(el.childNodes[i].cloneNode(true)); 2944 } 2945 } 2946 else { 2947 node.innerHTML += innerHTML; 2948 } 2949 2950 if (oldHtml) { 2951 node.innerHTML += oldHtml; 2952 } 2953 2954 if (!good_browser) { 2955 for(var i = 0; i < scripts.length; i++) { 2956 if (HTML_AJAX_Util.getType(scripts[i]) == 'string') { 2957 scripts[i] = scripts[i].replace(/^\s*<!(\[CDATA\[|--)|((\/\/)?--|\]\])>\s*$/g, ''); 2958 window.eval(scripts[i]); 2959 } 2960 else { 2961 node.appendChild(scripts[i]); 2962 } 2963 } 2964 } 2965 return; 2966 }, 2967 classSep: '(^|$| )', 2968 hasClass: function(o, className) { 2969 var o = this.getElement(o); 2970 var regex = new RegExp(this.classSep + className + this.classSep); 2971 return regex.test(o.className); 2972 }, 2973 addClass: function(o, className) { 2974 var o = this.getElement(o); 2975 if(!this.hasClass(o, className)) { 2976 o.className += " " + className; 2977 } 2978 }, 2979 removeClass: function(o, className) { 2980 var o = this.getElement(o); 2981 var regex = new RegExp(this.classSep + className + this.classSep); 2982 o.className = o.className.replace(regex, " "); 2983 }, 2984 replaceClass: function(o, oldClass, newClass) { 2985 var o = this.getElement(o); 2986 var regex = new RegExp(this.classSep + oldClass + this.classSep); 2987 o.className = o.className.replace(regex, newClass); 2988 }, 2989 getElement: function(el) { 2990 if (typeof el == 'string') { 2991 return document.getElementById(el); 2992 } 2993 return el; 2994 } 2995} 2996// }}}
2997// behavior/behavior.js 2998/** 2999 3000ModifiedBehavior v1.0 by Ron Lancaster based on Ben Nolan's Behaviour, June 2005 implementation. 3001Modified to use Dean Edward's CSS Query. 3002 3003Description 3004---------- 3005 3006Uses css selectors to apply javascript Behaviors to enable unobtrusive javascript in html documents. 3007 3008Dependencies 3009------------ 3010 3011Requires [Dean Edwards CSSQuery](http://dean.edwards.name/my/cssQuery/ "CSSQuery"). 3012 3013Usage 3014------ 3015 3016 Behavior.register( 3017 "b.someclass", 3018 function(element) { 3019 element.onclick = function(){ 3020 alert(this.innerHTML); 3021 } 3022 } 3023 ); 3024 3025 Behavior.register( 3026 "#someid u", 3027 function(element) { 3028 element.onmouseover = function(){ 3029 this.innerHTML = "BLAH!"; 3030 } 3031 }, 3032 getElementByID("parent") 3033 ); 3034 3035Call `Behavior.apply()` to re-apply the rules (if you update the dom, etc). 3036 3037License 3038------ 3039 3040Reproduced under BSD licensed. Same license as Ben Nolan's implementation. 3041 3042More information for Ben Nolan's implementation: <http://ripcord.co.nz/behaviour/> 3043 3044*/ 3045 3046var Behavior = { 3047 // so to an id to get debug timings 3048 debug : false, 3049 3050 // private data member 3051 list : new Array(), 3052 3053 // private method 3054 addLoadEvent : function(func) { 3055 var oldonload = window.onload; 3056 3057 if (typeof window.onload != 'function') { 3058 window.onload = func; 3059 } else { 3060 window.onload = function() { 3061 oldonload(); 3062 func(); 3063 } 3064 } 3065 }, 3066 3067 // void apply() : Applies the registered ruleset. 3068 apply : function() { 3069 if (this.debug) { 3070 document.getElementById(this.debug).innerHTML += 'Apply: '+new Date()+'<br>'; 3071 var total = 0; 3072 } 3073 if (Behavior.list.length > 2) { 3074 cssQuery.caching = true; 3075 } 3076 for (i = 0; i < Behavior.list.length; i++) { 3077 var rule = Behavior.list[i]; 3078 3079 if (this.debug) { var ds = new Date() }; 3080 var tags = cssQuery(rule.selector, rule.from); 3081 3082 if (this.debug) { 3083 var de = new Date(); 3084 var ts = de.valueOf()-ds.valueOf(); 3085 document.getElementById(this.debug).innerHTML += 'Rule: '+rule.selector+' - Took: '+ts+' - Returned: '+tags.length+' tags<br>'; 3086 total += ts; 3087 } 3088 if (tags) { 3089 for (j = 0; j < tags.length; j++) { 3090 rule.action(tags[j]); 3091 } 3092 } 3093 } 3094 if (Behavior.list.length > 2) { 3095 cssQuery.caching = false; 3096 } 3097 3098 if (this.debug) { 3099 document.getElementById(this.debug).innerHTML += 'Total rule apply time: '+total; 3100 } 3101 }, 3102 3103 // void register() : register a css selector, and the action (function) to take, 3104 // from (optional) is a document, element or array of elements which is filtered by selector. 3105 register : function(selector, action, from) { 3106 Behavior.list.push(new BehaviorRule(selector, from, action)); 3107 }, 3108 3109 // void start() : initial application of ruleset at document load. 3110 start : function() { 3111 Behavior.addLoadEvent(function() { 3112 Behavior.apply(); 3113 }); 3114 } 3115} 3116 3117function BehaviorRule(selector, from, action) { 3118 this.selector = selector; 3119 this.from = from; 3120 this.action = action; 3121} 3122 3123Behavior.start();
3124// behavior/cssQuery-p.js 3125/* 3126 cssQuery, version 2.0.2 (2005-08-19) 3127 Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/) 3128 License: http://creativecommons.org/licenses/LGPL/2.1/ 3129*/ 3130eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('7 x=6(){7 1D="2.0.2";7 C=/\\s*,\\s*/;7 x=6(s,A){33{7 m=[];7 u=1z.32.2c&&!A;7 b=(A)?(A.31==22)?A:[A]:[1g];7 1E=18(s).1l(C),i;9(i=0;i<1E.y;i++){s=1y(1E[i]);8(U&&s.Z(0,3).2b("")==" *#"){s=s.Z(2);A=24([],b,s[1])}1A A=b;7 j=0,t,f,a,c="";H(j<s.y){t=s[j++];f=s[j++];c+=t+f;a="";8(s[j]=="("){H(s[j++]!=")")a+=s[j];a=a.Z(0,-1);c+="("+a+")"}A=(u&&V[c])?V[c]:21(A,t,f,a);8(u)V[c]=A}m=m.30(A)}2a x.2d;5 m}2Z(e){x.2d=e;5[]}};x.1Z=6(){5"6 x() {\\n [1D "+1D+"]\\n}"};7 V={};x.2c=L;x.2Y=6(s){8(s){s=1y(s).2b("");2a V[s]}1A V={}};7 29={};7 19=L;x.15=6(n,s){8(19)1i("s="+1U(s));29[n]=12 s()};x.2X=6(c){5 c?1i(c):o};7 D={};7 h={};7 q={P:/\\[([\\w-]+(\\|[\\w-]+)?)\\s*(\\W?=)?\\s*([^\\]]*)\\]/};7 T=[];D[" "]=6(r,f,t,n){7 e,i,j;9(i=0;i<f.y;i++){7 s=X(f[i],t,n);9(j=0;(e=s[j]);j++){8(M(e)&&14(e,n))r.z(e)}}};D["#"]=6(r,f,i){7 e,j;9(j=0;(e=f[j]);j++)8(e.B==i)r.z(e)};D["."]=6(r,f,c){c=12 1t("(^|\\\\s)"+c+"(\\\\s|$)");7 e,i;9(i=0;(e=f[i]);i++)8(c.l(e.1V))r.z(e)};D[":"]=6(r,f,p,a){7 t=h[p],e,i;8(t)9(i=0;(e=f[i]);i++)8(t(e,a))r.z(e)};h["2W"]=6(e){7 d=Q(e);8(d.1C)9(7 i=0;i<d.1C.y;i++){8(d.1C[i]==e)5 K}};h["2V"]=6(e){};7 M=6(e){5(e&&e.1c==1&&e.1f!="!")?e:23};7 16=6(e){H(e&&(e=e.2U)&&!M(e))28;5 e};7 G=6(e){H(e&&(e=e.2T)&&!M(e))28;5 e};7 1r=6(e){5 M(e.27)||G(e.27)};7 1P=6(e){5 M(e.26)||16(e.26)};7 1o=6(e){7 c=[];e=1r(e);H(e){c.z(e);e=G(e)}5 c};7 U=K;7 1h=6(e){7 d=Q(e);5(2S d.25=="2R")?/\\.1J$/i.l(d.2Q):2P(d.25=="2O 2N")};7 Q=6(e){5 e.2M||e.1g};7 X=6(e,t){5(t=="*"&&e.1B)?e.1B:e.X(t)};7 17=6(e,t,n){8(t=="*")5 M(e);8(!14(e,n))5 L;8(!1h(e))t=t.2L();5 e.1f==t};7 14=6(e,n){5!n||(n=="*")||(e.2K==n)};7 1e=6(e){5 e.1G};6 24(r,f,B){7 m,i,j;9(i=0;i<f.y;i++){8(m=f[i].1B.2J(B)){8(m.B==B)r.z(m);1A 8(m.y!=23){9(j=0;j<m.y;j++){8(m[j].B==B)r.z(m[j])}}}}5 r};8(![].z)22.2I.z=6(){9(7 i=0;i<1z.y;i++){o[o.y]=1z[i]}5 o.y};7 N=/\\|/;6 21(A,t,f,a){8(N.l(f)){f=f.1l(N);a=f[0];f=f[1]}7 r=[];8(D[t]){D[t](r,A,f,a)}5 r};7 S=/^[^\\s>+~]/;7 20=/[\\s#.:>+~()@]|[^\\s#.:>+~()@]+/g;6 1y(s){8(S.l(s))s=" "+s;5 s.P(20)||[]};7 W=/\\s*([\\s>+~(),]|^|$)\\s*/g;7 I=/([\\s>+~,]|[^(]\\+|^)([#.:@])/g;7 18=6(s){5 s.O(W,"$1").O(I,"$1*$2")};7 1u={1Z:6(){5"\'"},P:/^(\'[^\']*\')|("[^"]*")$/,l:6(s){5 o.P.l(s)},1S:6(s){5 o.l(s)?s:o+s+o},1Y:6(s){5 o.l(s)?s.Z(1,-1):s}};7 1s=6(t){5 1u.1Y(t)};7 E=/([\\/()[\\]?{}|*+-])/g;6 R(s){5 s.O(E,"\\\\$1")};x.15("1j-2H",6(){D[">"]=6(r,f,t,n){7 e,i,j;9(i=0;i<f.y;i++){7 s=1o(f[i]);9(j=0;(e=s[j]);j++)8(17(e,t,n))r.z(e)}};D["+"]=6(r,f,t,n){9(7 i=0;i<f.y;i++){7 e=G(f[i]);8(e&&17(e,t,n))r.z(e)}};D["@"]=6(r,f,a){7 t=T[a].l;7 e,i;9(i=0;(e=f[i]);i++)8(t(e))r.z(e)};h["2G-10"]=6(e){5!16(e)};h["1x"]=6(e,c){c=12 1t("^"+c,"i");H(e&&!e.13("1x"))e=e.1n;5 e&&c.l(e.13("1x"))};q.1X=/\\\\:/g;q.1w="@";q.J={};q.O=6(m,a,n,c,v){7 k=o.1w+m;8(!T[k]){a=o.1W(a,c||"",v||"");T[k]=a;T.z(a)}5 T[k].B};q.1Q=6(s){s=s.O(o.1X,"|");7 m;H(m=s.P(o.P)){7 r=o.O(m[0],m[1],m[2],m[3],m[4]);s=s.O(o.P,r)}5 s};q.1W=6(p,t,v){7 a={};a.B=o.1w+T.y;a.2F=p;t=o.J[t];t=t?t(o.13(p),1s(v)):L;a.l=12 2E("e","5 "+t);5 a};q.13=6(n){1d(n.2D()){F"B":5"e.B";F"2C":5"e.1V";F"9":5"e.2B";F"1T":8(U){5"1U((e.2A.P(/1T=\\\\1v?([^\\\\s\\\\1v]*)\\\\1v?/)||[])[1]||\'\')"}}5"e.13(\'"+n.O(N,":")+"\')"};q.J[""]=6(a){5 a};q.J["="]=6(a,v){5 a+"=="+1u.1S(v)};q.J["~="]=6(a,v){5"/(^| )"+R(v)+"( |$)/.l("+a+")"};q.J["|="]=6(a,v){5"/^"+R(v)+"(-|$)/.l("+a+")"};7 1R=18;18=6(s){5 1R(q.1Q(s))}});x.15("1j-2z",6(){D["~"]=6(r,f,t,n){7 e,i;9(i=0;(e=f[i]);i++){H(e=G(e)){8(17(e,t,n))r.z(e)}}};h["2y"]=6(e,t){t=12 1t(R(1s(t)));5 t.l(1e(e))};h["2x"]=6(e){5 e==Q(e).1H};h["2w"]=6(e){7 n,i;9(i=0;(n=e.1F[i]);i++){8(M(n)||n.1c==3)5 L}5 K};h["1N-10"]=6(e){5!G(e)};h["2v-10"]=6(e){e=e.1n;5 1r(e)==1P(e)};h["2u"]=6(e,s){7 n=x(s,Q(e));9(7 i=0;i<n.y;i++){8(n[i]==e)5 L}5 K};h["1O-10"]=6(e,a){5 1p(e,a,16)};h["1O-1N-10"]=6(e,a){5 1p(e,a,G)};h["2t"]=6(e){5 e.B==2s.2r.Z(1)};h["1M"]=6(e){5 e.1M};h["2q"]=6(e){5 e.1q===L};h["1q"]=6(e){5 e.1q};h["1L"]=6(e){5 e.1L};q.J["^="]=6(a,v){5"/^"+R(v)+"/.l("+a+")"};q.J["$="]=6(a,v){5"/"+R(v)+"$/.l("+a+")"};q.J["*="]=6(a,v){5"/"+R(v)+"/.l("+a+")"};6 1p(e,a,t){1d(a){F"n":5 K;F"2p":a="2n";1a;F"2o":a="2n+1"}7 1m=1o(e.1n);6 1k(i){7 i=(t==G)?1m.y-i:i-1;5 1m[i]==e};8(!Y(a))5 1k(a);a=a.1l("n");7 m=1K(a[0]);7 s=1K(a[1]);8((Y(m)||m==1)&&s==0)5 K;8(m==0&&!Y(s))5 1k(s);8(Y(s))s=0;7 c=1;H(e=t(e))c++;8(Y(m)||m==1)5(t==G)?(c<=s):(s>=c);5(c%m)==s}});x.15("1j-2m",6(){U=1i("L;/*@2l@8(@\\2k)U=K@2j@*/");8(!U){X=6(e,t,n){5 n?e.2i("*",t):e.X(t)};14=6(e,n){5!n||(n=="*")||(e.2h==n)};1h=1g.1I?6(e){5/1J/i.l(Q(e).1I)}:6(e){5 Q(e).1H.1f!="2g"};1e=6(e){5 e.2f||e.1G||1b(e)};6 1b(e){7 t="",n,i;9(i=0;(n=e.1F[i]);i++){1d(n.1c){F 11:F 1:t+=1b(n);1a;F 3:t+=n.2e;1a}}5 t}}});19=K;5 x}();',62,190,'|||||return|function|var|if|for||||||||pseudoClasses||||test|||this||AttributeSelector|||||||cssQuery|length|push|fr|id||selectors||case|nextElementSibling|while||tests|true|false|thisElement||replace|match|getDocument|regEscape||attributeSelectors|isMSIE|cache||getElementsByTagName|isNaN|slice|child||new|getAttribute|compareNamespace|addModule|previousElementSibling|compareTagName|parseSelector|loaded|break|_0|nodeType|switch|getTextContent|tagName|document|isXML|eval|css|_1|split|ch|parentNode|childElements|nthChild|disabled|firstElementChild|getText|RegExp|Quote|x22|PREFIX|lang|_2|arguments|else|all|links|version|se|childNodes|innerText|documentElement|contentType|xml|parseInt|indeterminate|checked|last|nth|lastElementChild|parse|_3|add|href|String|className|create|NS_IE|remove|toString|ST|select|Array|null|_4|mimeType|lastChild|firstChild|continue|modules|delete|join|caching|error|nodeValue|textContent|HTML|prefix|getElementsByTagNameNS|end|x5fwin32|cc_on|standard||odd|even|enabled|hash|location|target|not|only|empty|root|contains|level3|outerHTML|htmlFor|class|toLowerCase|Function|name|first|level2|prototype|item|scopeName|toUpperCase|ownerDocument|Document|XML|Boolean|URL|unknown|typeof|nextSibling|previousSibling|visited|link|valueOf|clearCache|cat
3130ch|concat|constructor|callee|try'.split('|'),0,{}))
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.