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