PageSourceSearch

https://ruspublica.ru/bitrix/js/main/core/core_ajax.js

js ruspublica.ru collected 2026-10-08 09:02:40 UTC 40,595 bytes, 1,803 lines download raw bytes

1;(function(window){
2
3if (window.BX.ajax)
4	return;
5
6var
7	BX = window.BX,
8
9	tempDefaultConfig = {},
10	defaultConfig = {
11		method: 'GET', // request method: GET|POST
12		dataType: 'html', // type of data loading: html|json|script
13		timeout: 0, // request timeout in seconds. 0 for browser-default
14		async: true, // whether request is asynchronous or not
15		processData: true, // any data processing is disabled if false, only callback call
16		scriptsRunFirst: false, // whether to run _all_ found scripts before onsuccess call. script tag can have an attribute "bxrunfirst" to turn  this flag on only for itself
17		emulateOnload: true,
18		skipAuthCheck: false, // whether to check authorization failure (SHOUD be set to true for CORS requests)
19		start: true, // send request immediately (if false, request can be started manually via XMLHttpRequest object returned)
20		cache: true, // whether NOT to add random addition to URL
21		preparePost: true, // whether set Content-Type x-www-form-urlencoded in POST
22		headers: false, // add additional headers, example: [{'name': 'If-Modified-Since', 'value': 'Wed, 15 Aug 2012 08:59:08 GMT'}, {'name': 'If-None-Match', 'value': '0'}]
23		lsTimeout: 30, //local storage data TTL. useless without lsId.
24		lsForce: false //wheter to force query instead of using localStorage data. useless without lsId.
25/*
26other parameters:
27	url: url to get/post
28	data: data to post
29	onsuccess: successful request callback. BX.proxy may be used.
30	onfailure: request failure callback. BX.proxy may be used.
31	onprogress: request progress callback. BX.proxy may be used.
32
33	lsId: local storage id - for constantly updating queries which can communicate via localStorage. core_ls.js needed
34
35any of the default parameters can be overridden. defaults can be changed by BX.ajax.Setup() - for all further requests!
36*/
37	},
38	ajax_session = null,
39	loadedScripts = {},
40	loadedScriptsQueue = [],
41	r = {
42		'url_utf': /[^\034-\254]+/g,
43		'script_self': /\/bitrix\/js\/main\/core\/core(_ajax)*.js$/i,
44		'script_self_window': /\/bitrix\/js\/main\/core\/core_window.js$/i,
45		'script_self_admin': /\/bitrix\/js\/main\/core\/core_admin.js$/i,
46		'script_onload': /window.onload/g
47	};
48
49// low-level method
50BX.ajax = function(config)
51{
52	var status, data;
53
54	if (!config || !config.url || !BX.type.isString(config.url))
55	{
56		return false;
57	}
58
59	for (var i in tempDefaultConfig)
60		if (typeof (config[i]) == "undefined") config[i] = tempDefaultConfig[i];
61
62	tempDefaultConfig = {};
63
64	for (i in defaultConfig)
65		if (typeof (config[i]) == "undefined") config[i] = defaultConfig[i];
66
67	config.method = config.method.toUpperCase();
68
69	if (!BX.localStorage)
70		config.lsId = null;
71
72	if (BX.browser.IsIE())
73	{
74		var result = r.url_utf.exec(config.url);
75		if (result)
76		{
77			do
78			{
79				config.url = config.url.replace(result, BX.util.urlencode(result));
80				result = r.url_utf.exec(config.url);
81			} while (result);
82		}
83	}
84
85	if(config.dataType == 'json')
86		config.emulateOnload = false;
87
88	if (!config.cache && config.method == 'GET')
89		config.url = BX.ajax._uncache(config.url);
90
91	if (config.method == 'POST' && config.preparePost)
92	{
93		config.data = BX.ajax.prepareData(config.data);
94	}
95
96	var bXHR = true;
97	if (config.lsId && !config.lsForce)
98	{
99		var v = BX.localStorage.get('ajax-' + config.lsId);
100		if (v !== null)
101		{
102			bXHR = false;
103
104			var lsHandler = function(lsData) {
105				if (lsData.key == 'ajax-' + config.lsId && lsData.value != 'BXAJAXWAIT')
106				{
107					var data = lsData.value,
108						bRemove = !!lsData.oldValue && data == null;
109					if (!bRemove)
110						BX.ajax.__run(config, data);
111					else if (config.onfailure)
112						config.onfailure("timeout");
113
114					BX.removeCustomEvent('onLocalStorageChange', lsHandler);
115				}
116			};
117
118			if (v == 'BXAJAXWAIT')
119			{
120				BX.addCustomEvent('onLocalStorageChange', lsHandler);
121			}
122			else
123			{
124				setTimeout(function() {lsHandler({key: 'ajax-' + config.lsId, value: v})}, 10);
125			}
126		}
127	}
128
129	if (bXHR)
130	{
131		config.xhr = BX.ajax.xhr();
132		if (!config.xhr) return;
133
134		if (config.lsId)
135		{
136			BX.localStorage.set('ajax-' + config.lsId, 'BXAJAXWAIT', config.lsTimeout);
137		}
138
139		config.xhr.open(config.method, config.url, config.async);
140
141		if (!config.skipBxHeader && !BX.ajax.isCrossDomain(config.url))
142		{
143			config.xhr.setRequestHeader('Bx-ajax', 'true');
144		}
145
146		if (config.method == 'POST' && config.preparePost)
147		{
148			config.xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
149		}
150		if (typeof(config.headers) == "object")
151		{
152			for (i = 0; i < config.headers.length; i++)
153				config.xhr.setRequestHeader(config.headers[i].name, config.headers[i].value);
154		}
155
156		if(!!config.onprogress)
157		{
158			BX.bind(config.xhr, 'progress', config.onprogress);
159		}
160
161		var bRequestCompleted = false;
162		var onreadystatechange = config.xhr.onreadystatechange = function(additional)
163		{
164			if (bRequestCompleted)
165				return;
166
167			if (additional === 'timeout')
168			{
169				if (config.onfailure)
170				{
171					config.onfailure("timeout");
172				}
173
174				BX.onCustomEvent(config.xhr, 'onAjaxFailure', ['timeout', '', config]);
175
176				config.xhr.onreadystatechange = BX.DoNothing;
177				config.xhr.abort();
178
179				if (config.async)
180				{
181					config.xhr = null;
182				}
183			}
184			else
185			{
186				if (config.xhr.readyState == 4 || additional == 'run')
187				{
188					status = BX.ajax.xhrSuccess(config.xhr) ? "success" : "error";
189					bRequestCompleted = true;
190					config.xhr.onreadystatechange = BX.DoNothing;
191
192					if (status == 'success')
193					{
194						var authHeader = (!!config.skipAuthCheck || BX.ajax.isCrossDomain(config.url))
195							? false
196							: config.xhr.getResponseHeader('X-Bitrix-Ajax-Status');
197
198						if(!!authHeader && authHeader == 'Authorize')
199						{
200							if (config.onfailure)
201							{
202								config.onfailure("auth", config.xhr.status);
203							}
204
205							BX.onCustomEvent(config.xhr, 'onAjaxFailure', ['auth', config.xhr.status, config]);
206						}
207						else
208						{
209							var data = config.xhr.responseText;
210
211							if (config.lsId)
212							{
213								BX.localStorage.set('ajax-' + config.lsId, data, config.lsTimeout);
214							}
215
216							BX.ajax.__run(config, data);
217						}
218					}
219					else
220					{
221						if (config.onfailure)
222						{
223							config.onfailure("status", config.xhr.status);
224						}
225
226						BX.onCustomEvent(config.xhr, 'onAjaxFailure', ['status', config.xhr.status, config]);
227					}
228
229					if (config.async)
230					{
231						config.xhr = null;
232					}
233				}
234			}
235		};
236
237		if (config.async && config.timeout > 0)
238		{
239			setTimeout(function() {
240				if (config.xhr && !bRequestCompleted)
241				{
242					onreadystatechange("timeout");
243				}
244			}, config.timeout * 1000);
245		}
246
247		if (config.start)
248		{
249			config.xhr.send(config.data);
250
251			if (!config.async)
252			{
253				onreadystatechange('run');
254			}
255		}
256
257		return config.xhr;
258	}
259};
260
261BX.ajax.xhr = function()
262{
263	if (window.XMLHttpRequest)
264	{
265		try {return new XMLHttpRequest();} catch(e){}
266	}
267	else if (window.ActiveXObject)
268	{
269		try { return new window.ActiveXObject("Msxml2.XMLHTTP.6.0"); }
270			catch(e) {}
271		try { return new window.ActiveXObject("Msxml2.XMLHTTP.3.0"); }
272			catch(e) {}
273		try { return new window.ActiveXObject("Msxml2.XMLHTTP"); }
274			catch(e) {}
275		try { return new window.ActiveXObject("Microsoft.XMLHTTP"); }
276			catch(e) {}
277		throw new Error("This browser does not support XMLHttpRequest.");
278	}
279
280	return null;
281};
282
283BX.ajax.isCrossDomain = function(url, location)
284{
285	location = location || window.location;
286
287	//Relative URL gets a current protocol
288	if (url.indexOf("//") === 0)
289	{
290		url = location.protocol + url;
291	}
292
293	//Fast check
294	if (url.indexOf("http") !== 0)
295	{
296		return false;
297	}
298
299	var link = window.document.createElement("a");
300	link.href = url;
301
302	return  link.protocol !== location.protocol ||
303			link.hostname !== location.hostname ||
304			BX.ajax.getHostPort(link.protocol, link.host) !== BX.ajax.getHostPort(location.protocol, location.host);
305};
306
307BX.ajax.getHostPort = function(protocol, host)
308{
309	var match = /:(\d+)$/.exec(host);
310	if (match)
311	{
312		return match[1];
313	}
314	else
315	{
316		if (protocol === "http:")
317		{
318			return "80";
319		}
320		else if (protocol === "https:")
321		{
322			return "443";
323		}
324	}
325
326	return "";
327};
328
329BX.ajax.__prepareOnload = function(scripts)
330{
331	if (scripts.length > 0)
332	{
333		BX.ajax['onload_' + ajax_session] = null;
334
335		for (var i=0,len=scripts.length;i<len;i++)
336		{
337			if (scripts[i].isInternal)
338			{
339				scripts[i].JS = scripts[i].JS.replace(r.script_onload, 'BX.aja
339x.onload_' + ajax_session);
340			}
341		}
342	}
343
344	BX.CaptureEventsGet();
345	BX.CaptureEvents(window, 'load');
346};
347
348BX.ajax.__runOnload = function()
349{
350	if (null != BX.ajax['onload_' + ajax_session])
351	{
352		BX.ajax['onload_' + ajax_session].apply(window);
353		BX.ajax['onload_' + ajax_session] = null;
354	}
355
356	var h = BX.CaptureEventsGet();
357
358	if (h)
359	{
360		for (var i=0; i<h.length; i++)
361			h[i].apply(window);
362	}
363};
364
365BX.ajax.__run = function(config, data)
366{
367	if (!config.processData)
368	{
369		if (config.onsuccess)
370		{
371			config.onsuccess(data);
372		}
373
374		BX.onCustomEvent(config.xhr, 'onAjaxSuccess', [data, config]);
375	}
376	else
377	{
378		data = BX.ajax.processRequestData(data, config);
379	}
380};
381
382
383BX.ajax._onParseJSONFailure = function(data)
384{
385	this.jsonFailure = true;
386	this.jsonResponse = data;
387	this.jsonProactive = /^\[WAF\]/.test(data);
388};
389
390BX.ajax.processRequestData = function(data, config)
391{
392	var result, scripts = [], styles = [];
393	switch (config.dataType.toUpperCase())
394	{
395		case 'JSON':
396
397			BX.addCustomEvent(config.xhr, 'onParseJSONFailure', BX.proxy(BX.ajax._onParseJSONFailure, config));
398			result = BX.parseJSON(data, config.xhr);
399			BX.removeCustomEvent(config.xhr, 'onParseJSONFailure', BX.proxy(BX.ajax._onParseJSONFailure, config));
400
401			if(!!result && BX.type.isArray(result['bxjs']))
402			{
403				for(var i = 0; i < result['bxjs'].length; i++)
404				{
405					if(BX.type.isNotEmptyString(result['bxjs'][i]))
406					{
407						scripts.push({
408							"isInternal": false,
409							"JS": result['bxjs'][i],
410							"bRunFirst": config.scriptsRunFirst
411						});
412					}
413					else
414					{
415						scripts.push(result['bxjs'][i])
416					}
417				}
418			}
419
420			if(!!result && BX.type.isArray(result['bxcss']))
421			{
422				styles = result['bxcss'];
423			}
424
425		break;
426		case 'SCRIPT':
427			scripts.push({"isInternal": true, "JS": data, "bRunFirst": config.scriptsRunFirst});
428			result = data;
429		break;
430
431		default: // HTML
432			var ob = BX.processHTML(data, config.scriptsRunFirst);
433			result = ob.HTML; scripts = ob.SCRIPT; styles = ob.STYLE;
434		break;
435	}
436
437	var bSessionCreated = false;
438	if (null == ajax_session)
439	{
440		ajax_session = parseInt(Math.random() * 1000000);
441		bSessionCreated = true;
442	}
443
444	if (styles.length > 0)
445		BX.loadCSS(styles);
446
447	if (config.emulateOnload)
448			BX.ajax.__prepareOnload(scripts);
449
450	var cb = BX.DoNothing;
451	if(config.emulateOnload || bSessionCreated)
452	{
453		cb = BX.defer(function()
454		{
455			if (config.emulateOnload)
456				BX.ajax.__runOnload();
457			if (bSessionCreated)
458				ajax_session = null;
459			BX.onCustomEvent(config.xhr, 'onAjaxSuccessFinish', [config]);
460		});
461	}
462
463	try
464	{
465		if (!!config.jsonFailure)
466		{
467			throw {type: 'json_failure', data: config.jsonResponse, bProactive: config.jsonProactive};
468		}
469
470		config.scripts = scripts;
471
472		BX.ajax.processScripts(config.scripts, true);
473
474		if (config.onsuccess)
475		{
476			config.onsuccess(result);
477		}
478
479		BX.onCustomEvent(config.xhr, 'onAjaxSuccess', [result, config]);
480
481		BX.ajax.processScripts(config.scripts, false, cb);
482	}
483	catch (e)
484	{
485		if (config.onfailure)
486			config.onfailure("processing", e);
487		BX.onCustomEvent(config.xhr, 'onAjaxFailure', ['processing', e, config]);
488	}
489};
490
491BX.ajax.processScripts = function(scripts, bRunFirst, cb)
492{
493	var scriptsExt = [], scriptsInt = '';
494
495	cb = cb || BX.DoNothing;
496
497	for (var i = 0, length = scripts.length; i < length; i++)
498	{
499		if (typeof bRunFirst != 'undefined' && bRunFirst != !!scripts[i].bRunFirst)
500			continue;
501
502		if (scripts[i].isInternal)
503			scriptsInt += ';' + scripts[i].JS;
504		else
505			scriptsExt.push(scripts[i].JS);
506	}
507
508	scriptsExt = BX.util.array_unique(scriptsExt);
509	var inlineScripts = scriptsInt.length > 0 ? function() { BX.evalGlobal(scriptsInt); } : BX.DoNothing;
510
511	if (scriptsExt.length > 0)
512	{
513		BX.load(scriptsExt, function() {
514			inlineScripts();
515			cb();
516		});
517	}
518	else
519	{
520		inlineScripts();
521		cb();
522	}
523};
524
525// TODO: extend this function to use with any data objects or forms
526BX.ajax.prepareData = function(arData, prefix)
527{
528	var data = '';
529	if (BX.type.isString(arData))
530		data = arData;
531	else if (null != arData)
532	{
533		for(var i in arData)
534		{
535			if (arData.hasOwnProperty(i))
536			{
537				if (data.length > 0)
538					data += '&';
539				var name = BX.util.urlencode(i);
540				if(prefix)
541					name = prefix + '[' + name + ']';
542				if(typeof arData[i] == 'object')
543					data += BX.ajax.prepareData(arData[i], name);
544				else
545					data += name + '=' + BX.util.urlencode(arData[i]);
546			}
547		}
548	}
549	return data;
550};
551
552BX.ajax.xhrSuccess = function(xhr)
553{
554	return (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || xhr.status === 1223 || xhr.status === 0;
555};
556
557BX.ajax.Setup = function(config, bTemp)
558{
559	bTemp = !!bTemp;
560
561	for (var i in config)
562	{
563		if (bTemp)
564			tempDefaultConfig[i] = config[i];
565		else
566			defaultConfig[i] = config[i];
567	}
568};
569
570BX.ajax.replaceLocalStorageValue = function(lsId, data, ttl)
571{
572	if (!!BX.localStorage)
573		BX.localStorage.set('ajax-' + lsId, data, ttl);
574};
575
576
577BX.ajax._uncache = function(url)
578{
579	return url + ((url.indexOf('?') !== -1 ? "&" : "?") + '_=' + (new Date()).getTime());
580};
581
582/* simple interface */
583BX.ajax.get = function(url, data, callback)
584{
585	if (BX.type.isFunction(data))
586	{
587		callback = data;
588		data = '';
589	}
590
591	data = BX.ajax.prepareData(data);
592
593	if (data)
594	{
595		url += (url.indexOf('?') !== -1 ? "&" : "?") + data;
596		data = '';
597	}
598
599	return BX.ajax({
600		'method': 'GET',
601		'dataType': 'html',
602		'url': url,
603		'data':  '',
604		'onsuccess': callback
605	});
606};
607
608BX.ajax.getCaptcha = function(callback)
609{
610	return BX.ajax.loadJSON('/bitrix/tools/ajax_captcha.php', callback);
611};
612
613BX.ajax.insertToNode = function(url, node)
614{
615	node = BX(node);
616	if (!!node)
617	{
618		var eventArgs = { cancel: false };
619		BX.onCustomEvent('onAjaxInsertToNode', [{ url: url, node: node, eventArgs: eventArgs }]);
620		if(eventArgs.cancel === true)
621		{
622			return;
623		}
624
625		var show = null;
626		if (!tempDefaultConfig.denyShowWait)
627		{
628			show = BX.showWait(node);
629			delete tempDefaultConfig.denyShowWait;
630		}
631
632		return BX.ajax.get(url, function(data) {
633			node.innerHTML = data;
634			BX.closeWait(node, show);
635		});
636	}
637};
638
639BX.ajax.post = function(url, data, callback)
640{
641	data = BX.ajax.prepareData(data);
642
643	return BX.ajax({
644		'method': 'POST',
645		'dataType': 'html',
646		'url': url,
647		'data':  data,
648		'onsuccess': callback
649	});
650};
651
652/**
653 * BX.ajax with BX.Promise
654 *
655 * @param config
656 * @returns {BX.Promise|false}
657 */
658BX.ajax.promise = function(config)
659{
660	var result = new BX.Promise();
661
662	config.onsuccess = function(data)
663	{
664		result.fulfill(data);
665	};
666	config.onfailure = function(reason, data)
667	{
668		result.reject({
669			reason: reason,
670			data: data
671		});
672	};
673	config.onprogress = function(data)
674	{
675		if (data.position == 0 && data.totalSize == 0)
676		{
677			result.reject({
678				reason: 'progress',
679				data: data
680			});
681		}
682	};
683
684	var xhr = BX.ajax(config);
685	if (!xhr)
686	{
687		result.reject({
688			reason: "init",
689			data: false
690		});
691	}
692
693	return result;
694};
695
696/* load and execute external file script with onload emulation */
697BX.ajax.loadScriptAjax = function(script_src, callback, bPreload)
698{
699	if (BX.type.isArray(script_src))
700	{
701		for (var i=0,len=script_src.length;i<len;i++)
702		{
703			BX.ajax.loadScriptAjax(script_src[i], callback, bPreload);
704		}
705	}
706	else
707	{
708		var script_src_test = script_src.replace(/\.js\?.*/, '.js');
709
710		if (r.script_self.test(script_src_test)) return;
711		if (r.script_self_window.test(script_src_test) && BX.CWindow) return;
712		if (r.script_self_admin.test(script_src_test) && BX.admin) return;
713
714		if (typeof loadedScripts[script_src_test] == 'undefined')
715		{
716			if (!!bPreload)
717			{
718				loadedScripts[script_src_test] = '';
719				return BX.loadScript(script_src);
720			}
721			else
722			{
723				return BX.ajax({
724					url: script_src,
725					method: 'GET',
726					dataType: 'script',
727					processData: true,
728					emulateOnload: false,
729					scriptsRunFirst: true,
730					async: false,
731					start: true,
732					onsuccess: function(result) {
733						loadedScripts[script_src_test] = result;
734						if (callback)
735							callback(result);
736					}
737				});
738			}
739		}
740		else if (callback)
741		{
742			callback(loadedScripts[script_src_test]);
743		}
744	}
745};
746
747/* non-xhr loadings */
748BX.ajax.loadJSON = function(url, data, callback, callback_failure)
749{
750	if (BX.type.isFunction(data))
751	{
752		callback_failure = callback;
753		callback = data;
754		data = '';
755	}
756
757	data = BX.ajax.prepareData(data);
758
759	if (data)
760	{
761		url += (url.indexOf('?') !== -1 ? "&" : "?") + data;
762		data = '';
763	}
764
765	return BX.ajax({
766		'method': 'GET',
767		'dataType': 'json',
768		'url': url,
769		'onsuccess': callback,
770		'onfailure': callback_failure
771	});
772};
773
774
775var prepareAjaxGetParameters = function(config)
776{
777	var getParameters = {};
778	if (typeof config.analyticsLabel !== 'undefined')
779	{
780		getParameters.analyticsLabel = config.analyticsLabel;
781	}
782	if (typeof config.mode !== 'undefined')
783	{
784		getParameters.mode = config.mode;
785	}
786	if (config.navigation && config.navigation.page)
787	{
788		getParameters.nav = 'page-' + config.navigation.page;
789	}
790
791	return getParameters;
792};
793
794var prepareAjaxConfig = function(config)
795{
796	config = BX.type.isPlainObject(config) ? config : {};
797
798	if (config.data instanceof FormData)
799	{
800		config.preparePost = false;
801
802		config.data.append('sessid', BX.bitrix_sessid());
803		if (BX.message.SITE_ID)
804		{
805			config.data.append('SITE_ID', BX.message.SITE_ID);
806		}
807		if (typeof config.signedParameters !== 'undefined')
808		{
809			config.data.append('signedParameters', config.signedParameters);
810		}
811	}
812	else
813	{
814		config.data = BX.type.isPlainObject(config.data) ? config.data : {};
815		if (BX.message.SITE_ID)
816		{
817			config.data.SITE_ID = BX.message.SITE_ID;
818		}
819		config.data.sessid = BX.bitrix_sessid();
820		if (typeof config.signedParameters !== 'undefined')
821		{
822			config.data.signedParameters = config.signedParameters;
823		}
824	}
825
826	if (!config.method)
827	{
828		config.method = 'POST'
829	}
830
831	return config;
832};
833
834var buildAjaxPromiseToRestoreCsrf = function(config, withoutRestoringCsrf)
835{
836	withoutRestoringCsrf = withoutRestoringCsrf || false;
837	var originalConfig = BX.clone(config);
838	var promise = BX.ajax.promise(config);
839
840	return promise.then(function(response) {
841		if (!withoutRestoringCsrf && BX.type.isPlainObject(response) && BX.type.isArray(response.errors))
842		{
843			var csrfProblem = false;
844			response.errors.forEach(function(error) {
845				if (error.code === 'invalid_csrf' && error.customData.csrf)
846				{
847					BX.message({'bitrix_sessid': error.customData.csrf});
848					originalConfig.data.sessid = BX.bitrix_sessid();
849
850					csrfProblem = true;
851				}
852			});
853
854			if (csrfProblem)
855			{
856				return buildAjaxPromiseToRestoreCsrf(originalConfig, true);
857			}
858		}
859
860		if (!BX.type.isPlainObject(response) || response.status !== 'success')
861		{
862			var errorPromise = new BX.Promise();
863			errorPromise.reject(response);
864
865			return errorPromise;
866		}
867
868		return response;
869	});
870};
871
872/**
873 *
874 * @param {string} action
875 * @param {Object} config
876 * @param {?string} [config.analyticsLabel]
877 * @param {string} [config.method='POST']
878 * @param {Object} [config.data]
879 * @param {?Object} [config.headers]
880 * @param {?Object} [config.timeout]
881 * @param {Object} [config.navigation]
882 * @param {number} [config.navigation.page]
883 */
884BX.ajax.runAction = function(action, config)
885{
886	config = prepareAjaxConfig(config);
887	var getParameters = prepareAjaxGetParameters(config);
888	getParameters.action = action;
889
890	var url = BX.util.add_url_param('/bitrix/services/main/ajax.php', getParameters);
891
892	return buildAjaxPromiseToRestoreCsrf({
893		method: config.method,
894		dataType: 'json',
895		url: url,
896		data: config.data,
897		timeout: config.timeout,
898		preparePost: config.preparePost,
899		headers: config.headers
900	});
901};
902
903/**
904 *
905 * @param {string} component
906 * @param {string} action
907 * @param {Object} config
908 * @param {?string} [config.analyticsLabel]
909 * @param {?string} [config.signedParameters]
910 * @param {string} [config.method='POST']
911 * @param {string} [config.mode='ajax'] Ajax or class.
912 * @param {Object} [config.data]
913 * @param {?array} [config.headers]
914 * @param {?number} [config.timeout]
915 * @param {Object} [config.navigation]
916 */
917BX.ajax.runComponentAction = function (component, action, config)
918{
919	config = prepareAjaxConfig(config);
920	config.mode = config.mode || 'ajax';
921
922	var getParameters = prepareAjaxGetParameters(config);
923	getParameters.c = component;
924	getParameters.action = action;
925
926	var url = BX.util.add_url_param('/bitrix/services/main/ajax.php', getParameters);
927
928	return buildAjaxPromiseToRestoreCsrf({
929		method: config.method,
930		dataType: 'json',
931		url: url,
932		data: config.data,
933		timeout: config.timeout,
934		preparePost: config.preparePost,
935		headers: config.headers
936	});
937};
938
939/*
940arObs = [{
941	url: url,
942	type: html|script|json|css,
943	callback: function
944}]
945*/
946BX.ajax.load = function(arObs, callback)
947{
948	if (!BX.type.isArray(arObs))
949		arObs = [arObs];
950
951	var cnt = 0;
952
953	if (!BX.type.isFunction(callback))
954		callback = BX.DoNothing;
955
956	var handler = function(data)
957		{
958			if (BX.type.isFunction(this.callback))
959				this.callback(data);
960
961			if (++cnt >= len)
962				callback();
963		};
964
965	for (var i = 0, len = arObs.length; i<len; i++)
966	{
967		switch(arObs[i].type.toUpperCase())
968		{
969			case 'SCRIPT':
970				BX.loadScript([arObs[i].url], BX.proxy(handler, arObs[i]));
971			break;
972			case 'CSS':
973				BX.loadCSS([arObs[i].url]);
974
975				if (++cnt >= len)
976					callback();
977			break;
978			case 'JSON':
979				BX.ajax.loadJSON(arObs[i].url, BX.proxy(handler, arObs[i]));
980			break;
981
982			default:
983				BX.ajax.get(arObs[i].url, '', BX.proxy(handler, arObs[i]));
984			break;
985		}
986	}
987};
988
989/* ajax form sending */
990BX.ajax.submit = function(obForm, callback)
991{
992	if (!obForm.target)
993	{
994		if (null == obForm.BXFormTarget)
995		{
996			var frame_name = 'formTarget_' + Math.random();
997			obForm.BXFormTarget = document.body.appendChild(BX.create('IFRAME', {
998				props: {
999					name: frame_name,
1000					id: frame_name,
1001					src: 'javascript:void(0)'
1002				},
1003				style: {
1004					display: 'none'
1005				}
1006			}));
1007		}
1008
1009		obForm.target = obForm.BXFormTarget.name;
1010	}
1011
1012	obForm.BXFormCallback = callback;
1013	BX.bind(obForm.BXFormTarget, 'load', BX.proxy(BX.ajax._submit_callback, obForm));
1014
1015	BX.submit(obForm);
1016
1017	return false;
1018};
1019
1020BX.ajax.submitComponentForm = function(obForm, container, bWait)
1021{
1022	if (!obForm.target)
1023	{
1024		if (null == obForm.BXFormTarget)
1025		{
1026			var frame_name = 'formTarget_' + Math.random();
1027			obForm.BXFormTarget = document.body.appendChild(BX.create('IFRAME', {
1028				props: {
1029					name: frame_name,
1030					id: frame_name,
1031					src: 'javascript:void(0)'
1032				},
1033				style: {
1034					display: 'none'
1035				}
1036			}));
1037		}
1038
1039		obForm.target = obForm.BXFormTarget.name;
1040	}
1041
1042	if (!!bWait)
1043		var w = BX.showWait(container);
1044
1045	obForm.BXFormCallback = function(d) {
1046		if (!!bWait)
1047			BX.closeWait(w);
1048
1049		var callOnload = function(){
1050			if(!!window.bxcompajaxframeonload)
1051			{
1052				setTimeout(function(){window.bxcompajaxframeonload();window.bxcompajaxframeonload=null;}, 10);
1053			}
1054		};
1055
1056		BX(container).innerHTML = d;
1057		BX.onCustomEvent('onAjaxSuccess', [null,null,callOnload]);
1058	};
1059
1060	BX.bind(obForm.BXFormTarget, 'load', BX.proxy(BX.ajax._submit_callback, obForm));
1061
1062	return true;
1063};
1064
1065// func will be executed in form context
1066BX.ajax._submit_callback = function()
1067{
1068	//opera and IE8 triggers onload event even on empty iframe
1069	try
1070	{
1071		if(this.BXFormTarget.contentWindow.location.href.indexOf('http') != 0)
1072			return;
1073	} catch (e) {
1074		return;
1075	}
1076
1077	if (this.BXFormCallback)
1078		this.BXFormCallback.apply(this, [this.BXFormTarget.contentWindow.document.body.innerHTML]);
1079
1080	BX.unbindAll(this.BXFormTarget);
1081};
1082
1083BX.ajax.prepareForm = function(obForm, data)
1084{
1085	data = (!!data ? data : {});
1086	var i, ii, el,
1087		_data = [],
1088		n = obForm.elements.length,
1089		files = 0, length = 0;
1090	if(!!obForm)
1091	{
1092		for (i = 0; i < n; i++)
1093		{
1094			el = obForm.elements[i];
1095			if (el.disabled)
1096				continue;
1097
1098			if(!el.type)
1099				continue;
1100
1101			switch(el.type.toLowerCase())
1102			{
1103				case 'text':
1104				case 'textarea':
1105				case 'password':
1106				case 'number':
1107				case 'hidden':
1108				case 'select-one':
1109					_data.push({name: el.name, value: el.value});
1110					length += (el.name.length + el.value.length);
1111					break;
1112				case 'file':
1113					if (!!el.files)
1114					{
1115						for (ii = 0; ii < el.files.length; ii++)
1116						{
1117							files++;
1118							_data.push({name: el.name, value: el.files[ii], file : true});
1119							length += el.files[ii].size;
1120						}
1121					}
1122					break;
1123				case 'radio':
1124				case 'checkbox':
1125					if(el.checked)
1126					{
1127						_data.push({name: el.name, value: el.value});
1128						length += (el.name.length + el.value.length);
1129					}
1130					break;
1131				case 'select-multiple':
1132					for (var j = 0; j < el.options.length; j++)
1133					{
1134						if (el.options[j].selected)
1135						{
1136							_data.push({name : el.name, value : el.options[j].value});
1137							length += (el.name.length + el.options[j].length);
1138						}
1139					}
1140					break;
1141				default:
1142					break;
1143			}
1144		}
1145
1146		i = 0; length = 0;
1147		var current = data, name, rest, pp;
1148
1149		while(i < _data.length)
1150		{
1151			var p = _data[i].name.indexOf('[');
1152			if (p == -1) {
1153				current[_data[i].name] = _data[i].value;
1154				current = data;
1155				i++;
1156			}
1157			else
1158			{
1159				name = _data[i].name.substring(0, p);
1160				rest = _data[i].name.substring(p+1);
1161				pp = rest.indexOf(']');
1162
1163				if(pp == -1)
1164				{
1165					if (!current[name])
1166						current[name] = [];
1167					current = data;
1168					i++;
1169				}
1170				else if(pp == 0)
1171				{
1172					if (!current[name])
1173						current[name] = [];
1174					//No index specified - so take the next integer
1175					current = current[name];
1176					_data[i].name = '' + current.length;
1177				}
1178				else
1179				{
1180					if (!current[name])
1181						current[name] = {};
1182					//Now index name becomes and name and we go deeper into the array
1183					current = current[name];
1184					_data[i].name = rest.substring(0, pp) + rest.substring(pp+1);
1185				}
1186			}
1187		}
1188	}
1189	return {data : data, filesCount : files, roughSize : length};
1190};
1191BX.ajax.submitAjax = function(obForm, config)
1192{
1193	config = (config !== null && typeof config == "object" ? config : {});
1194	config.url = (config["url"] || obForm.getAttribute("action"));
1195
1196	var additionalData = (config["data"] || {});
1197	config.data = BX.ajax.prepareForm(obForm).data;
1198	for (var ii in additionalData)
1199	{
1200		if (additionalData.hasOwnProperty(ii))
1201		{
1202			config.data[ii] = additionalData[ii];
1203		}
1204	}
1205
1206	if (!window["FormData"])
1207	{
1208		BX.ajax(config);
1209	}
1210	else
1211	{
1212		var isFile = function(item)
1213		{
1214			var res = Object.prototype.toString.call(item);
1215			return (res == '[object File]' || res == '[object Blob]');
1216		},
1217		appendToForm = function(fd, key, val)
1218		{
1219			if (!!val && typeof val == "object" && !isFile(val))
1220			{
1221				for (var ii in val)
1222				{
1223					if (val.hasOwnProperty(ii))
1224					{
1225						appendToForm(fd, (key == '' ? ii : key + '[' + ii + ']'), val[ii]);
1226					}
1227				}
1228			}
1229			else
1230				fd.append(key, (!!val ? val : ''));
1231		},
1232		prepareData = function(arData)
1233		{
1234			var data = {};
1235			if (null != arData)
1236			{
1237				if(typeof arData == 'object')
1238				{
1239					for(var i in arData)
1240					{
1241						if (arData.hasOwnProperty(i))
1242						{
1243							var name = BX.util.urlencode(i);
1244							if(typeof arData[i] == 'object' && arData[i]["file"] !== true)
1245								data[name] = prepareData(arData[i]);
1246							else if (arData[i]["file"] === true)
1247								data[name] = arData[i]["value"];
1248							else
1249								data[name] = BX.util.urlencode(arData[i]);
1250						}
1251					}
1252				}
1253				else
1254					data = BX.util.urlencode(arData);
1255			}
1256			return data;
1257		},
1258		fd = new window.FormData();
1259
1260		if (config.method !== 'POST')
1261		{
1262			config.data = BX.ajax.prepareData(config.data);
1263			if (config.data)
1264			{
1265				config.url += (config.url.indexOf('?') !== -1 ? "&" : "?") + config.data;
1266				config.data = '';
1267			}
1268		}
1269		else
1270		{
1271			if (config.preparePost === true)
1272				config.data = prepareData(config.data);
1273			appendToForm(fd, '', config.data);
1274			config.data = fd;
1275		}
1276
1277		config.preparePost = false;
1278		config.start = false;
1279
1280		var xhr = BX.ajax(config);
1281		if (!!config["onprogress"])
1282			xhr.upload.addEventListener(
1283				'progress',
1284				function(e){
1285					var percent = null;
1286					if(e.lengthComputable && (e.total || e["totalSize"])) {
1287						percent = e.loaded * 100 / (e.total || e["totalSize"]);
1288					}
1289					config["onprogress"](e, percent);
1290				}
1291			);
1292		xhr.send(fd);
1293	}
1294};
1295
1296BX.ajax.UpdatePageData = function (arData)
1297{
1298	if (arData.TITLE)
1299		BX.ajax.UpdatePageTitle(arData.TITLE);
1300	if (arData.WINDOW_TITLE || arData.TITLE)
1301		BX.ajax.UpdateWindowTitle(arData.WINDOW_TITLE || arData.TITLE);
1302	if (arData.NAV_CHAIN)
1303		BX.ajax.UpdatePageNavChain(arData.NAV_CHAIN);
1304	if (arData.CSS && arData.CSS.length > 0)
1305		BX.loadCSS(arData.CSS);
1306	if (arData.SCRIPTS && arData.SCRIPTS.length > 0)
1307	{
1308		var f = function(result,config,cb){
1309
1310			if(!!config && BX.type.isArray(config.scripts))
1311			{
1312				for(var i=0,l=arData.SCRIPTS.length;i<l;i++)
1313				{
1314					config.scripts.push({isInternal:false,JS:arData.SCRIPTS[i]});
1315				}
1316			}
1317			else
1318			{
1319				BX.loadScript(arData.SCRIPTS,cb);
1320			}
1321
1322			BX.removeCustomEvent('onAjaxSuccess',f);
1323		};
1324		BX.addCustomEvent('onAjaxSuccess',f);
1325	}
1326	else
1327	{
1328		var f1 = function(result,config,cb){
1329			if(BX.type.isFunction(cb))
1330			{
1331				cb();
1332			}
1333			BX.removeCustomEvent('onAjaxSuccess',f1);
1334		};
1335		BX.addCustomEvent('onAjaxSuccess', f1);
1336	}
1337};
1338
1339BX.ajax.UpdatePageTitle = function(title)
1340{
1341	var obTitle = BX('pagetitle');
1342	if (obTitle)
1343	{
1344		obTitle.removeChild(obTitle.firstChild);
1345		if (!obTitle.firstChild)
1346			obTitle.appendChild(document.createTextNode(title));
1347		else
1348			obTitle.insertBefore(document.createTextNode(title), obTitle.firstChild);
1349	}
1350};
1351
1352BX.ajax.UpdateWindowTitle = function(title)
1353{
1354	document.title = title;
1355};
1356
1357BX.ajax.UpdatePageNavChain = function(nav_chain)
1358{
1359	var obNavChain = BX('navigation');
1360	if (obNavChain)
1361	{
1362		obNavChain.innerHTML = nav_chain;
1363	}
1364};
1365
1366/* user options handling */
1367BX.userOptions = {
1368	options: null,
1369	bSend: false,
1370	delay: 5000,
1371	path: '/bitrix/admin/user_options.php?'
1372};
1373
1374BX.userOptions.setAjaxPath = function(url)
1375{
1376	BX.userOptions.path = url.indexOf('?') == -1? url+'?': url+'&';
1377}
1378BX.userOptions.save = function(sCategory, sName, sValName, sVal, bCommon)
1379{
1380	if (null == BX.userOptions.options)
1381		BX.userOptions.options = {};
1382
1383	bCommon = !!bCommon;
1384	BX.userOptions.options[sCategory+'.'+sName+'.'+sValName] = [sCategory, sName, sValName, sVal, bCommon];
1385
1386	var sParam = BX.userOptions.__get();
1387	if (sParam != '')
1388		document.cookie = BX.message('COOKIE_PREFIX')+"_LAST_SETTINGS=" + encodeURIComponent(sParam) + "&sessid="+BX.bitrix_sessid()+"; expires=Thu, 31 Dec 2020 23:59:59 GMT; path=/;";
1389
1390	if(!BX.userOptions.bSend)
1391	{
1392		BX.userOptions.bSend = true;
1393		setTimeout(function(){BX.userOptions.send(null)}, BX.userOptions.delay);
1394	}
1395};
1396
1397BX.userOptions.send = function(callback)
1398{
1399	var sParam = BX.userOptions.__get();
1400	BX.userOptions.options = null;
1401	BX.userOptions.bSend = false;
1402
1403	if (sParam != '')
1404	{
1405		document.cookie = BX.message('COOKIE_PREFIX') + "_LAST_SETTINGS=; path=/;";
1406		BX.ajax({
1407			'method': 'GET',
1408			'dataType': 'html',
1409			'processData': false,
1410			'cache': false,
1411			'url': BX.userOptions.path+sParam+'&sessid='+BX.bitrix_sessid(),
1412			'onsuccess': callback
1413		});
1414	}
1415};
1416
1417BX.userOptions.del = function(sCategory, sName, bCommon, callback)
1418{
1419	BX.ajax.get(BX.userOptions.path+'action=delete&c='+sCategory+'&n='+sName+(bCommon == true? '&common=Y':'')+'&sessid='+BX.bitrix_sessid(), callback);
1420};
1421
1422BX.userOptions.__get = function()
1423{
1424	if (!BX.userOptions.options) return '';
1425
1426	var sParam = '', n = -1, prevParam = '', aOpt, i;
1427
1428	for (i in BX.userOptions.options)
1429	{
1430		if(BX.userOptions.options.hasOwnProperty(i))
1431		{
1432			aOpt = BX.userOptions.options[i];
1433
1434			if (prevParam != aOpt[0]+'.'+aOpt[1])
1435			{
1436				n++;
1437				sParam += '&p['+n+'][c]='+BX.util.urlencode(aOpt[0]);
1438				sParam += '&p['+n+'][n]='+BX.util.urlencode(aOpt[1]);
1439				if (aOpt[4] == true)
1440					sParam += '&p['+n+'][d]=Y';
1441				prevParam = aOpt[0]+'.'+aOpt[1];
1442			}
1443
1444			var valueName = aOpt[2];
1445			var value = aOpt[3];
1446
1447			if (valueName === null)
1448			{
1449				sParam += '&p['+n+'][v]='+BX.util.urlencode(value);
1450			}
1451			else
1452			{
1453				sParam += '&p['+n+'][v]['+BX.util.urlencode(valueName)+']='+BX.util.urlencode(value);
1454			}
1455		}
1456	}
1457
1458	return sParam.substr(1);
1459};
1460
1461BX.ajax.history = {
1462	expected_hash: '',
1463
1464	obParams: null,
1465
1466	obFrame: null,
1467	obImage: null,
1468
1469	obTimer: null,
1470
1471	bInited: false,
1472	bHashCollision: false,
1473	bPushState: !!(history.pushState && BX.type.isFunction(history.pushState)),
1474
1475	startState: null,
1476
1477	init: function(obParams)
1478	{
1479		if (BX.ajax.history.bInited)
1480			return;
1481
1482		this.obParams = obParams;
1483		var obCurrentState = this.obParams.getState();
1484
1485		if (BX.ajax.history.bPushState)
1486		{
1487			BX.ajax.history.expected_hash = window.location.pathname;
1488			if (window.location.search)
1489				BX.ajax.history.expected_hash += window.location.search;
1490
1491			BX.ajax.history.put(obCurrentState, BX.ajax.history.expected_hash, '', true);
1492			// due to some strange thing, chrome calls popstate event on page start. so we should delay it
1493			setTimeout(function(){BX.bind(window, 'popstate', BX.ajax.history.__hashListener);}, 500);
1494		}
1495		else
1496		{
1497			BX.ajax.history.expected_hash = window.location.hash;
1498
1499			if (!BX.ajax.history.expected_hash || BX.ajax.history.expected_hash == '#')
1500				BX.ajax.history.expected_hash = '__bx_no_hash__';
1501
1502			jsAjaxHistoryContainer.put(BX.ajax.history.expected_hash, obCurrentState);
1503			BX.ajax.history.obTimer = setTimeout(BX.ajax.history.__hashListener, 500);
1504
1505			if (BX.browser.IsIE())
1506			{
1507				BX.ajax.history.obFrame = document.createElement('IFRAME');
1508				BX.hide_object(BX.ajax.history.obFrame);
1509
1510				document.body.appendChild(BX.ajax.history.obFrame);
1511
1512				BX.ajax.history.obFrame.contentWindow.document.open();
1513				BX.ajax.history.obFrame.contentWindow.document.write(BX.ajax.history.expected_hash);
1514				BX.ajax.history.obFrame.contentWindow.document.close();
1515			}
1516			else if (BX.browser.IsOpera())
1517			{
1518				BX.ajax.history.obImage = document.createElement('IMG');
1519				BX.hide_object(BX.ajax.history.obImage);
1520
1521				document.body.appendChild(BX.ajax.history.obImage);
1522
1523				BX.ajax.history.obImage.setAttribute('src', 'javascript:location.href = \'javascript:BX.ajax.history.__hashListener();\';');
1524			}
1525		}
1526
1527		BX.ajax.history.bInited = true;
1528	},
1529
1530	__hashListener: function(e)
1531	{
1532		e = e || window.event || {state:false};
1533
1534		if (BX.ajax.history.bPushState)
1535		{
1536			BX.ajax.history.obParams.setState(e.state||BX.ajax.history.startState);
1537		}
1538		else
1539		{
1540			if (BX.ajax.history.obTimer)
1541			{
1542				window.clearTimeout(BX.ajax.history.obTimer);
1543				BX.ajax.history.obTimer = null;
1544			}
1545
1546			var current_hash;
1547			if (null != BX.ajax.history.obFrame)
1548				current_hash = BX.ajax.history.obFrame.contentWindow.document.body.innerText;
1549			else
1550				current_hash = window.location.hash;
1551
1552			if (!current_hash || current_hash == '#')
1553				current_hash = '__bx_no_hash__';
1554
1555			if (current_hash.indexOf('#') == 0)
1556				current_hash = current_hash.substring(1);
1557
1558			if (current_hash != BX.ajax.history.expected_hash)
1559			{
1560				var state = jsAjaxHistoryContainer.get(current_hash);
1561				if (state)
1562				{
1563					BX.ajax.history.obParams.setState(state);
1564
1565					BX.ajax.history.expected_hash = current_hash;
1566					if (null != BX.ajax.history.obFrame)
1567					{
1568						var __hash = current_hash == '__bx_no_hash__' ? '' : current_hash;
1569						if (window.location.hash != __hash && window.location.hash != '#' + __hash)
1570							window.location.hash = __hash;
1571					}
1572				}
1573			}
1574
1575			BX.ajax.history.obTimer = setTimeout(BX.ajax.history.__hashListener, 500);
1576		}
1577	},
1578
1579	put: function(state, new_hash, new_hash1, bStartState)
1580	{
1581		if (this.bPushState)
1582		{
1583			if(!bStartState)
1584			{
1585				history.pushState(state, '', new_hash);
1586			}
1587			else
1588			{
1589				BX.ajax.history.startState = state;
1590			}
1591		}
1592		else
1593		{
1594			if (typeof new_hash1 != 'undefined')
1595				new_hash = new_hash1;
1596			else
1597				new_hash = 'view' + new_hash;
1598
1599			jsAjaxHistoryContainer.put(new_hash, state);
1600			BX.ajax.history.expected_hash = new_hash;
1601
1602			window.location.hash = BX.util.urlencode(new_hash);
1603
1604			if (null != BX.ajax.history.obFrame)
1605			{
1606				BX.ajax.history.obFrame.contentWindow.document.open();
1607				BX.ajax.history.obFrame.contentWindow.document.write(new_hash);
1608				BX.ajax.history.obFrame.contentWindow.document.close();
1609			}
1610		}
1611	},
1612
1613	checkRedirectStart: function(param_name, param_value)
1614	{
1615		var current_hash = window.location.hash;
1616		if (current_hash.substring(0, 1) == '#') current_hash = current_hash.substring(1);
1617
1618		var test = current_hash.substring(0, 5);
1619		if (test == 'view/' || test == 'view%')
1620		{
1621			BX.ajax.history.bHashCollision = true;
1622			document.write('<' + 'div id="__ajax_hash_collision_' + param_value + '" style="display: none;">');
1623		}
1624	},
1625
1626	checkRedirectFinish: function(param_name, param_value)
1627	{
1628		document.write('</div>');
1629
1630		var current_hash = window.location.hash;
1631		if (current_hash.substring(0, 1) == '#') current_hash = current_hash.substring(1);
1632
1633		BX.ready(function ()
1634		{
1635			var test = current_hash.substring(0, 5);
1636			if (test == 'view/' || test == 'view%')
1637			{
1638				var obColNode = BX('__ajax_hash_collision_' + param_value);
1639				var obNode = obColNode.firstChild;
1640				BX.cleanNode(obNode);
1641				obColNode.style.display = 'block';
1642
1643				// IE, Opera and Chrome automatically modifies hash with urlencode, but FF doesn't ;-(
1644				if (test != 'view%')
1645					current_hash = BX.util.urlencode(current_hash);
1646
1647				current_hash += (current_hash.indexOf('%3F') == -1 ? '%3F' : '%26') + param_name + '=' + param_value;
1648
1649				var url = '/bitrix/tools/ajax_redirector.php?hash=' + current_hash;
1650
1651				BX.ajax.insertToNode(url, obNode);
1652			}
1653		});
1654	}
1655};
1656
1657BX.ajax.component = function(node)
1658{
1659	this.node = node;
1660};
1661
1662BX.ajax.component.prototype.getState = function()
1663{
1664	var state = {
1665		'node': this.node,
1666		'title': window.document.title,
1667		'data': BX(this.node).innerHTML
1668	};
1669
1670	var obNavChain = BX('navigation');
1671	if (null != obNavChain)
1672		state.nav_chain = obNavChain.innerHTML;
1673
1674	BX.onCustomEvent(BX(state.node), "onComponentAjaxHistoryGetState", [state]);
1675
1676	return state;
1677};
1678
1679BX.ajax.component.prototype.setState = function(state)
1680{
1681	BX(state.node).innerHTML = state.data;
1682	BX.ajax.UpdatePageTitle(state.title);
1683
1684	if (state.nav_chain)
1685	{
1686		BX.ajax.UpdatePageNavChain(state.nav_chain);
1687	}
1688
1689	BX.onCustomEvent(BX(state.node), "onComponentAjaxHistorySetState", [state]);
1690};
1691
1692var jsAjaxHistoryContainer = {
1693	arHistory: {},
1694
1695	put: function(hash, state)
1696	{
1697		this.arHistory[hash] = state;
1698	},
1699
1700	get: function(hash)
1701	{
1702		return this.arHistory[hash];
1703	}
1704};
1705
1706
1707BX.ajax.FormData = function()
1708{
1709	this.elements = [];
1710	this.files = [];
1711	this.features = {};
1712	this.isSupported();
1713	this.log('BX FormData init');
1714};
1715
1716BX.ajax.FormData.isSupported = function()
1717{
1718	var f = new BX.ajax.FormData();
1719	var result = f.features.supported;
1720	f = null;
1721	return result;
1722};
1723
1724BX.ajax.FormData.prototype.log = function(o)
1725{
1726	if (false) {
1727		try {
1728			if (BX.browser.IsIE()) o = JSON.stringify(o);
1729			console.log(o);
1730		} catch(e) {}
1731	}
1732};
1733
1734BX.ajax.FormData.prototype.isSupported = function()
1735{
1736	var f = {};
1737	f.fileReader = (window.FileReader && window.FileReader.prototype.readAsBinaryString);
1738	f.readFormData = f.sendFormData = !!(window.FormData);
1739	f.supported = !!(f.readFormData && f.sendFormData);
1740	this.features = f;
1741	this.log('features:');
1742	this.log(f);
1743
1744	return f.supported;
1745};
1746
1747BX.ajax.FormData.prototype.append = function(name, value)
1748{
1749	if (typeof(value) === 'object') { // seems to be files element
1750		this.files.push({'name': name, 'value':value});
1751	} else {
1752		this.elements.push({'name': name, 'value':value});
1753	}
1754};
1755
1756BX.ajax.FormData.prototype.send = function(url, callbackOk, callbackProgress, callbackError)
1757{
1758	this.log('FD send');
1759	this.xhr = BX.ajax({
1760			'method': 'POST',
1761			'dataType': 'html',
1762			'url': url,
1763			'onsuccess': callbackOk,
1764			'onfailure': callbackError,
1765			'start': false,
1766			'preparePost':false
1767		});
1768
1769	if (callbackProgress)
1770	{
1771		this.xhr.upload.addEventListener(
1772			'progress',
1773			function(e) {
1774				if (e.lengthComputable)
1775					callbackProgress(e.loaded / (e.total || e.totalSize));
1776			},
1777			false
1778		);
1779	}
1780
1781	if (this.features.readFormData && this.features.sendFormData)
1782	{
1783		var fd = new FormData();
1784		this.log('use browser formdata');
1785		for (var i in this.elements)
1786		{
1787			if(this.elements.hasOwnProperty(i))
1788				fd.append(this.elements[i].name,this.elements[i].value);
1789		}
1790		for (i in this.files)
1791		{
1792			if(this.files.hasOwnProperty(i))
1793				fd.append(this.files[i].name, this.files[i].value);
1794		}
1795		this.xhr.send(fd);
1796	}
1797
1798	return this.xhr;
1799};
1800
1801BX.addCustomEvent('onAjaxFailure', BX.debug);
1802})(window);
1803

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.