1 /* 2 SpiderGL Computer Graphics Library 3 Copyright (c) 2010, Marco Di Benedetto - Visual Computing Lab, ISTI - CNR 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions are met: 8 * Redistributions of source code must retain the above copyright 9 notice, this list of conditions and the following disclaimer. 10 * Redistributions in binary form must reproduce the above copyright 11 notice, this list of conditions and the following disclaimer in the 12 documentation and/or other materials provided with the distribution. 13 * Neither the name of SpiderGL nor the 14 names of its contributors may be used to endorse or promote products 15 derived from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY 21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @fileOverview IO 31 */ 32 33 /** 34 * The SpiderGL.IO namespace. 35 * 36 * @namespace The SpiderGL.IO namespace. 37 */ 38 SpiderGL.IO = { }; 39 40 /** 41 * Creates a SpiderGL.IO.Request. 42 * 43 * SpiderGL.IO.Request is the base class for I/O requests. 44 * 45 * @class The SpiderGL.IO.Request is the base class for I/O requests. 46 * 47 * @augments SpiderGL.Core.ObjectBase 48 */ 49 SpiderGL.IO.Request = function (url, options) { 50 SpiderGL.Core.ObjectBase.call(this); 51 52 options = SpiderGL.Utility.getDefaultObject({ 53 async : SpiderGL.IO.Request.DEFAULT_ASYNC, 54 send : SpiderGL.IO.Request.DEFAULT_SEND, 55 onProgress : null, 56 onCancel : null, 57 onError : null, 58 onSuccess : null, 59 onFinish : null 60 }, options); 61 62 this._url = url; 63 this._async = options.async; 64 this._status = SpiderGL.IO.Request.NONE; 65 this._sent = false; 66 this._aborted = false; 67 this._data = null; 68 this._loaded = 0; 69 this._total = 0; 70 71 this._events = { 72 progress : { main : null, listeners : [ ] }, 73 cancel : { main : null, listeners : [ ] }, 74 error : { main : null, listeners : [ ] }, 75 success : { main : null, listeners : [ ] }, 76 finish : { main : null, listeners : [ ] } 77 }; 78 79 this.onProgress = options.onProgress; 80 this.onCancel = options.onCancel; 81 this.onError = options.onError; 82 this.onSuccess = options.onSuccess; 83 this.onFinish = options.onFinish; 84 }; 85 86 SpiderGL.IO.Request.NONE = 0; 87 SpiderGL.IO.Request.ONGOING = 1; 88 SpiderGL.IO.Request.CANCELLED = 2; 89 SpiderGL.IO.Request.FAILED = 3; 90 SpiderGL.IO.Request.SUCCEEDED = 4; 91 92 SpiderGL.IO.Request.DEFAULT_ASYNC = true; 93 SpiderGL.IO.Request.DEFAULT_SEND = true; 94 95 SpiderGL.IO.Request.prototype = { 96 _indexOf : function (handlers, h) { 97 for (var i=0, n=handlers.length; i<n; ++i) { 98 if (handlers[i] == h) { 99 return i; 100 } 101 } 102 return -1; 103 }, 104 105 _setMainListener : function (eventName, eventHandler) { 106 var evt = this._events[eventName]; 107 if (!evt) return; 108 if (evt.main == eventHandler) return; 109 if (eventHandler) { this.addEventListener(eventName, eventHandler); } 110 else { this.removeEventListener(eventName, eventHandler); } 111 evt.main = eventHandler; 112 }, 113 114 _dispatch : function () { 115 var name = arguments[0]; 116 var evt = this._events[name]; 117 if (!evt) return; 118 var args = Array.prototype.slice.call(arguments, 1); 119 args.push(this); 120 var lst = evt.listeners; 121 for (var i=0, n=lst.length; i<n; ++i) { 122 lst[i].apply(null, args); 123 } 124 }, 125 126 _doPostProgress : function () { 127 }, 128 129 _doPostCancel : function () { 130 }, 131 132 _doPostError : function () { 133 }, 134 135 _doPostSuccess : function () { 136 }, 137 138 _doPostFinish : function () { 139 }, 140 141 _doOnProgress : function (loaded, total) { 142 if (this._aborted) return; 143 this._loaded = loaded; 144 this._total = total; 145 this._doPostProgress(); 146 this._dispatch("progress", this._loaded, this._total); 147 }, 148 149 _doOnCancel : function () { 150 if (this._aborted) return; 151 this._status = SpiderGL.IO.Request.CANCELLED; 152 this._finishTime = SpiderGL.Utility.getTime(); 153 this._doPostCancel(); 154 this._dispatch("cancel"); 155 }, 156 157 _doOnError : function () { 158 if (this._aborted) return; 159 this._status = SpiderGL.IO.Request.FAILED; 160 this._finishTime = SpiderGL.Utility.getTime(); 161 this._doPostError(); 162 this._dispatch("error"); 163 }, 164 165 _doOnSuccess : function () { 166 if (this._aborted) return; 167 this._status = SpiderGL.IO.Request.SUCCEEDED; 168 this._finishTime = SpiderGL.Utility.getTime(); 169 this._doPostSuccess(); 170 this._dispatch("success"); 171 }, 172 173 _doOnFinish : function () { 174 this._doPostFinish(); 175 this._dispatch("finish"); 176 }, 177 178 _doSend : function () { 179 return false; 180 }, 181 182 _doCancel : function () { 183 return false; 184 }, 185 186 get canSend() { 187 return (this._url && !this._sent); 188 }, 189 190 get url() { 191 return this._url; 192 }, 193 194 set url(s) { 195 this.cancel(); 196 this._url = s; 197 }, 198 199 get status() { 200 return this._status; 201 }, 202 203 get data() { 204 return this._data; 205 }, 206 207 get bytesLoaded() { 208 return this._loaded; 209 }, 210 211 get bytesTotal() { 212 return this._total; 213 }, 214 215 get sent() { 216 return this._sent; 217 }, 218 219 get ongoing() { 220 return (this._status == SpiderGL.IO.Request.ONGOING); 221 }, 222 223 get cancelled() { 224 return (this._status == SpiderGL.IO.Request.CANCELLED); 225 }, 226 227 get failed() { 228 return (this._status == SpiderGL.IO.Request.FAILED); 229 }, 230 231 get succeeded() { 232 return (this._status == SpiderGL.IO.Request.SUCCEEDED); 233 }, 234 235 get finished() { 236 return (this.succeeded || this.failed || this.cancelled); 237 }, 238 239 get startTime() { 240 return this._startTime; 241 }, 242 243 get finishTime() { 244 return this._finishTime; 245 }, 246 247 get elapsedTime() { 248 if (this._startTime < 0) return 0; 249 if (this._finishTime < 0) return (SpiderGL.Utility.getTime() - this._startTime); 250 return (this._finishTime - this._startTime); 251 }, 252 253 addEventListener : function (eventName, eventHandler) { 254 if (!eventHandler) return; 255 var evt = this._events[eventName]; 256 if (!evt) return; 257 var idx = this._indexOf(evt.listeners, eventHandler); 258 if (idx >= 0) return; 259 evt.listeners.push(eventHandler); 260 }, 261 262 removeEventListener : function (eventName, eventHandler) { 263 var evt = this._events[eventName]; 264 if (!evt) return; 265 var idx = this._indexOf(evt.listeners, eventHandler); 266 if (idx < 0) return; 267 evt.listeners.splice(idx, 1); 268 }, 269 270 get onProgress() { 271 return this._events.progress.main; 272 }, 273 274 set onProgress(f) { 275 this._setMainListener("progress", f); 276 }, 277 278 get onCancel() { 279 return this._events.cancel.main; 280 }, 281 282 set onCancel(f) { 283 this._setMainListener("cancel", f); 284 }, 285 286 get onError() { 287 return this._events.error.main; 288 }, 289 290 set onError(f) { 291 this._setMainListener("error", f); 292 }, 293 294 get onSuccess() { 295 return this._events.success.main; 296 }, 297 298 set onSuccess(f) { 299 this._setMainListener("success", f); 300 }, 301 302 get onFinish() { 303 return this._events.finish.main; 304 }, 305 306 set onFinish(f) { 307 this._setMainListener("finish", f); 308 }, 309 310 cancel : function () { 311 if (!this.ongoing) { return false; } 312 this._status = SpiderGL.IO.Request.CANCELLED; 313 this._aborted = true; 314 var r = this._doCancel(); 315 this._finishTime = SpiderGL.Utility.getTime(); 316 return r; 317 }, 318 319 send : function () { 320 if (!this.canSend) { return false; } 321 this._data = null; 322 this._status = SpiderGL.IO.Request.ONGOING; 323 this._aborted = false; 324 this._sent = true; 325 this._finishTime = -1; 326 this._startTime = SpiderGL.Utility.getTime(); 327 var r = this._doSend(); 328 if (!r) { 329 this._startTime = -1; 330 this._status = SpiderGL.IO.Request.NONE; 331 this._sent = false; 332 }; 333 return r; 334 } 335 }; 336 337 SpiderGL.Type.extend(SpiderGL.IO.Request, SpiderGL.Core.ObjectBase); 338 339 /** 340 * Creates a SpiderGL.IO.XHRRequestBase. 341 * 342 * SpiderGL.IO.XHRRequestBase is the base class for I/O requests. 343 * 344 * @class The SpiderGL.IO.XHRRequestBase is the base class for I/O requests. 345 * 346 * @augments SpiderGL.IO.Request 347 */ 348 SpiderGL.IO.XHRRequestBase = function (url, options) { 349 options = options || { }; 350 SpiderGL.IO.Request.call(this, url, options); 351 352 var that = this; 353 354 var xhr = new XMLHttpRequest(); 355 this._xhr = xhr; 356 357 xhr.onprogress = function (evt) { that._xhrOnProgress(evt); }; 358 xhr.onabort = function () { that._doOnCancel(); that._doOnFinish(); }; 359 xhr.onerror = function () { that._doOnError(); that._doOnFinish(); }; 360 xhr.onload = function () { 361 var status = xhr.status; 362 if ((status === 0) || (status === 200) || (!!that._range && (status == 206))) { 363 that._doOnSuccess(); 364 } 365 else { 366 that._doOnError(); 367 } 368 that._doOnFinish(); 369 }; 370 371 this._range = null; 372 373 this._xhr.open("GET", this._url, this._async); 374 375 if ("range" in options) { 376 this._range = [ options.range[0], options.range[1] ]; 377 var rangeStr = "bytes=" + options.range[0] + "-" + options.range[1]; 378 xhr.setRequestHeader("Range", rangeStr); 379 } 380 381 this._prepareXHR(); 382 383 var send = SpiderGL.Utility.getDefaultValue(options.send, SpiderGL.IO.Request.DEFAULT_SEND); 384 if (send) { 385 this.send(); 386 } 387 }; 388 389 SpiderGL.IO.XHRRequestBase.prototype = { 390 _prepareXHR : function () { 391 }, 392 393 _doCancel : function () { 394 this._xhr.abort(); 395 this._xhr = new XMLHttpRequest(); 396 this._xhr.open("GET", this._url, this._async); 397 this._prepareXHR(); 398 return true; 399 }, 400 401 _doSend : function () { 402 this._xhr.send(); 403 return true; 404 }, 405 406 _xhrOnProgress : function (evt) { 407 var loaded = 0; 408 var total = 0; 409 if (evt && evt.lengthComputable) { 410 loaded = evt.loaded; 411 total = evt.total; 412 } 413 this._doOnProgress(loaded, total); 414 } 415 }; 416 417 SpiderGL.Type.extend(SpiderGL.IO.XHRRequestBase, SpiderGL.IO.Request); 418 419 /** 420 * Creates a SpiderGL.IO.XHRRequest. 421 * 422 * SpiderGL.IO.XHRRequest is the base class for I/O requests. 423 * 424 * @class The SpiderGL.IO.XHRRequest is the base class for I/O requests. 425 * 426 * @augments SpiderGL.IO.XHRRequestBase 427 */ 428 SpiderGL.IO.XHRRequest = function (url, options) { 429 SpiderGL.IO.XHRRequestBase.call(this, url, options); 430 }; 431 432 SpiderGL.IO.XHRRequest.prototype = { 433 _doPostSuccess : function () { 434 this._data = this._xhr.responseText; 435 }, 436 437 get xhr() { 438 return this._xhr; 439 }, 440 441 get response() { 442 return this.data; 443 } 444 }; 445 446 SpiderGL.Type.extend(SpiderGL.IO.XHRRequest, SpiderGL.IO.XHRRequestBase); 447 448 /** 449 * Creates a SpiderGL.IO.TextRequest. 450 * 451 * SpiderGL.IO.TextRequest is the base class for I/O requests. 452 * 453 * @class The SpiderGL.IO.TextRequest is the base class for I/O requests. 454 * 455 * @augments SpiderGL.IO.XHRRequestBase 456 */ 457 SpiderGL.IO.TextRequest = function (url, options) { 458 SpiderGL.IO.XHRRequestBase.call(this, url, options); 459 }; 460 461 SpiderGL.IO.TextRequest.prototype = { 462 _doPostSuccess : function () { 463 this._data = this._xhr.responseText; 464 }, 465 466 get text() { 467 return this.data; 468 } 469 }; 470 471 SpiderGL.Type.extend(SpiderGL.IO.TextRequest, SpiderGL.IO.XHRRequestBase); 472 473 /** 474 * Synchronous text read. 475 * This function is equivalent to issuing a SpiderGL.IO.TextRequest with the async flag set to false and no callbacks, and then reading its text property. 476 * 477 * @param {string} url The URL of the content 478 * 479 * @returns {string} The text content, or null on failure. 480 */ 481 SpiderGL.IO.readText = function (url) { 482 var r = new SpiderGL.IO.TextRequest(url, {async:false}); 483 return r.text; 484 }; 485 486 /** 487 * Asynchronous text read. 488 * This function creates a SpiderGL.IO.TextRequest with the async and seng flags set to true, overriding their values in the options parameter. 489 * 490 * @param {string} url The URL of the content 491 * @param {object} options The request options. 492 * 493 * @returns {SpiderGL.IO.TextRequest} The internally generated SpiderGL.IO.TextRequest. 494 */ 495 SpiderGL.IO.requestText = function (url, options) { 496 options = SpiderGL.Utility.getDefaultObject({ }, options); 497 options.async = true; 498 options.send = true; 499 var r = new SpiderGL.IO.TextRequest(url, options); 500 return r; 501 }; 502 503 /** 504 * Creates a SpiderGL.IO.JSONRequest. 505 * 506 * SpiderGL.IO.JSONRequest is the base class for I/O requests. 507 * 508 * @class The SpiderGL.IO.JSONRequest is the base class for I/O requests. 509 * 510 * @augments SpiderGL.IO.XHRRequestBase 511 */ 512 SpiderGL.IO.JSONRequest = function (url, options) { 513 SpiderGL.IO.XHRRequestBase.call(this, url, options); 514 }; 515 516 SpiderGL.IO.JSONRequest.prototype = { 517 _doPostSuccess : function () { 518 this._data = JSON.parse(this._xhr.responseText); 519 }, 520 521 get text() { 522 return this._xhr.responseText; 523 }, 524 525 get json() { 526 return this.data; 527 } 528 }; 529 530 SpiderGL.Type.extend(SpiderGL.IO.JSONRequest, SpiderGL.IO.XHRRequestBase); 531 532 /** 533 * Synchronous JSON object read. 534 * This function is equivalent to issuing a SpiderGL.IO.JSONRequest with the async flag set to false and no callbacks, and then reading its json property. 535 * 536 * @param {string} url The URL of the content 537 * 538 * @returns {object} The JSON-parsed object, or null on failure. 539 */ 540 SpiderGL.IO.readJSON = function (url) { 541 var r = new SpiderGL.IO.JSONRequest(url, {async:false}); 542 return r.json; 543 }; 544 545 /** 546 * Asynchronous JSON read. 547 * This function creates a SpiderGL.IO.JSONRequest with the async and seng flags set to true, overriding their values in the options parameter. 548 * 549 * @param {string} url The URL of the content 550 * @param {object} options The request options. 551 * 552 * @returns {SpiderGL.IO.JSONRequest} The internally generated SpiderGL.IO.JSONRequest. 553 */ 554 SpiderGL.IO.requestJSON = function (url, options) { 555 options = SpiderGL.Utility.getDefaultObject({ }, options); 556 options.async = true; 557 options.send = true; 558 var r = new SpiderGL.IO.JSONRequest(url, options); 559 return r; 560 }; 561 562 /** 563 * Creates a SpiderGL.IO.BinaryRequest. 564 * 565 * SpiderGL.IO.BinaryRequest is the base class for I/O requests. 566 * 567 * @class The SpiderGL.IO.BinaryRequest is the base class for I/O requests. 568 * 569 * @augments SpiderGL.IO.XHRRequestBase 570 */ 571 SpiderGL.IO.BinaryRequest = function (url, options) { 572 SpiderGL.IO.XHRRequestBase.call(this, url, options); 573 }; 574 575 SpiderGL.IO.BinaryRequest.prototype = { 576 _prepareXHR : function () { 577 var xhr = this._xhr; 578 var overrideMime = false; 579 580 /* 581 if (xhr.hasOwnProperty("responseType")) { 582 try { 583 xhr.responseType = "arraybuffer"; 584 } 585 catch (e) { 586 overrideMime = true; 587 } 588 } 589 else { 590 overrideMime = true; 591 } 592 */ 593 594 if (overrideMime) { 595 xhr.overrideMimeType("text/plain; charset=x-user-defined"); 596 } 597 598 xhr.responseType = "arraybuffer"; 599 }, 600 601 _setArrayBuffer : function () { 602 var xhr = this._xhr; 603 604 if (xhr.responseType == "arraybuffer") { 605 this._data = xhr.response; 606 } 607 else if (xhr.mozResponseArrayBuffer != null) { 608 this._data = xhr.mozResponseArrayBuffer; 609 } 610 else if (xhr.responseText != null) { 611 var data = new String(xhr.responseText); 612 var arr = new Array(data.length); 613 for (var i=0, n=data.length; i<n; ++i) { 614 arr[i] = data.charCodeAt(i) & 0xff; 615 } 616 this._data = (new Uint8Array(arr)).buffer; 617 } 618 else { 619 this._data = null; 620 } 621 }, 622 623 _doPostSuccess : function () { 624 this._setArrayBuffer(); 625 }, 626 627 get data() { 628 if (this.ongoing) { 629 this._setArrayBuffer(); 630 } 631 return this._data; 632 }, 633 634 get buffer() { 635 return this.data; 636 } 637 }; 638 639 SpiderGL.Type.extend(SpiderGL.IO.BinaryRequest, SpiderGL.IO.XHRRequestBase); 640 641 /** 642 * Synchronous binary data read. 643 * This function is equivalent to issuing a SpiderGL.IO.BinaryRequest with the async flag set to false and no callbacks, and then reading its buffer property. 644 * 645 * @param {string} url The URL of the content 646 * 647 * @returns {ArrayBuffer} The content binary data, or null on failure. 648 */ 649 SpiderGL.IO.readBinary = function (url) { 650 var r = new SpiderGL.IO.BinaryRequest(url, {async:false}); 651 return r.buffer; 652 }; 653 654 /** 655 * Asynchronous binary read. 656 * This function creates a SpiderGL.IO.BinaryRequest with the async and seng flags set to true, overriding their values in the options parameter. 657 * 658 * @param {string} url The URL of the content 659 * @param {object} options The request options. 660 * 661 * @returns {SpiderGL.IO.BinaryRequest} The internally generated SpiderGL.IO.BinaryRequest. 662 */ 663 SpiderGL.IO.requestBinary = function (url, options) { 664 options = SpiderGL.Utility.getDefaultObject({ }, options); 665 options.async = true; 666 options.send = true; 667 var r = new SpiderGL.IO.BinaryRequest(url, options); 668 return r; 669 }; 670 671 /** 672 * Creates a SpiderGL.IO.ImageRequest. 673 * 674 * SpiderGL.IO.ImageRequest is the base class for I/O requests. 675 * The request is always asynchronous, meaning that the async flag is ignored. 676 * 677 * @class The SpiderGL.IO.ImageRequest is the base class for I/O requests. 678 * 679 * @augments SpiderGL.IO.Request 680 */ 681 SpiderGL.IO.ImageRequest = function (url, options) { 682 options = options || { }; 683 SpiderGL.IO.Request.call(this, url, options); 684 685 var that = this; 686 687 var img = new Image(); 688 this._img = img; 689 this._data = img; 690 691 img.onabort = function () { that._doOnCancel(); that._doOnFinish(); }; 692 img.onerror = function () { that._doOnError(); that._doOnFinish(); }; 693 img.onload = function () { that._doOnSuccess(); that._doOnFinish(); }; 694 695 if (typeof img.onprogress != "undefined") { 696 img.onprogress = function (evt) { that._imgOnProgress(evt); }; 697 } 698 699 var send = SpiderGL.Utility.getDefaultValue(options.send, SpiderGL.IO.Request.DEFAULT_SEND); 700 if (send) { 701 this.send(); 702 } 703 }; 704 705 SpiderGL.IO.ImageRequest.prototype = { 706 _doPostSuccess : function () { 707 this._data = this._img; 708 }, 709 710 _doCancel : function () { 711 this._img.src = null; 712 this._img = new Image(); 713 return true; 714 }, 715 716 _doSend : function () { 717 this._img.src = this._url; 718 return true; 719 }, 720 721 _imgOnProgress : function (evt) { 722 var loaded = 0; 723 var total = 0; 724 if (evt && evt.lengthComputable) { 725 loaded = evt.loaded; 726 total = evt.total; 727 } 728 this._doOnProgress(loaded, total); 729 }, 730 731 get image() { 732 return this.data; 733 } 734 }; 735 736 SpiderGL.Type.extend(SpiderGL.IO.ImageRequest, SpiderGL.IO.Request); 737 738 /** 739 * Asynchronous image read. 740 * This function creates a SpiderGL.IO.ImageRequest with the async and seng flags set to true, overriding their values in the options parameter. 741 * 742 * @param {string} url The URL of the content 743 * @param {object} options The request options. 744 * 745 * @returns {SpiderGL.IO.ImageRequest} The internally generated SpiderGL.IO.ImageRequest. 746 */ 747 SpiderGL.IO.requestImage = function (url, options) { 748 options = SpiderGL.Utility.getDefaultObject({ }, options); 749 options.async = true; 750 options.send = true; 751 var r = new SpiderGL.IO.ImageRequest(url, options); 752 return r; 753 }; 754 755 /** 756 * Creates a SpiderGL.IO.AggregateRequest. 757 * 758 * SpiderGL.IO.AggregateRequest is the base class for I/O requests. 759 * 760 * @class The SpiderGL.IO.AggregateRequest is the base class for I/O requests. 761 * 762 * @augments SpiderGL.IO.Request 763 */ 764 SpiderGL.IO.AggregateRequest = function (options) { 765 options = options || { }; 766 SpiderGL.IO.Request.call(this, "*", options); 767 768 var that = this; 769 770 this._proxyOnProgress = function (loaded, total, req) { 771 that._reqOnProgress(loaded, total, req); 772 }; 773 774 this._proxyOnCancel = function (req) { 775 that._reqOnCancel(req); 776 }; 777 778 this._proxyOnError = function (req) { 779 that._reqOnError(req); 780 }; 781 782 this._proxyOnSuccess = function (req) { 783 that._reqOnSuccess(req); 784 }; 785 786 this._proxyOnFinish = function (req) { 787 that._reqOnFinish(req); 788 }; 789 790 this._aggrStartTime = -1; 791 this._aggrFinishTime = -1; 792 793 this._eventReq = null; 794 this._cancelledReqs = 0; 795 this._failedReqs = 0; 796 this._succeededReqs = 0; 797 this._requests = [ ]; 798 var requests = options.requests; 799 if (requests) { 800 for (var i=0, n=requests.length; i<n; ++i) { 801 var r = requests[i]; 802 if (r && !r.sent) { 803 this._installProxies(r); 804 this.addRequest(r); 805 } 806 } 807 } 808 809 var send = SpiderGL.Utility.getDefaultValue(options.send, SpiderGL.IO.Request.DEFAULT_SEND); 810 if (send) { 811 this.send(); 812 } 813 }; 814 815 SpiderGL.IO.AggregateRequest.prototype = { 816 _doPostCancel : function () { 817 if (!this._requestsFinished) { 818 this._status = SpiderGL.IO.Request.ONGOING; 819 } 820 }, 821 822 _doPostError : function () { 823 if (!this._requestsFinished) { 824 this._status = SpiderGL.IO.Request.ONGOING; 825 } 826 }, 827 828 _doPostSuccess : function () { 829 if (!this._requestsFinished) { 830 this._status = SpiderGL.IO.Request.ONGOING; 831 } 832 }, 833 834 _doCancel : function () { 835 var requests = this._requests; 836 for (var i=0, n=requests.length; i<n; ++i) { 837 requests[i].cancel(); 838 } 839 this._aggrFinishTime = SpiderGL.Utility.getTime(); 840 }, 841 842 _doSend : function () { 843 this._aggrStartTime = SpiderGL.Utility.getTime(); 844 var requests = this._requests; 845 for (var i=0, n=requests.length; i<n; ++i) { 846 requests[i].send(); 847 } 848 }, 849 850 get _requestsFinished() { 851 return ((this._cancelledReqs + this._failedReqs + this._succeededReqs) == this._requests.length); 852 }, 853 854 _installProxies : function (req) { 855 req.addEventListener("progress", this._proxyOnProgress); 856 req.addEventListener("cancel", this._proxyOnCancel); 857 req.addEventListener("error", this._proxyOnError); 858 req.addEventListener("success", this._proxyOnSuccess); 859 req.addEventListener("finish", this._proxyOnFinish); 860 }, 861 862 _uninstallProxies : function (req) { 863 req.removeEventListener("progress", this._proxyOnProgress); 864 req.removeEventListener("cancel", this._proxyOnCancel); 865 req.removeEventListener("error", this._proxyOnError); 866 req.removeEventListener("success", this._proxyOnSuccess); 867 req.removeEventListener("finish", this._proxyOnFinish); 868 }, 869 870 _reqOnProgress : function (loaded, total, req) { 871 var idx = this._indexOf(this._requests, req); 872 if (idx < 0) return; 873 this._eventReq = req; 874 this._doOnProgress(loaded, total); 875 this._eventReq = null; 876 }, 877 878 _reqOnCancel : function (req) { 879 var idx = this._indexOf(this._requests, req); 880 if (idx < 0) return; 881 this._eventReq = req; 882 //this._doOnCancel(); 883 this._cancelledReqs++; 884 if (this._requestsFinished) { 885 this._aggrFinishTime = SpiderGL.Utility.getTime(); 886 if (this._cancelledReqs == this._requests.length) { 887 this._eventReq = this; 888 this._doOnCancel(); 889 } 890 } 891 else { 892 } 893 this._eventReq = null; 894 }, 895 896 _reqOnError : function (req) { 897 var idx = this._indexOf(this._requests, req); 898 if (idx < 0) return; 899 this._eventReq = req; 900 //this._doOnError(); 901 this._failedReqs++; 902 if (this._requestsFinished) { 903 this._aggrFinishTime = SpiderGL.Utility.getTime(); 904 this._eventReq = this; 905 this._doOnError(); 906 } 907 this._eventReq = null; 908 }, 909 910 _reqOnSuccess : function (req) { 911 var idx = this._indexOf(this._requests, req); 912 if (idx < 0) return; 913 this._eventReq = req; 914 //this._doOnSuccess(); 915 this._succeededReqs++; 916 if (this._requestsFinished) { 917 this._aggrFinishTime = SpiderGL.Utility.getTime(); 918 this._eventReq = this; 919 if (this._failedReqs > 0) { 920 this._doOnError(); 921 } 922 else { 923 this._doOnSuccess(); 924 } 925 } 926 this._eventReq = null; 927 }, 928 929 _reqOnFinish : function (req) { 930 var idx = this._indexOf(this._requests, req); 931 if (idx < 0) return; 932 this._uninstallProxies(req); 933 this._eventReq = req; 934 //this._doOnFinish(); 935 if (this._requestsFinished) { 936 this._eventReq = this; 937 this._doOnFinish(); 938 } 939 this._eventReq = null; 940 }, 941 942 get eventSenderRequest() { 943 return this._eventReq; 944 }, 945 946 get requests() { 947 return this._requests.slice(); 948 }, 949 950 get requests$() { 951 return this._requests; 952 }, 953 954 get startTime() { 955 return this._aggrStartTime; 956 }, 957 958 get finishTime() { 959 return this._aggrFinishTime; 960 }, 961 962 get elapsedTime() { 963 if (this._aggrStartTime < 0) return 0; 964 if (this._aggrFinishTime < 0) return (SpiderGL.Utility.getTime() - this._aggrStartTime); 965 return (this._aggrFinishTime - this._aggrStartTime); 966 }, 967 968 addRequest : function (r) { 969 if (!r || this._sent) return; 970 var idx = this._indexOf(this._requests, r); 971 if (idx >= 0) return; 972 this._requests.push(r); 973 }, 974 975 removeRequest : function (r) { 976 if (!r || this._sent) return; 977 var idx = this._indexOf(this._requests, r); 978 if (idx < 0) return; 979 this._requests.splice(idx, 1); 980 } 981 }; 982 983 SpiderGL.Type.extend(SpiderGL.IO.AggregateRequest, SpiderGL.IO.Request); 984 985