1/** ************************************************************************************************************************ **\ 2* 3* Set of classes and functions that will help generate and process AJAX queries. 4* 5* @package VIT-Lib 6* @subpackage Ajax 7* 8* @license MIT License 9* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 10* associated documentation files (the "Software"), to deal in the Software without restriction, including 11* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to 13* the following conditions: 14* 15* The above copyright notice and this permission notice shall be included in all copies or substantial 16* portions of the Software. 17* 18* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 19* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 20* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23* 24* @author Victor Denisenkov aka Mr.V!T 25* @copyright Copyright (c) 2008 - 2012 Victor Denisenkov aka Mr.V!T 26* @version 1.0 27* 28\** ************************************************************************************************************************ **/ 29 30/** //** ----= OBJECT vAjax =--------------------------------------------------------------------------------------\**//** \ 31* 32* Ajax procesing object. Implements both jQuery common ajax and ajaxUpload plugin for iframe upload tricks (for old 33* browsers). Designed to use together with server side vAjax object. Supports POST progress monitoring using server 34* side plugins like APC or HTML5 files API. By default enables progress monitoring for forms with files and progressbar 35* present. 36* 37* @package VIT-Lib 38* @subpackage Ajax 39* @category Helper 40* 41* @param string url - Path to controller to make request to. 42* 43* @param MIXED [data] - Data to post on request. Can be DOM form, HTML5 FormData object, jQuery selector 44* or object which points to form, or plain object with parameters. 45* 46* @param object [options] - Additional options if necessary. 47* 48* @todo Known bug: ajaxUpload can't handle server errors. Need workaround (possible write own iframe upload?) 49* 50\**//** ----------------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 51 52// ToDo: Cross domain support with both JSONP and Access-Control-Allow-Origin: * 53 54function vAjax (url, data, options) { 55 56 // Creating basic object with events assigned 57 var obj = vEventObject(['success', 'error', 'start', 'stop', 'done', 'progressStart', 'progressStop'], { 58 59 opt : { // Default object options 60 async : true, // Set FALSE to make sync call 61 simple : false, // Expect simple answers and threat them as success or trigger errors on those. 62 modern : true, // Allow or not modern APIs 63 64 progress : '.progressFill', // Default progressbar fill element selector. Can be replaced with callback or own selector. 65 progressNum : '.progressNum', // Default progressbar Numeric indicator. Will be set to current %. Ignored if callback given for fill. 66 progressOn : false, // Forces progress monitoring (not used currently). 67 68 progressUrl : '/upload/?key=', // Progress monitoring controller. Key marker will be added to end of this. 69 progressDelay : 500, // Delay before starting progress monitoring using server side plugin. 70 progressInterval : 500 // Interval to update progress. 71 }, //OBJECT options 72 73 resSplit : "-=-CUT-=-", // Unique marker used to split results. 74 75 controller : url, // Url to make request to. 76 source : data || {}, // Source given. 77 78 sourceForm : false, // Source form if available. 79 sourceData : {}, // Source data if available (if form given - will contain form inputs as array). 80 sourceElement : false, // Source form as jQuery pointer. 81 82 isModern : false, // HMTL5 usage marker. Will be set to TRUE if system decides to use HTML5 83 // formData and XHR2 to post data 84 85 Method : '', // Will store used upload method. 86 87 88 prgInterval : false, // Progress bar monitor interval resource 89 prgTimeout : false, // Progress bar monitoring timeout resource 90 91 _processor : false, // Stores custom XHR processor if specified. 92 93 /** //** ----= options =--------------------------------------------------------------------------------------\**//** \ 94 * 95 * Used to setup options on run time. 96 * 97 * @param object options - Data object with options to setup. 98 * 99 * @return SELF 100 * 101 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 102 options : function (options) { 103 104 options = options || {}; 105 106 // Merging options 107 jQuery.extend(this.opt, options); 108 109 // Testing browser to be modern 110 this.isModern = this.opt.modern && isXHR2(); 111 112 return this; 113 }, //FUNC options 114 115 /** //** ----= processor =------------------------------------------------------------------------------\**//** \ 116 * 117 * Custom processor is used to use external ajax xhr implementation. vAjax is passed as parameter to processor to 118 * allow implementation of final events. Processor should call .ajaxSuccess() / .ajaxError() for appropiate events. 119 * 120 * @param function proc - Processor callback. 121 * 122 * @return SELF 123 * 124 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 125 processor : function ( proc ) { 126 this._processor = proc; 127 return this; 128 }, //FUNC processor 129 130 /** //** ----= parseResult =------------------------------------------------------------------------------\**//** \ 131 * 132 * Prses and format result data. Generates result to pass to callbacks. For internal use. 133 * 134 * @param object result - Request responce. 135 * 136 * @return object - Object with result data. 137 * 138 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 139 parseResult : function (result) { 140 141 var self = this; 142
143 // Making sure that result have all vields 144 if ( !result.responseText ) 145 result.responseText = ''; 146 147 // ---- Preparing data ---- 148 149 // Preparing result wrapper 150 var data = { 151 152 req : self.sourceData, // Request source data. 153 154 status : { // Responce meta like status and fields list. Default one for simple responces. Full responce will provide own head. 155 major : (result.statusMinor == 'success'), // Major operation status TRUE or FALSE. Simples are TRUE normally. 156 minor : result.statusMinor, // Minor/detailed status as string (like 'success', 'error', 'warning', 'simple' etc) 157 code : result.status, // Satus code if available 158 text : result.statusText, // Request status text 159 full : false, // Full(complex) responce marker 160 fields : [] // Custom responce fileds/types list 161 }, //OBJECT meta 162 163 res : '' // Request basic response - whole simple request, or head/status message for complex response. Will be added with parsing below. 164 }; //OBJECT data 165 166 // Trying to split as complex result 167 var tmp = result.responseText.split(this.resSplit); 168 169 // Smth basic will present even for plain responce 170 // (for example in case of server script fatal erorrs). 171 // Correcting res to have at least smth 172 data.res = tmp[0] || ''; 173 174 // Determinig wether result was full(complex) or simple 175 data.status.full = tmp.length > 1; 176 177 // ---- Simple result ---- 178 179 // If got simple result (either error or success) 180 if ( !data.status.full ) { 181 182 // Updating status 183 data.status.major = data.status.major ? this.opt.simple : data.status.major; 184 data.status.minor = 'simple'; 185
186 // If simple is threating as error - filling result as status text (expecting server errors) 187 if ( !this.opt.simple && !data.status.text ) 188 data.status.text = data.res; 189 190 // Running callbacks 191 192 // We are done anyway, so triggering stop event, passing self as param 193 this.stop(data, this); 194 195 // Error/success 196 if ( data.status.major && this.opt.simple ) 197 this.success(data, this); 198 else 199 this.error(data, this); 200 201 // Both stop and done are called anyway, difference is calling order: stop, success/error, done 202 this.done(data, this); 203 204 return data; 205 206 } // If simple 207 208 // ---- Complex result head and fields ---- 209 210 // For full responce status - header will go second (after possible debug) 211 var head = JSON.parse(tmp[1]); 212 213 // Updating data status, merging existing response with given one 214 // Mergin only if no text supplied already (usually errors have text) 215 if ( !data.status.text ) 216 jQuery.extend(data.status, head); 217 218 // Looping through given fields (if present) and decoding them to response 219 var di = 2; 220 if ( head.fields ) { 221 222 for ( var name in head.fields ) { 223 224 // Decoding non scalar values 225 if ( !head.fields[name] ) { 226 data[name] = JSON.parse(tmp[di]); 227 } else { //IF need to decode 228 data[name] = tmp[di]; 229 } //IF no need to decode (scalar) 230 231 // Increasing split counter 232 di++; 233 } //FOR each field 234 235 } //IF was fields posted 236 237 // Running callbacks 238 239 // We are done anyway, so triggering stop event, passing self as param 240 this.stop(data, this); 241 242 // Error/success 243 if ( data.status.major ) 244 this.success(data, this); 245 else 246 this.error(data, this); 247 248 // Both stop and done are called anyway, difference is calling order: stop, success/error, done 249 this.done(data, this); 250 251 return data; 252 253 }, //FUNC parseResult 254 255// ==== CALLBAKCS ============================================================================================================== 256 257 /** //** ----= ajaxSuccess =------------------------------------------------------------------------------\**//** \ 258 * 259 * Ajax success event callback. For internal use, can be altered though. 260 * 261 * @see jQuery.ajax callbacks for parameters. 262 * 263 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 264 ajaxSuccess : function (res, status) { 265 266 this.ajaxProgressStop(100); 267 268 status = status || 'success'; 269 270 // Creating result object 271 return this.parseResult({ 272 responseText : res, 273 status : 0, 274 statusText : '', 275 statusMinor : status 276 }); //parseResult.result 277 278 }, //FUNC ajaxSuccess 279 280 /** //** ----= ajaxError =------------------------------------------------------------------------------\**//** \ 281 * 282 * Ajax Error event callback. For internal use, can be altered though. 283 * 284 * @see jQuery.ajax callbacks for parameters. 285 * 286 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 287 ajaxError : function (res, status) { 288 289 this.ajaxProgressStop('error'); 290 291 // Adding minor status to common result 292 res.statusMinor = status; 293 294 return this.parseResult(res); 295 296 }, //FUNC ajaxError 297 298 /** //** ----= ajaxXHR =--------------------------------------------------------------------------------------\**//** \ 299 * 300 * Ajax XHR callback. Used to alter jQuery XHR. 301 * 302 * @see jQuery.ajax callbacks for parameters. 303 * 304 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 305 ajaxXHR : function () { 306 307 var self = this; 308 309 var x = jQuery.ajaxSettings.xhr(); 310 311 // Adding listener only if really needed. If not - xhr goes back untouched 312 if ( this.hasProgress() ) { 313 314 // If have progress - good place to reset it 315 this.ajaxProgressStart(); 316 317 // We are sure that .upload exists: previously it was tested in .post() 318 x.upload.addEventListener('progress', function (e) { 319 320 if ( e.lengthComputable ) { 321 322 // Calculating procents 323 var proc = (e.loaded * 100) / e.total; 324 325 self.ajaxProgress( Math.floor(proc) ); 326 327 } //IF there is progress available 328 329 }, false); 330 331 } //IF need progress monitoring 332 333 return x; 334 }, //FUNC ajaxXHR 335 336// ==== Progress =============================================================================================================== 337 338 /** //** ----= getFormElement =------------------------------------------------------------------------------\**//** \ 339 * 340 * For internal use. Checks given parameter as for element. Mainly used for progress indication elements search. 341 * 342 * @param MIXED - jQuery selector to search. 343 * 344 * @return MIXED - jQuery element to use as progress element, or FALSE if not applicable. 345 * 346 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 347 getFormElement : function (el) { 348 349 // This does not assumes callback functions. Those should be checked outside this and processed separately. 350 351 // If already jQuery - only checking length 352 if ( isJQ(el) ) { 353 if ( el.length > 0 ) 354 return el; 355 356 return false;
357 } //IF jQuery given 358 359 // If string selector given - searching it within form 360 // Search on form or FALSE, done this way for optimization 361 // and to avoid multiple for updates with common class selectors 362 // If user needs global selector search - he still can pass ready jQuery or use callback 363 if ( isStr(el) ) { 364 365 // Not allowing selector search outside of form. 366 if ( !this.sourceElement ) 367 return false; 368 369 var j = this.sourceElement.find(el); 370 371 // If smth found - we're good to go 372 if ( j.length > 0 ) 373 return j; 374 375 return false; 376 } //IF string passsed 377 378 // At this point assuming that element is given as DOM element 379 // Then just wrapping it with jQuery 380 return jQuery(el); 381 382 }, //FUNC getFormElement 383 384 /** //** ----= progress =--------------------------------------------------------------------------------------\**//** \ 385 * 386 * Progress monitoring event. Triggers on progress update event. Can accept either callbacks or valid jQuery 387 * selectors (string, jQuery or DOMElement). Callbacks will get current precentage as parameter. In case if 388 * selector given - for progressBar system will set width, for numeric indicator will set .html(). jQuery selectors 389 * do not process errors or other status updates, though those will be passed into callbacks. 390 * 391 * @param MIXED bar[,num] - Progress bar and numeric bar callbacks or elements to process. 392 * 393 * @param bool [force] - Forcing progress event. If set to FALSE system will try to detect if progress 394 * monitoring is necessary. 395 * 396 * @return SELF 397 * 398 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 399 progress : function (bar, num, force) { 400 401 this.opt.progress = bar; 402 this.opt.progressNum = num; 403 404 this.opt.progressOn = force || false; 405 406 return this; 407 }, //FUNC progress 408 409 /** //** ----= hasProgress =------------------------------------------------------------------------------\**//** \ 410 * 411 * For internal use. Checks if need to even setup progress indication. 412 * 413 * @return MIXED - jQuery element to use as progress element, or 414 * 415 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 416 hasProgress : function () { 417 418 // Nothing to do if nothing is given as progress 419 if ( !this.opt.progress && !this.opt.progressNum ) 420 return false; 421 422 // Progress is always enabled for callbacks 423 // ToDo: review this behavior, mb add hasFiles for testing. 424 425 // If not callbacks - checking to be jQuery 426 if ( !isFunction(this.opt.progress) ) 427 this.opt.progress = this.getFormElement(this.opt.progress); 428 429 if ( !isFunction(this.opt.progressNum) ) 430 this.opt.progressNum = this.getFormElement(this.opt.progressNum); 431 432 // Now they are callback, jQuery or just disabled, so fast to check. Enough one of either. 433 if ( this.opt.progress || this.opt.progressNum ) 434 return true; 435 436 return false; 437 }, //FUNC hasProgress 438 439 /** //** ----= ajaxProgressStart =----------------------------------------------------------------------\**//** \ 440 * 441 * Resets progress elements if set. 442 * 443 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 444 ajaxProgressStart : function (proc) { 445 446 // If jQuery element set for progress - good to show them 447 448 if ( isJQ(this.opt.progress) ) 449 this.opt.progress.fadeIn(); 450 451 if ( isJQ(this.opt.progressNum) ) 452 this.opt.progressNum.fadeIn(); 453 454 this.ajaxProgress(0); 455 this.progressStart(0); 456 457 }, //FUNC ajaxProgressStart 458 459 /** //** ----= ajaxProgress =------------------------------------------------------------------------------\**//** \ 460 * 461 * Progress event callback. Used on progress monitoring. For internal use, can be altered though. 462 * 463 * @param int proc - Current progress precentage. 464 * 465 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 466 ajaxProgress : function (proc) { 467 468 // Nothing to do if nothing is given as progress 469 if ( !this.opt.progress && !this.opt.progressNum ) 470 return; 471 472 // For selectors processing only numeric proc 473 // Errors and other mess will be processed in callbacks if necessary 474 475 // ---- Progress bar ---- 476 477 if ( this.opt.progress ) { 478 479 // Can be callback or jQuery at this poing 480 if ( isFunction(this.opt.progress) ) 481 this.opt.progress(proc); 482 483 else if ( isNumeric(proc) ) 484 this.opt.progress.width(proc + '%'); 485 486 } //IF progress given 487 488 // ---- Numeric indicator ---- 489 490 if ( this.opt.progressNum ) { 491 492 // Can be callback or jQuery at this poing 493 if ( isFunction(this.opt.progressNum) ) 494 this.opt.progressNum(proc); 495 496 else if ( isNumeric(proc) ) 497 this.opt.progressNum.html( proc != 0 ? proc + '%' : ''); 498 499 } //IF progress given 500 501 }, //FUNC ajaxProgress 502
503 /** //** ----= ajaxProgressStop =------------------------------------------------------------------------------\**//** \ 504 * 505 * Forces progress monitoring stop. 506 * 507 * @param int proc - Current progress precentage. 508 * 509 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 510 ajaxProgressStop : function (proc) { 511 512 if ( this.prgInterval ) 513 clearInterval(this.prgInterval); 514 515 if ( this.prgTimeout ) 516 clearInterval(this.prgTimeout); 517 518 if ( this.hasProgress() ) 519 this.ajaxProgress(proc); 520 521 this.progressStop(proc); 522 523 }, //FUNC ajaxProgressStop 524 525// ==== Processors ============================================================================================================= 526 527 /** //** ----= hasFiles =--------------------------------------------------------------------------------------\**//** \ 528 * 529 * Checks if form or data object contains files inputs. 530 * 531 * @param jQuery form - Form element to search within. 532 * 533 * @return SELF 534 * 535 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 536 hasFiles : function ($source) { 537 538 // If jQuery for form given - just searching for file inputs 539 if ( isJQ($source) ) { 540 if ( $source.find('INPUT[type=file]').length > 0 ) 541 return true; 542 } //IF form given 543 else { 544 545 // Non modern browsers can't have files anyway 546 if ( !this.isModern ) 547 return false; 548 549 // Looking for files in dataObject 550 for ( var $i in $source ) { 551 552 // Doing className check in addition, 553 // because of sometimes weird brwosers passing data between windows 554 if ( $source[$i] instanceof File || getClassOf($source[$i]) === 'File' ) 555 return true; 556 } 557 } //IF dataObject 558 559 return false; 560 }, //FUNC hasFiles 561 562 /** //** ----= postArray =------------------------------------------------------------------------------\**//** \ 563 * 564 * For internal use. Sends data object using common jQuery ajax. Does not supports progress monitoring 565 * (no reason for arrays). 566 * 567 * @return SELF 568 * 569 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 570 postArray : function () { 571 572 var self = this; 573 574 this.Method = 'array'; 575 576 jQuery.ajax({ 577 type : 'POST', 578 dataType : 'text', 579 async : self.opt.async, 580 context : self, 581 url : self.controller, 582 data : self.sourceData, 583 success : self.ajaxSuccess, 584 error : self.ajaxError 585 }); //OBJECT jQuery.ajax.settings 586 587 return this; 588 }, //FUNC postArray 589 590 /** //** ----= postData =--------------------------------------------------------------------------------------\**//** \ 591 * 592 * For internal use. Sends data using formData object. Optionally uses xhr for progress monitoring. 593 * 594 * @return SELF 595 * 596 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 597 postData : function () { 598 599 var self = this; 600 var post = false; 601 var $form = this.sourceForm ? _jq(this.sourceForm) : false; 602 var $files = false; 603 604 // Marking method as data 605 this.Method = 'data'; 606 607 // Disabling empty files if happen on form 608 // Doing this to fix XHR multipart bug in some Safari versions 609 // https://bugs.webkit.org/show_bug.cgi?id=184490 610 611 if ( $form ) { 612 613 // Looking for non disabled file inputs 614 $files = $form.find('input[type="file"]:not([disabled])'); 615 $files.each( function () { 616 617 // Disabling input 618 if ( this.files.length == 0 ) 619 jQuery(this).prop('disabled', true); 620 621 }); //each file 622 623 } //IF form provided 624 625 // Need to generate FormData object 626 // Creating FormData from form, if one given 627 // Or using one if one come as sourceData 628 // Otherwise generating one from dataObject 629 630 if ( this.sourceData instanceof FormData ) { 631 post = this.sourceData 632 }
632 //IF sourceData is FormData 633 else if ( this.sourceForm ) { 634 post = new FormData(this.sourceForm); 635 } //IF form given 636 else { 637 post = new FormData(); 638 for ( var $i in this.sourceData ) 639 post.append($i, this.sourceData[$i]); 640 } //IF dataObject given 641 642 // Restoring disabled file inputs (see bugfix above) 643 if ( $files ) 644 $files.prop('disabled', false); 645 646 // Sending ajax using custom XHR 647 jQuery.ajax({ 648 type : 'POST', 649 dataType : 'text', 650 async : self.opt.async, 651 context : self, 652 url : self.controller, 653 data : post, 654 success : self.ajaxSuccess, 655 error : self.ajaxError, 656 657 // Disablong jQuery headers and source processing 658 contentType : false, 659 processData : false, 660 661 // Adding progress monitoring, upload listener will be added optionally if necessary 662 // With function wrapper to have proper this 663 xhr : function () { return self.ajaxXHR() } 664 }); //OBJECT jQuery.ajax.settings 665 666 return this; 667 668 }, //FUNC postData 669 670 /** //** ----= postFrame =------------------------------------------------------------------------------\**//** \ 671 * 672 * For internal use. Sends data using iframe send trick. Used to simulate ajax upload on classic systems. 673 * Uses ajaxupload jQuery plugin if available. Uses server side progress monitoring if necessary. 674 * 675 * @return SELF 676 * 677 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 678 postFrame : function () { 679 680 var self = this; 681 682 this.Method = 'frame'; 683 684 if ( !self.sourceForm ) 685 throw('Source form is not set.'); 686 687 // ---- Setting up progress ---- 688 689 // Saving test result, for later reuse 690 var prg = this.opt.progressUrl && this.hasProgress(); 691 692 if ( prg ) { 693 694 var sn = 'PRG' + randomString(); 695 696 // Adding additional inputs for monitoring on server side 697 this.sourceElement.append('<input type="hidden" name="UPLOAD_IDENTIFIER" value="' + sn + '" />'); 698 this.sourceElement.append('<input type="hidden" name="APC_UPLOAD_PROGRESS" value="' + sn + '" />'); 699 700 // Resetting filler 701 this.ajaxProgressStart(); 702 703 } //IF progress is set 704 705 // ---- Posting ---- 706 707 // Saving action and target, cuz ajaxUpload breaks them sometimes 708 var action = this.sourceForm.action; 709 var target = this.sourceForm.target; 710 711 jQuery.ajaxUpload ({ 712 type : 'POST', 713 dataType : 'text', 714 url : self.controller, 715 secureuri : false, 716 uploadform : self.sourceForm, 717 // Simulating context with wrappers 718 success : function ( res, status ) { self.ajaxSuccess(res, status) }, 719 error : function ( res, status ) { self.ajaxError(res, status) } 720 }); //AJAX 721 722 // ---- Monitoring progress ---- 723 724 if ( prg ) { 725 726 // Bar should start progressing with additional delay, to do not overflow on small files 727 self.prgTimeout = setTimeout( function () { 728 729 // Adding check timer 730 self.prgInterval = setInterval( function() { 731 732 jQuery.get(self.opt.progressUrl + sn, {}, function(data) { 733 734 self.ajaxProgress(data, self); 735 736 // If got 100 or error - stopping timer 737 if ( data == '100' || !isNumeric(data) ) { 738 clearInterval(self.prgInterval); 739 } //IF done 740 741 }); //FUNC jQuery.get.callback 742 743 }, self.opt.progressInterval); //FUNC setInterval.callback 744 }, self.opt.progressDelay); //FUNC setTimeout.callback 745 746 // Cleaning progress inputs 747 this.sourceElement.find('INPUT[name="APC_UPLOAD_PROGRESS"], INPUT[name="UPLOAD_IDENTIFIER"]').remove(); 748 } //IF progress set 749 750 // ---- Cleaning form ---- 751 752 this.sourceForm.action = action; 753 this.sourceForm.target = target; 754 755 return this; 756 }, //FUNC postFrame 757 758 /** //** ----= post =--------------------------------------------------------------------------------------\**//** \ 759 * 760 * Fires request with settings given. 761 * 762 * @return SELF 763 * 764 \**//** --------------------------------------------------------------------------------------= by Mr.V!T =----/** //**/ 765 post : function () { 766 767 // ---- Checking source ---- 768 769 var source = this.source; // Just shortcut 770 771 // Making sure that there is smth meaningfull 772 if ( !source ) 773 source = {}; 774 775 // Restting sources 776 this.sourceElement = false; // jQuery pointer to form element 777 this.sourceForm = false; // DOM form element 778 this.sourceData = source; // By default assuming data object or formData 779
780 // Converting jQuery selector to jQuery 781 if ( typeof this.source == 'string' ) 782 source = jQuery(this.source); 783 784 // Getting DOM form from jQuery 785 if ( source instanceof jQuery ) { 786 787 if ( source.length < 1 ) 788 throw('Source form is not found.'); 789 790 // Saving jQuery 791 this.sourceElement = source; 792 source = source.get(0); 793 } //IF got jQuery 794 795 // At this step source should be either DOM form or data object 796 // Checking it and setting sources 797 // ToDo: tricky check for DOM form, improove 798 if ( source.elements ) { 799 800 // Trying to correct url using form action 801 if ( !this.controller ) 802 this.controller = source.action; 803 804 this.sourceForm = source; 805 806 // Serializing form as array anyway for callbacks 807 this.sourceData = formToArray(source); 808 809 // Adding jQuery if not already there 810 if ( !this.sourceElement ) 811 this.sourceElement = jQuery(source); 812 813 } //If got form 814 815 // ---- Testing environment ---- 816 817 // If still no controller (even after from action correction) - nothing to do 818 if ( !this.controller ) 819 throw('Destination url is not set.'); 820 821 // ---- Selecting method and sending ---- 822 823 // Triggering start event, passing self as param 824 this.start(this); 825 826 // In most cases postData will be used 827 // Only reason to use tricky frame ajaxUpload is in old browser 828 // and files really present on form 829 // Of course if ajaxUpload is available 830 // So checking it in complexity order i.e. easyer checks goes first 831 832 // Checking if custom processor is given 833 if ( isFunction(this._processor) ) { 834 this._processor(this); 835 return this; 836 } //IF custom processor 837 838 // Form data is always served with postData 839 if ( this.isModern && this.sourceData instanceof FormData ) 840 return this.postData(); 841 842 // If form or files were not given uploading with common jQuery 843 // Non modern browser can't have files anyway 844 if ( !this.sourceForm && !this.hasFiles(this.sourceData) ) 845 return this.postArray(); 846 847 // If modern - using formData for all other cases 848 if ( this.isModern ) 849 return this.postData(); 850 851 // If form is not for files, and modern uploading is not available - uploading as array 852 if ( this.sourceForm.enctype != 'multipart/form-data' ) 853 return this.postArray(); 854 855 // Now looking for files on form (last chance to not use .postFrame() ) 856 if ( !this.hasFiles(this.sourceElement) ) 857 return this.postArray(); 858 859 // Finally we tried everything, have to use ajaxUpload 860 // Testing if ajaxUpload even exists first 861 if ( !isSet(jQuery.ajaxUpload) ) 862 throw('Can\'t upload files with ajax on this browser.'); 863 864 return this.postFrame(); 865 } //FUNC post 866 867 }); //OBJECT vAjax 868 869 // Setting options on startup 870 obj.options(options); 871 872 return obj; 873 874} //CONSTRUCTOR vAjax 875 876// #### DEPRECATED ############################################################################################################# 877 878var ajaxReturn = function (status_place, destination) { 879 if (status_place) this.statusPlace = status_place; 880 if (destination) this.controller = destination; 881} //CONSTRUCTOR ajaxReturn 882 883ajaxReturn.prototype = { 884 controller : '', 885 post : {}, 886 ModalDialog : '', 887 ModalLoader : '', 888 statusPlace : '', 889 890 onSuccess : function (data) {}, 891 onError : function (data) {}, 892 onFail : function (data) {}, 893 onSimple : function (data) {}, 894 onStart : function () {}, 895 onStatus : function (html) {}, 896 onProgress : function (proc) {}, 897 898 parseResult : function (result) { 899 900 var res = {}; 901 res._post = this.post; 902 903 var data = result.split('-=-CUT-=-'); 904 res._message = data[0]; 905 if ( !res._message ) res._message = ''; 906 907 res._fullhead = data.length != 1; 908 909 if (res._fullhead) { 910 var head = JSON.parse(data[1]); 911 res._major = head.major; 912 res._minor = head.minor; 913 res._status = head.minor; 914 res._fields = head.fields; 915// res.data = []; 916 var di = 2; 917 if ( res._fields.length != 0 ) { 918 for (i = 0; i < res._fields.length; i++) { 919 res[res._fields[i]] = data[di]; 920 di++; 921 } //FOR each field 922 } //IF was fields posted 923 } //IF was full result 924 return res; 925 },//FUNC parseResult 926 927 /*--------------------------------------------------------------------------------*\ 928 | DoStatus 929 |---------------------------------------------------------------------------------- 930 | Updates status. 931 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 932 | Params: 933 | message string - Status message to display. 934 | callback funciton - Funciton to call. 935 | data MIXED - Data to pass to callback function. 936 | Return: 937 | bool - ALways FALSE. 938 \*--------------------------------------------------------------= by Mr.V!T =-----*/ 939 DoStatus : function (message, callback, data) { 940 941 if ( this.statusPlace && message ) jQuery('#'+this.statusPlace).html( status_string(message) ); 942 943 if ( callback instanceof Function ) callback(data); 944 945 this.doModals('finish'); 946 947 return false;
948 }, //FUNC DoStatus 949 950 ajax_success : function (res) { 951 var data = this.parseResult(res); 952 953 if (this.statusPlace) jQuery('#'+this.statusPlace).html(data._message); 954 955 var cb = this.onSimple; 956 if ( data._fullhead ) 957 cb = ( data._major )? this.onSuccess : this.onError; 958 959 this.DoStatus('', cb, data); 960 961 }, //FUNC sucess 962 963 ajax_error : function (message, res) { 964 965 this.DoStatus(message, this.onFail, res); 966 967 }, //FUNC error 968 969 postForm : function (form_id) { 970 var _ar = this; 971 972 if (!_ar.controller) return this.DoStatus('Invalid destination. Aborting.'); 973 974 if ( !form_id ) return this.postData(); 975 976 var form = (form_id.elements)? form_id : document.getElementById(form_id); 977 if ( !form.elements ) return this.DoStatus('Can\'t find data to POST. Aborting.'); 978 979 if ( form.enctype != 'multipart/form-data' ) return this.postData( formToArray(form) ); 980 981 //if ( _ar.statusPlace ) insert_bar(_ar.statusPlace); 982 983 this.doModals('start'); 984 985 this.onStart(); 986 987 var old_action = form.action; 988 989 jQuery.ajaxUpload ({ 990 type : 'POST', dataType : 'html', 991 url : _ar.controller, 992 secureuri : false, 993 uploadform : form, 994 success : function (res) { 995 _ar.ajax_success(res); 996 }, //FUNC success 997 error : function (res, status) { 998 _ar.ajax_error(res.statusText, res.responseText); 999 } //FUNC error 1000 }); //AJAX 1001 1002 form.action = old_action; 1003 form.target = ''; 1004 1005 return false; 1006 }, //FUNC postForm 1007 1008 postData : function (post_data) { 1009 1010 if ( !post_data ) post_data = {}; 1011 1012 // post_data = arrayToPost(post_data); 1013 1014 this.post = post_data; 1015 var _ar = this; 1016 1017 //if ( _ar.statusPlace ) insert_bar(_ar.statusPlace); 1018 1019 this.doModals('start'); 1020 1021 if (!_ar.controller) return this.DoStatus('Invalid destination. Aborting.'); 1022 1023 this.onStart(); 1024 1025 jQuery.ajax({ 1026 type : 'POST', dataType: 'html', 1027 url : _ar.controller, 1028 data : post_data, 1029 success : function (res) { 1030 _ar.ajax_success(res); 1031 }, //FUNC success 1032 error : function (res, status) { 1033 _ar.ajax_error(res.statusText, res.responseText); 1034 } //FUNC error 1035 }); //AJAX 1036 1037 return false; 1038 }, //FUNC postData 1039 1040 postFormData : function (post_data) { 1041 1042 this.post = post_data; 1043 var _ar = this; 1044 var self = this; 1045 1046 this.doModals('start'); 1047 1048 if (!_ar.controller) return this.DoStatus('Invalid destination. Aborting.'); 1049 1050 this.onStart(); 1051 1052 jQuery.ajax({ 1053 type : 'POST', dataType: 'html', 1054 url : _ar.controller, 1055 data : post_data, 1056 contentType : false, 1057 processData : false, 1058 1059 success : function (res) { 1060 _ar.ajax_success(res); 1061 }, //FUNC success 1062 1063 error : function (res,status) { 1064 _ar.ajax_error(res.statusText, res.responseText); 1065 }, //FUNC error 1066 1067 // Attempting to alter xhr to add progress listener 1068 xhr : function() { 1069 1070 var req = $.ajaxSettings.xhr(); 1071 1072 if (req) { 1073 1074 req.upload.addEventListener('progress', function(e) { 1075 1076 if ( e.lengthComputable ) { 1077 var proc = (e.loaded * 100) / e.total; 1078 1079 self.onProgress( Math.floor(proc) ); 1080 1081 } //IF there is progress available 1082 1083 }, false); //FUNC XHR.upload.onProgress 1084 1085 } //IF xhr returned 1086 1087 return req; 1088 } //FUNC xhr 1089 1090 }); //AJAX 1091 1092 return false; 1093 }, //FUNC postFormData 1094 1095 /*--------------------------------------------------------------------------------*\need 1096 | post 1097 |---------------------------------------------------------------------------------- 1098 | Autoselects best post method and posts source. 1099 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1100 | Params: 1101 | source MIXED - Data source. 1102 | Return: 1103 | bool - Always FALSE. 1104 \*--------------------------------------------------------------= by Mr.V!T =-----*/ 1105 post : function (source) { 1106 1107 if ( typeof source == 'string' ) return this.postForm(source); 1108 if ( source.elements ) return this.postForm(source); 1109 1110 if ( source instanceof FormData ) return this.postFormData(source); 1111 1112 return this.postData(source); 1113 }, //FUNC post 1114 1115 /*--------------------------------------------------------------------------------*\ 1116 | setModals 1117 |---------------------------------------------------------------------------------- 1118 | Set modal windows parameters. 1119 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1120 | Params: 1121 | dialog string - ID of window to use as Dialog. 1122 | loader string - ID of window to use as loader window. 1123 | Return: 1124 | SELF 1125 \*--------------------------------------------------------------= by Mr.V!T =-----*/ 1126 setModals : function (dialog, loader) { 1127 1128 this.ModalDialog = dialog; 1129 1130 if ( !loader ) return this; 1131
1132 tmp = document.getElementById(loader); 1133 if ( !tmp ) return this; 1134 1135 this.ModalLoader = loader; 1136 1137 return this; 1138 }, //FUNC setModals 1139 1140 /*--------------------------------------------------------------------------------*\ 1141 | doModals 1142 |---------------------------------------------------------------------------------- 1143 | Displays or hides modals windows. 1144 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1145 | Params: 1146 | mode string - Status mode: 1147 | 'start' - Set starting mode. 1148 | *other* - Finished mode. 1149 | Return: 1150 | NULL 1151 \*--------------------------------------------------------------= by Mr.V!T =-----*/ 1152 doModals : function ( mode ) { 1153 1154 if ( mode == 'start' ) { 1155 if ( this.ModalLoader ) { 1156 jQuery('#'+this.ModalDialog).jqm(); 1157 jQuery('#'+this.ModalDialog).jqmHide(); 1158 jqmShowCentered('#'+this.ModalLoader); 1159 } //IF loader is set 1160 1161 if ( this.ModalDialog && !this.ModalLoader ) jqmShowCentered('#'+this.ModalDialog); 1162 } else { //IF 1163 if ( this.ModalLoader ) jQuery('#'+this.ModalLoader).jqmHide(); 1164 if ( this.ModalDialog ) jqmShowCentered('#'+this.ModalDialog); 1165 } //IF 1166 1167 } //FUNC doModals 1168 1169} //CLASS ajaxReturn
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.