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