PageSourceSearch

https://canadatattooshows.com/cms2t/res/vit-lib/ajax.js

js canadatattooshows.com collected 2026-10-09 22:41:33 UTC 37,070 bytes, 1,163 lines download raw bytes

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.