PageSourceSearch

https://levitacia.co/bitrix/cache/js/s1/levitacia/kernel_main/kernel_main_v1.js?1756734951302069

js levitacia.co collected 2026-10-08 19:04:08 UTC 302,069 bytes, 12,144 lines download raw bytes

1; /* /bitrix/js/main/core/core_timer.js?16741571766316*/
2; /* /bitrix/js/main/core/core_webrtc.js?167415717624229*/
3; /* /bitrix/js/main/dd.js?167415717914809*/
4; /* /bitrix/js/main/core/core_uf.js?167415717618700*/
5; /* /bitrix/js/main/core/core_dd.js?16741571763613*/
6; /* /bitrix/js/main/core/core_tooltip.js?167415717615458*/
7; /* /bitrix/js/main/pageobject/pageobject.js?1674157176864*/
8; /* /bitrix/js/main/core/core_window.js?167415717698371*/
9; /* /bitrix/js/main/utils.js?167415717929279*/
10; /* /bitrix/js/main/date/main.date.js?167415717634530*/
11; /* /bitrix/js/main/core/core_date.js?167415717636080*/
12; /* /bitrix/js/main/core/core_fx.js?167415717616888*/
13
14; /* Start:"a:4:{s:4:"full";s:47:"/bitrix/js/main/core/core_fx.js?167415717616888";s:6:"source";s:31:"/bitrix/js/main/core/core_fx.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
15;(function(window){
16
17var defaultOptions = {
18	time: 1.0,
19	step: 0.05,
20	type: 'linear',
21
22	allowFloat: false
23}
24
25/*
26options: {
27	start: start value or {param: value, param: value}
28	finish: finish value or {param: value, param: value}
29	time: time to transform in seconds
30	type: linear|accelerated|decelerated|custom func name
31	callback,
32	callback_start,
33	callback_complete,
34
35	step: time between steps in seconds
36	allowFloat: false|true
37}
38*/
39BX.fx = function(options)
40{
41	this.options = options;
42
43	if (null != this.options.time)
44		this.options.originalTime = this.options.time;
45	if (null != this.options.step)
46		this.options.originalStep = this.options.step;
47
48	if (!this.__checkOptions())
49		return false;
50
51	this.__go = BX.delegate(this.go, this);
52
53	this.PARAMS = {};
54}
55
56BX.fx.prototype.__checkOptions = function()
57{
58	if (typeof this.options.start != typeof this.options.finish)
59		return false;
60
61	if (null == this.options.time) this.options.time = defaultOptions.time;
62	if (null == this.options.step) this.options.step = defaultOptions.step;
63	if (null == this.options.type) this.options.type = defaultOptions.type;
64	if (null == this.options.allowFloat) this.options.allowFloat = defaultOptions.allowFloat;
65
66	this.options.time *= 1000;
67	this.options.step *= 1000;
68
69	if (typeof this.options.start != 'object')
70	{
71		this.options.start = {_param: this.options.start};
72		this.options.finish = {_param: this.options.finish};
73	}
74
75	var i;
76	for (i in this.options.start)
77	{
78		if (null == this.options.finish[i])
79		{
80			this.options.start[i] = null;
81			delete this.options.start[i];
82		}
83	}
84
85	if (!BX.type.isFunction(this.options.type))
86	{
87		if (BX.type.isFunction(window[this.options.type]))
88			this.options.type = window[this.options.type];
89		else if (BX.type.isFunction(BX.fx.RULES[this.options.type]))
90			this.options.type = BX.fx.RULES[this.options.type];
91		else
92			this.options.type = BX.fx.RULES[defaultOptions.type];
93	}
94
95	return true;
96}
97
98BX.fx.prototype.go = function()
99{
100	var timeCurrent = new Date().valueOf();
101	if (timeCurrent < this.PARAMS.timeFinish)
102	{
103		for (var i in this.PARAMS.current)
104		{
105			this.PARAMS.current[i][0] = this.options.type.apply(this, [{
106				start_value: this.PARAMS.start[i][0],
107				finish_value: this.PARAMS.finish[i][0],
108				current_value: this.PARAMS.current[i][0],
109				current_time: timeCurrent - this.PARAMS.timeStart,
110				total_time: this.options.time
111			}]);
112		}
113
114		this._callback(this.options.callback);
115
116		if (!this.paused)
117			this.PARAMS.timer = setTimeout(this.__go, this.options.step);
118	}
119	else
120	{
121		this.stop();
122	}
123}
124
125BX.fx.prototype._callback = function(cb)
126{
127	var tmp = {};
128
129	cb = cb || this.options.callback;
130
131	for (var i in this.PARAMS.current)
132	{
133		tmp[i] = (this.options.allowFloat ? this.PARAMS.current[i][0] : Math.round(this.PARAMS.current[i][0])) + this.PARAMS.current[i][1];
134	}
135
136	return cb.apply(this, [null != tmp['_param'] ? tmp._param : tmp]);
137}
138
139BX.fx.prototype.start = function()
140{
141	var i,value, unit;
142
143	this.PARAMS.start = {};
144	this.PARAMS.current = {};
145	this.PARAMS.finish = {};
146
147	for (i in this.options.start)
148	{
149		value = +this.options.start[i];
150		unit = (this.options.start[i]+'').substring((value+'').length);
151		this.PARAMS.start[i] = [value, unit];
152		this.PARAMS.current[i] = [value, unit];
153		this.PARAMS.finish[i] = [+this.options.finish[i], unit];
154	}
155
156	this._callback(this.options.callback_start);
157	this._callback(this.options.callback);
158
159	this.PARAMS.timeStart = new Date().valueOf();
160	this.PARAMS.timeFinish = this.PARAMS.timeStart + this.options.time;
161	this.PARAMS.timer = setTimeout(BX.delegate(this.go, this), this.options.step);
162
163	return this;
164}
165
166BX.fx.prototype.pause = function()
167{
168	if (this.paused)
169	{
170		this.PARAMS.timer = setTimeout(this.__go, this.options.step);
171		this.paused = false;
172	}
173	else
174	{
175		clearTimeout(this.PARAMS.timer);
176		this.paused = true;
177	}
178}
179
180BX.fx.prototype.stop = function(silent)
181{
182	silent = !!silent;
183	if (this.PARAMS.timer)
184		clearTimeout(this.PARAMS.timer);
185
186	if (null != this.options.originalTime)
187		this.options.time = this.options.originalTime;
188	if (null != this.options.originalStep)
189		this.options.step = this.options.originalStep;
190
191	this.PARAMS.current = this.PARAMS.finish;
192	if (!silent) {
193		this._callback(this.options.callback);
194		this._callback(this.options.callback_complete);
195	}
196}
197
198/*
199type rules of animation
200 - linear - simple linear animation
201 - accelerated
202 - decelerated
203*/
204
205/*
206	params: {
207		start_value, finish_value, current_time, total_time
208	}
209*/
210BX.fx.RULES =
211{
212	linear: function(params)
213	{
214		return params.start_value + (params.current_time/params.total_time) * (params.finish_value - params.start_value);
215	},
216
217	decelerated: function(params)
218	{
219		return params.start_value + Math.sqrt(params.current_time/params.total_time) * (params.finish_value - params.start_value);
220	},
221
222	accelerated: function(params)
223	{
224		var q = params.current_time/params.total_time;
225		return params.start_value + q * q * (params.finish_value - params.start_value);
226	}
227}
228
229/****************** effects realizaion ************************/
230
231/*
232	type = 'fade' || 'scroll' || 'scale' || 'fold'
233*/
234
235BX.fx.hide = function(el, type, opts)
236{
237	el = BX(el);
238
239	if (typeof type == 'object' && null == opts)
240	{
241		opts = type;
242		type = opts.type
243	}
244
245	if (!opts) opts = {};
246
247	if (!BX.type.isNotEmptyString(type))
248	{
249		el.style.display = 'none';
250		return;
251	}
252
253	var fxOptions = BX.fx.EFFECTS[type](el, opts, 0);
254	fxOptions.callback_complete = function () {
255		if (opts.hide !== false)
256			el.style.display = 'none';
257
258		if (opts.callback_complete)
259			opts.callback_complete.apply(this, arguments);
260	}
261
262	return (new BX.fx(fxOptions)).start();
263}
264
265BX.fx.show = function(el, type, opts)
266{
267	el = BX(el);
268
269	if (typeof type == 'object' && null == opts)
270	{
271		opts = type;
272		type = opts.type
273	}
274
275	if (!opts) opts = {};
276
277	if (!BX.type.isNotEmptyString(type))
278	{
279		el.style.display = 'block';
280		return;
281	}
282
283	var fxOptions = BX.fx.EFFECTS[type](el, opts, 1);
284
285	fxOptions.callback_complete = function () {
286		if (opts.show !== false)
287			el.style.display = 'block';
288
289		if (opts.callback_complete)
290			opts.callback_complete.apply(this, arguments);
291	}
292
293	return (new BX.fx(fxOptions)).start();
294}
295
296BX.fx.EFFECTS = {
297	scroll: function(el, opts, action)
298	{
299		if (!opts.direction) opts.direction = 'vertical';
300
301		var param = opts.direction == 'horizontal' ? 'width' : 'height';
302
303		var val = parseInt(BX.style(el, param));
304		if (isNaN(val))
305		{
306			val = BX.pos(el)[param];
307		}
308
309		if (action == 0)
310			var start = val, finish = opts.min_height ? parseInt(opts.min_height) : 0;
311		else
312			var finish = val, start = opts.min_height ? parseInt(opts.min_height) : 0;
313
314		return {
315			'start': start,
316			'finish': finish,
317			'time': opts.time || defaultOptions.time,
318			'type': 'linear',
319			callback_start: function () {
320				if (BX.style(el, 'position') == 'static')
321					el.style.position = 'relative';
322
323				el.style.overflow = 'hidden';
324				el.style[param] = start + 'px';
325				el.style.display = 'block';
326			},
327			callback: function (val) {el.style[param] = val + 'px';}
328		}
329	},
330
331	fade: function(el, opts, action)
332	{
333		var fadeOpts = {
334			'time': opts.time || defaultOptions.time,
335			'type': action == 0 ? 'decelerated' : 'linear',
336			'start': action == 0 ? 1 : 0,
337			'finish': action == 0 ? 0 : 1,
338			'allowFloat': true
339		};
340
341		if (BX.browser.IsIE() && !BX.browser.IsIE9())
342		{
343			fadeOpts.start *= 100; fadeOpts.finish *= 100; fadeOpts.allowFloat = false;
344
345			fadeOpts.callback_start = function() {
346				el.style.display = 'block';
347				el.style.filter += "progid:DXImageTransform.Microsoft.Alpha(opacity=" + fadeOpts.start + ")";
348			};
349
350			fadeOpts.callback = function (val) {
351				(el.filters['DXImageTransform.Microsoft.alpha']||el.filters.alpha).opacity = val;
352			}
353		}
354		else
355		{
356			fadeOpts.callback_start = function () {
357				el.style.display = 'block';
358			}
359
360			fadeOpts.callback = function (val) {
361				el.style.opacity = el.style.KhtmlOpacity = el.style.MozOpacity = val;
362			};
363		}
364
365		return fadeOpts;
366	},
367
368	fold: function (el, opts, action) // 'fold' is a combination of two consequential 'scroll' hidings.
369	{
370		if (action != 0) return;
371
372		var pos = BX.pos(el);
373		var coef = pos.height / (pos.width + pos.height);
374		var old_opts = {time: opts.time || defaultOptions.time, callback_complete: opts.callback_complete, hide: opts.hide};
375
376		opts.type = 'scroll';
377		opts.direction = 'vertical';
378		opts.min_height = opts.min_height || 10;
379		opts.hide = false;
380		opts.time = coef * old_opts.time;
381		opts.callback_complete = function()
382		{
383			el.style.whiteSpace = 'nowrap';
384
385			opts.direction = 'horizontal';
386			opts.min_height = null;
387
388			opts.time = old_opts.time - opts.time;
389			opts.hide = old_opts.hide;
390			opts.callback_complete = old_opts.callback_complete;
391
392			BX.fx.hide(el, opts);
393		}
394
395		return BX.fx.EFFECTS.scroll(el, opts, action);
396	},
397
398	scale: function (el, opts, action)
399	{
400		var val = {width: parseInt(BX.style(el, 'width')), height: parseInt(BX.style(el, 'height'))};
401		if (isNaN(val.width) || isNaN(val.height))
402		{
403			var pos = BX.pos(el)
404			val = {width: pos.width, height: pos.height};
405		}
406
407		if (action == 0)
408			var start = val, finish = {width: 0, height: 0};
409		else
410			var finish = val, start = {width: 0, height: 0};
411
412		return {
413			'start': start,
414			'finish': finish,
415			'time': opts.time || defaultOptions.time,
416			'type': 'linear',
417			callback_start: function () {
418				el.style.position = 'relative';
419				el.style.overflow = 'hidden';
420				el.style.display = 'block';
421				el.style.height = start.height + 'px';
422				el.style.width = start.width + 'px';
423			},
424			callback: function (val) {
425				el.style.height = val.height + 'px';
426				el.style.width = val.width + 'px';
427			}
428		}
429	}
430}
431
432// Color animation
433//
434// Set animation rule
435// BX.fx.colorAnimate.addRule('animationRule1',"#FFF","#faeeb4", "background-color", 100, 1, true);
436// BX.fx.colorAnimate.addRule('animationRule2',"#fc8282","#ff0000", "color", 100, 1, true);
437// Params: 1 - animation name, 2 - start color, 3 - end color, 4 - count step, 5 - delay each step, 6 - return color on end animation
438//
439// Animate color for element
440// BX.fx.colorAnimate(BX('element'), 'animationRule1,animationRule2');
441
442var defaultOptionsColorAnimation = {
443	arStack: {},
444	arRules: {},
445	globalAnimationId: 0
446}
447
448BX.fx.colorAnimate = function(element, rule, back)
449{
450	if (element == null)
451		return;
452
453	animationId = element.getAttribute('data-animation-id');
454	if (animationId == null)
455	{
456		animationId = defaultOptionsColorAnimation.globalAnimationId;
457		element.setAttribute('data-animation-id', defaultOptionsColorAnimation.globalAnimationId++);
458	}
459	var aRuleList = rule.split(/\s*,\s*/);
460
461	for (var j	= 0; j < aRuleList.length; j++)
462	{
463		rule = aRuleList[j];
464
465		if (!defaultOptionsColorAnimation.arRules[rule]) continue;
466
467		var i=0;
468
469		if (!defaultOptionsColorAnimation.arStack[animationId])
470		{
471			defaultOptionsColorAnimation.arStack[animationId] = {};
472		}
473		else if (defaultOptionsColorAnimation.arStack[animationId][rule])
474		{
475			i = defaultOptionsColorAnimation.arStack[animationId][rule].i;
476			clearInterval(defaultOptionsColorAnimation.arStack[animationId][rule].tId);
477		}
478
479		if ((i==0 && back) || (i==defaultOptionsColorAnimation.arRules[rule][3] && !back)) continue;
480
481		defaultOptionsColorAnimation.arStack[animationId][rule] = {'i':i, 'element': element, 'tId':setInterval('BX.fx.colorAnimate.run("'+animationId+'","'+rule+'")', defaultOptionsColorAnimation.arRules[rule][4]),'back':Boolean(back)};
482	}
483}
484
485BX.fx.colorAnimate.addRule = function (rule, startColor, finishColor, cssProp, step, delay, back)
486{
487	defaultOptionsColorAnimation.arRules[rule] = [
488		BX.util.hex2rgb(startColor),
489		BX.util.hex2rgb(finishColor),
490		cssProp.replace(/\-(.)/g,function(){return arguments[1].toUpperCase();}),
491		step,
492		delay || 1,
493		back || false
494	];
495};
496
497BX.fx.colorAnimate.run = function(animationId, rule)
498{
499	element = defaultOptionsColorAnimation.arStack[animationId][rule].element;
500
501    defaultOptionsColorAnimation.arStack[animationId][rule].i += defaultOptionsColorAnimation.arStack[animationId][rule].back?-1:1;
502 	var finishPercent = defaultOptionsColorAnimation.arStack[animationId][rule].i/defaultOptionsColorAnimation.arRules[rule][3];
503	var startPercent = 1 - finishPercent;
504
505	var aRGBStart = defaultOptionsColorAnimation.arRules[rule][0];
506	var aRGBFinish = defaultOptionsColorAnimation.arRules[rule][1];
507
508	element.style[defaultOptionsColorAnimation.arRules[rule][2]] = 'rgb('+
509	Math.floor( aRGBStart['r'] * startPercent + aRGBFinish['r'] * finishPercent ) + ','+
510	Math.floor( aRGBStart['g'] * startPercent + aRGBFinish['g'] * finishPercent ) + ','+
511	Math.floor( aRGBStart['b'] * startPercent + aRGBFinish['b'] * finishPercent ) +')';
512
513	if ( defaultOptionsColorAnimation.arStack[animationId][rule].i == defaultOptionsColorAnimation.arRules[rule][3] || defaultOptionsColorAnimation.arStack[animationId][rule].i ==0)
514	{
515		clearInterval(defaultOptionsColorAnimation.arStack[animationId][rule].tId);
516		if (defaultOptionsColorAnimation.arRules[rule][5])
517			BX.fx.colorAnimate(defaultOptionsColorAnimation.arStack[animationId][rule].element, rule, true);
518	}
519}
520
521
522/*
523options = {
524	delay: 100,
525	duration : 3000,
526	start : { scroll : document.body.scrollTop, left : 0, opacity :  100 },
527	finish : { scroll : document.body.scrollHeight, left : 500, opacity : 10 },
528	transition : BitrixAnimation.makeEaseOut(BitrixAnimation.transitions.quart),
529
530	step : function(state)
531	{
532		document.body.scrollTop = state.scroll;
533		button.style.left =  state.left + "px";
534		button.style.opacity =  state.opacity / 100;
535	},
536	complete : function()
537	{
538		button.style.background = "green";
539	}
540}
541
542options =
543{
544	delay : 20,
545	duration : 4000,
546	transition : BXAnimation.makeEaseOut(BXAnimation.transitions.quart),
547	progress : function(progress)
548	{
549		document.body.scrollTop = Math.round(topMax * progress);
550		button.style.left =  Math.round(leftMax * progress) + "px";
551		button.style.opacity =  (100 + Math.round((opacityMin - 100) * progress)) / 100;
552
553	},
554	complete : function()
555	{
556		button.style.background = "green";
557	}
558}
559*/
560
561BX.easing = function(options)
562{
563	this.options = options;
564	this.timer = null;
565};
566
567BX.easing.prototype.animate = function()
568{
569	if (!this.options || !this.options.start || !this.options.finish ||
570		typeof(this.options.start) != "object" || typeof(this.options.finish) != "object"
571		)
572		return null;
573
574	for (var propName in this.options.start)
575	{
576		if (typeof(this.options.finish[propName]) == "undefined")
577		{
578			delete this.options.start[propName];
579		}
580	}
581
582	this.options.progress = function(progress) {
583		var state = {};
584		for (var propName in this.start)
585			state[propName] = Math.round(this.start[propName] + (this.finish[propName] - this.start[propName]) * progress);
586
587		if (this.step)
588		{
589			this.step(state);
590		}
591	};
592
593	this.animateProgress();
594};
595
596BX.easing.prototype.stop = function(completed)
597{
598	if (this.timer)
599	{
600		cancelAnimationFrame(this.timer);
601		this.timer = null;
602		if (completed)
603		{
604			this.options.complete && this.options.complete();
605		}
606	}
607};
608
609BX.easing.prototype.animateProgress = function()
610{
611	if (!window.requestAnimationFrame)
612	{
613		//For old browsers we skip animation
614		this.options.progress(1);
615		this.options.complete && this.options.complete();
616		return;
617	}
618
619	var start = null;
620	var delta = this.options.transition || BX.easing.transitions.linear;
621	var duration = this.options.duration || 1000;
622	var animation = BX.proxy(function(time) {
623
624		if (start === null)
625		{
626			start = time;
627		}
628
629		var progress = (time - start) / duration;
630		if (progress > 1)
631		{
632			progress = 1;
633		}
634
635		this.options.progress(delta(progress));
636
637		if (progress == 1)
638		{
639			this.stop(true);
640		}
641		else
642		{
643			this.timer = requestAnimationFrame(animation);
644		}
645
646	}, this);
647
648	this.timer = requestAnimationFrame(animation);
649};
650
651BX.easing.makeEaseInOut = function(delta)
652{
653	return function(progress) {
654		if (progress < 0.5)
655			return delta( 2 * progress ) / 2;
656		else
657			return (2 - delta( 2 * (1-progress) ) ) / 2;
658	}
659};
660
661BX.easing.makeEaseOut = function(delta)
662{
663	return function(progress) {
664		return 1 - delta(1 - progress);
665	};
666};
667
668BX.easing.transitions = {
669
670	linear : function(progress)
671	{
672		return progress;
673	},
674
675	quad : function(progress)
676	{
677		return Math.pow(progress, 2);
678	},
679
680	cubic : function(progress) {
681		return Math.pow(progress, 3);
682	},
683
684	quart : function(progress)
685	{
686		return Math.pow(progress, 4);
687	},
688
689	quint : function(progress)
690	{
691		return Math.pow(progress, 5);
692	},
693
694	circ : function(progress)
695	{
696		return 1 - Math.sin(Math.acos(progress));
697	},
698
699	back : function(progress)
700	{
701		return Math.pow(progress, 2) * ((1.5 + 1) * progress - 1.5);
702	},
703
704	elastic: function(progress)
705	{
706		return Math.pow(2, 10 * (progress-1)) * Math.cos(20 * Math.PI * 1.5/3 * progress);
707	},
708
709	bounce : function(progress)
710	{
711		for(var a = 0, b = 1; 1; a += b, b /= 2) {
712			if (progress >= (7 - 4 * a) / 11) {
713				return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2);
714			}
715		}
716	}};
717
718
719})(window);
720
721
722/* End */
723;
724; /* Start:"a:4:{s:4:"full";s:54:"/bitrix/js/main/pageobject/pageobject.js?1674157176864";s:6:"source";s:40:"/bitrix/js/main/pageobject/pageobject.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
725window.BX = BX || {};
726
727BX.PageObject = {
728	getRootWindow: function()
729	{
730		return BX.PageObject.getTopWindowOfCurrentHost(window);
731	},
732
733	isCrossOriginObject: function(currentWindow)
734	{
735		try
736		{
737			void currentWindow.location.host;
738		}
739		catch (e)
740		{
741			// cross-origin object
742			return true;
743		}
744
745		return false;
746	},
747
748	getTopWindowOfCurrentHost: function(currentWindow)
749	{
750		if (
751			!BX.PageObject.isCrossOriginObject(currentWindow.parent)
752			&& currentWindow.parent !== currentWindow
753			&& currentWindow.parent.location.host === currentWindow.location.host
754		)
755		{
756			return BX.PageObject.getTopWindowOfCurrentHost(currentWindow.parent);
757		}
758
759		return currentWindow;
760	},
761
762	getParentWindowOfCurrentHost: function(currentWindow)
763	{
764		if (BX.PageObject.isCrossOriginObject(currentWindow.parent))
765		{
766			return currentWindow;
767		}
768
769		return currentWindow.parent;
770	}
771};
772/* End */
773;
774; /* Start:"a:4:{s:4:"full";s:51:"/bitrix/js/main/core/core_window.js?167415717698371";s:6:"source";s:35:"/bitrix/js/main/core/core_window.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
775;(function(window) {
776if (BX.WindowManager) return;
777
778/* windows manager */
779BX.WindowManager = {
780	_stack: [],
781	_runtime_resize: {},
782	_delta: 2,
783	_delta_start: 1000,
784	currently_loaded: null,
785
786	settings_category: 'BX.WindowManager.9.5',
787
788	register: function (w)
789	{
790		this.currently_loaded = null;
791
792		w.WM_REG_INDEX = this._stack.length;
793		this._stack.push(w);
794
795		if (this._stack.length < 2)
796		{
797			BX.bind(document, 'keyup', BX.proxy(this.__checkKeyPress, this));
798		}
799	},
800
801	unregister: function (w)
802	{
803		if (null == w.WM_REG_INDEX)
804			return null;
805
806		var _current;
807		if (this._stack.length > 0)
808		{
809			while ((_current = this.__pop_stack()) != w)
810			{
811				if (!_current)
812				{
813					_current = null;
814					break;
815				}
816			}
817
818			if (this._stack.length <= 0)
819			{
820				this.enableKeyCheck();
821			}
822
823			return _current;
824		}
825		else
826		{
827			return null;
828		}
829	},
830
831	__pop_stack: function(clean)
832	{
833		if (this._stack.length > 0)
834		{
835			var _current = this._stack.pop();
836			_current.WM_REG_INDEX = null;
837			BX.onCustomEvent(_current, 'onWindowUnRegister', [clean === true]);
838
839			return _current;
840		}
841		else
842			return null;
843	},
844
845	clean: function()
846	{
847		while (this.__pop_stack(true)){}
848		this._stack = null;
849		this.disableKeyCheck();
850	},
851
852	Get: function()
853	{
854		if (this.currently_loaded)
855			return this.currently_loaded;
856		else if (this._stack.length > 0)
857			return this._stack[this._stack.length-1];
858		else
859			return null;
860	},
861
862	setStartZIndex: function(value)
863	{
864		this._delta_start = value;
865	},
866
867	restoreStartZIndex: function()
868	{
869		this._delta_start = 1000;
870	},
871
872	GetZIndex: function()
873	{
874		var _current;
875		return (null != (_current = this._stack[this._stack.length-1])
876			? parseInt(_current.Get().style.zIndex) + this._delta
877			: this._delta_start
878		);
879	},
880
881	__get_check_url: function(url)
882	{
883		var pos = url.indexOf('?');
884		return pos == -1 ? url : url.substring(0, pos);
885	},
886
887	saveWindowSize: function(url, params)
888	{
889		var check_url = this.__get_check_url(url);
890		if (BX.userOptions)
891		{
892			BX.userOptions.save(this.settings_category, 'size_' + check_url, 'width', params.width);
893			BX.userOptions.save(this.settings_category, 'size_' + check_url, 'height', params.height);
894		}
895
896		this._runtime_resize[check_url] = params;
897	},
898
899	saveWindowOptions: function(wnd_id, opts)
900	{
901		if (BX.userOptions)
902		{
903			for (var i in opts)
904			{
905				if(opts.hasOwnProperty(i))
906				{
907					BX.userOptions.save(this.settings_category, 'options_' + wnd_id, i, opts[i]);
908				}
909			}
910		}
911	},
912
913	getRuntimeWindowSize: function(url)
914	{
915		return this._runtime_resize[this.__get_check_url(url)];
916	},
917
918	disableKeyCheck: function()
919	{
920		BX.unbind(document, 'keyup', BX.proxy(this.__checkKeyPress, this));
921	},
922
923	enableKeyCheck: function()
924	{
925		BX.bind(document, 'keyup', BX.proxy(this.__checkKeyPress, this));
926	},
927
928	__checkKeyPress: function(e)
929	{
930		if (null == e)
931			e = window.event;
932
933		if (e.keyCode == 27)
934		{
935			var wnd = BX.WindowManager.Get();
936			if (wnd && !wnd.unclosable) wnd.Close();
937		}
938	}
939};
940
941BX.garbage(BX.WindowManager.clean, BX.WindowManager);
942
943/* base button class */
944BX.CWindowButton = function(params)
945{
946	if (params.btn)
947	{
948		this.btn = params.btn;
949		this.parentWindow = params.parentWindow;
950
951		if (/save|apply/i.test(this.btn.name))
952		{
953			BX.bind(this.btn, 'click', BX.delegate(this.disableUntilError, this));
954		}
955	}
956	else
957	{
958		this.title = params.title; // html value attr
959		this.hint = params.hint; // html title attr
960		this.id = params.id; // html name and id attrs
961		this.name = params.name; // html name or value attrs when id and title 're absent
962		this.className = params.className; // className for button input
963
964		this.action = params.action;
965		this.onclick = params.onclick;
966
967		// you can override button creation method
968		if (params.Button && BX.type.isFunction(params.Button))
969			this.Button = params.Button;
970
971		this.btn = null;
972	}
973};
974
975BX.CWindowButton.prototype.disable = function()
976{
977	if (this.btn)
978		this.parentWindow.showWait(this.btn);
979};
980BX.CWindowButton.prototype.enable = function(){
981	if (this.btn)
982		this.parentWindow.closeWait(this.btn);
983};
984
985BX.CWindowButton.prototype.emulate = function()
986{
987	if (this.btn && this.btn.disabled)
988		return;
989
990	var act =
991		this.action
992		? BX.delegate(this.action, this)
993		: (
994			this.onclick
995			? this.onclick
996			: (
997				this.btn
998				? this.btn.getAttribute('onclick')
999				: ''
1000			)
1001		);
1002
1003	if (act)
1004	{
1005		setTimeout(act, 50);
1006		if (this.btn && /save|apply/i.test(this.btn.name) && !this.action)
1007		{
1008			this.disableUntilError();
1009		}
1010	}
1011};
1012
1013BX.CWindowButton.prototype.Button = function(parentWindow)
1014{
1015	this.parentWindow = parentWindow;
1016
1017	var btn = {
1018		props: {
1019			'type': 'button',
1020			'name': this.id ? this.id : this.name,
1021			'value': this.title ? this.title : this.name,
1022			'id': this.id
1023		}
1024	};
1025
1026	if (this.hint)
1027		btn.props.title = this.hint;
1028	if (!!this.className)
1029		btn.props.className = this.className;
1030
1031	if (this.action)
1032	{
1033		btn.events = {
1034			'click': BX.delegate(this.action, this)
1035		};
1036	}
1037	else if (this.onclick)
1038	{
1039		if (BX.browser.IsIE())
1040		{
1041			btn.events = {
1042				'click': BX.delegate(function() {eval(this.onclick)}, this)
1043			};
1044		}
1045		else
1046		{
1047			btn.attrs = {
1048				'onclick': this.onclick
1049			};
1050		}
1051	}
1052
1053	this.btn = BX.create('INPUT', btn);
1054
1055	return this.btn;
1056};
1057
1058BX.CWindowButton.prototype.disableUntilError = function() {
1059	this.disable();
1060	if (!this.__window_error_handler_set)
1061	{
1062		BX.addCustomEvent(this.parentWindow, 'onWindowError', BX.delegate(this.enable, this));
1063		this.__window_error_handler_set = true;
1064	}
1065};
1066
1067/* base window class */
1068BX.CWindow = function(div, type)
1069{
1070	this.DIV = div || document.createElement('DIV');
1071
1072	this.SETTINGS = {
1073		resizable: false,
1074		min_height: 0,
1075		min_width: 0,
1076		top: 0,
1077		left: 0,
1078		draggable: false,
1079		drag_restrict: true,
1080		resize_restrict: true
1081	};
1082
1083	this.ELEMENTS = {
1084		draggable: [],
1085		resizer: [],
1086		close: []
1087	};
1088
1089	this.type = type == 'float' ? 'float' : 'dialog';
1090
1091	BX.adjust(this.DIV, {
1092		props: {
1093			className: 'bx-core-window'
1094		},
1095		style: {
1096			'zIndex': 0,
1097			'position': 'absolute',
1098			'display': 'none',
1099			'top': this.SETTINGS.top + 'px',
1100			'left': this.SETTINGS.left + 'px',
1101			'height': '100px',
1102			'width': '100px'
1103		}
1104	});
1105
1106	this.isOpen = false;
1107
1108	BX.addCustomEvent(this, 'onWindowRegister', BX.delegate(this.onRegister, this));
1109	BX.addCustomEvent(this, 'onWindowUnRegister', BX.delegate(this.onUnRegister, this));
1110
1111	this.MOUSEOVER = null;
1112	BX.bind(this.DIV, 'mouseover', BX.delegate(this.__set_msover, this));
1113	BX.bind(this.DIV, 'mouseout', BX.delegate(this.__unset_msover, this));
1114
1115	BX.ready(BX.delegate(function() {
1116		document.body.appendChild(this.DIV);
1117		BX.ZIndexManager.register(this.DIV);
1118	}, this));
1119};
1120
1121BX.CWindow.prototype.Get = function () {return this.DIV};
1122BX.CWindow.prototype.visible = function() {return this.isOpen;};
1123
1124BX.CWindow.prototype.Show = function(bNotRegister)
1125{
1126	this.DIV.style.display = 'block';
1127
1128	if (!bNotRegister)
1129	{
1130		BX.WindowManager.register(this);
1131		BX.onCustomEvent(this, 'onWindowRegister');
1132	}
1133
1134	BX.ZIndexManager.bringToFront(this.DIV);
1135};
1136
1137BX.CWindow.prototype.Hide = function()
1138{
1139	BX.WindowManager.unregister(this);
1140	this.DIV.style.display = 'none';
1141};
1142
1143BX.CWindow.prototype.onRegister = function()
1144{
1145	this.isOpen = true;
1146};
1147
1148BX.CWindow.prototype.onUnRegister = function(clean)
1149{
1150	this.isOpen = false;
1151
1152	if (clean || (this.PARAMS && this.PARAMS.content_url))
1153	{
1154		if (clean) {BX.onCustomEvent(this, 'onWindowClose', [this, true]);}
1155
1156		if (this.DIV.parentNode)
1157			this.DIV.parentNode.removeChild(this.DIV);
1158	}
1159	else
1160	{
1161		this.DIV.style.display = 'none';
1162	}
1163};
1164
1165BX.CWindow.prototype.CloseDialog = // compatibility
1166BX.CWindow.prototype.Close = function(bImmediately)
1167{
1168	BX.onCustomEvent(this, 'onBeforeWindowClose', [this]);
1169	if (bImmediately !== true)
1170	{
1171		if (this.denyClose)
1172			return false;
1173	}
1174
1175	BX.onCustomEvent(this, 'onWindowClose', [this]);
1176
1177	//this crashes vis editor in ie via onWindowResizeExt event handler
1178	//if (this.bExpanded) this.__expand();
1179	// alternative version:
1180	if (this.bExpanded)
1181	{
1182		var pDocElement = BX.GetDocElement();
1183		BX.unbind(window, 'resize', BX.proxy(this.__expand_onresize, this));
1184		pDocElement.style.overflow = this.__expand_settings.overflow;
1185	}
1186
1187	BX.WindowManager.unregister(this);
1188
1189	return true;
1190};
1191
1192BX.CWindow.prototype.SetResize = function(elem)
1193{
1194	elem.style.cursor = 'se-resize';
1195	BX.bind(elem, 'mousedown', BX.proxy(this.__startResize, this));
1196
1197	this.ELEMENTS.resizer.push(elem);
1198	this.SETTINGS.resizable = true;
1199};
1200
1201BX.CWindow.prototype.SetExpand = function(elem, event_name)
1202{
1203	event_name = event_name || 'click';
1204	BX.bind(elem, event_name, BX.proxy(this.__expand, this));
1205};
1206
1207BX.CWindow.prototype.__expand_onresize = function()
1208{
1209	var windowSize = BX.GetWindowInnerSize();
1210	this.DIV.style.width = windowSize.innerWidth + "px";
1211	this.DIV.style.height = windowSize.innerHeight + "px";
1212
1213	BX.onCustomEvent(this, 'onWindowResize');
1214};
1215
1216BX.CWindow.prototype.__expand = function()
1217{
1218	var pDocElement = BX.GetDocElement();
1219
1220	if (!this.bExpanded)
1221	{
1222		var wndScroll = BX.GetWindowScrollPos(),
1223			wndSize = BX.GetWindowInnerSize();
1224
1225		this.__expand_settings = {
1226			resizable: this.SETTINGS.resizable,
1227			draggable: this.SETTINGS.draggable,
1228			width: this.DIV.style.width,
1229			height: this.DIV.style.height,
1230			left: this.DIV.style.left,
1231			top: this.DIV.style.top,
1232			scrollTop: wndScroll.scrollTop,
1233			scrollLeft: wndScroll.scrollLeft,
1234			overflow: BX.style(pDocElement, 'overflow')
1235		};
1236
1237		this.SETTINGS.resizable = false;
1238		this.SETTINGS.draggable = false;
1239
1240		window.scrollTo(0,0);
1241		pDocElement.style.overflow = 'hidden';
1242
1243		this.DIV.style.top = '0px';
1244		this.DIV.style.left = '0px';
1245
1246		this.DIV.style.width = wndSize.innerWidth + 'px';
1247		this.DIV.style.height = wndSize.innerHeight + 'px';
1248
1249		this.bExpanded = true;
1250
1251		BX.onCustomEvent(this, 'onWindowExpand');
1252		BX.onCustomEvent(this, 'onWindowResize');
1253
1254		BX.bind(window, 'resize', BX.proxy(this.__expand_onresize, this));
1255	}
1256	else
1257	{
1258		BX.unbind(window, 'resize', BX.proxy(this.__expand_onresize, this));
1259
1260		this.SETTINGS.resizable = this.__expand_settings.resizable;
1261		this.SETTINGS.draggable = this.__expand_settings.draggable;
1262
1263		pDocElement.style.overflow = this.__expand_settings.overflow;
1264
1265		this.DIV.style.top = this.__expand_settings.top;
1266		this.DIV.style.left = this.__expand_settings.left;
1267		this.DIV.style.width = this.__expand_settings.width;
1268		this.DIV.style.height = this.__expand_settings.height;
1269
1270		window.scrollTo(this.__expand_settings.scrollLeft, this.__expand_settings.scrollTop);
1271
1272		this.bExpanded = false;
1273
1274		BX.onCustomEvent(this, 'onWindowNarrow');
1275		BX.onCustomEvent(this, 'onWindowResize');
1276
1277	}
1278};
1279
1280BX.CWindow.prototype.Resize = function(x, y)
1281{
1282	var new_width = Math.max(x - this.pos.left + this.dx, this.SETTINGS.min_width);
1283	var new_height = Math.max(y - this.pos.top + this.dy, this.SETTINGS.min_height);
1284
1285	if (this.SETTINGS.resize_restrict)
1286	{
1287		var scrollSize = BX.GetWindowScrollSize();
1288
1289		if (this.pos.left + new_width > scrollSize.scrollWidth - this.dw)
1290			new_width = scrollSize.scrollWidth - this.pos.left - this.dw;
1291	}
1292
1293	this.DIV.style.width = new_width + 'px';
1294	this.DIV.style.height = new_height + 'px';
1295
1296	BX.onCustomEvent(this, 'onWindowResize');
1297};
1298
1299BX.CWindow.prototype.__startResize = function(e)
1300{
1301	if (!this.SETTINGS.resizable)
1302		return false;
1303
1304	if(!e) e = window.event;
1305
1306	this.wndSize = BX.GetWindowScrollPos();
1307	this.wndSize.innerWidth = BX.GetWindowInnerSize().innerWidth;
1308
1309	this.pos = BX.pos(this.DIV);
1310
1311	this.x = e.clientX + this.wndSize.scrollLeft;
1312	this.y = e.clientY + this.wndSize.scrollTop;
1313
1314	this.dx = this.pos.left + this.pos.width - this.x;
1315	this.dy = this.pos.top + this.pos.height - this.y;
1316	this.dw = this.pos.width - parseInt(this.DIV.style.width);
1317
1318	BX.bind(document, "mousemove", BX.proxy(this.__moveResize, this));
1319	BX.bind(document, "mouseup", BX.proxy(this.__stopResize, this));
1320
1321	if(document.body.setCapture)
1322		document.body.setCapture();
1323
1324	document.onmousedown = BX.False;
1325
1326	var b = document.body;
1327	b.ondrag = b.onselectstart = BX.False;
1328	b.style.MozUserSelect = this.DIV.style.MozUserSelect = 'none';
1329	b.style.cursor = 'se-resize';
1330
1331	BX.onCustomEvent(this, 'onWindowResizeStart');
1332
1333	return true;
1334};
1335
1336BX.CWindow.prototype.__moveResize = function(e)
1337{
1338	if(!e) e = window.event;
1339
1340	var windowScroll = BX.GetWindowScrollPos();
1341
1342	var x = e.clientX + windowScroll.scrollLeft;
1343	var y = e.clientY + windowScroll.scrollTop;
1344
1345	if(this.x == x && this.y == y)
1346		return;
1347
1348	this.Resize(x, y);
1349
1350	this.x = x;
1351	this.y = y;
1352};
1353
1354BX.CWindow.prototype.__stopResize = function()
1355{
1356	if(document.body.releaseCapture)
1357		document.body.releaseCapture();
1358
1359	BX.unbind(document, "mousemove", BX.proxy(this.__moveResize, this));
1360	BX.unbind(document, "mouseup", BX.proxy(this.__stopResize, this));
1361
1362	document.onmousedown = null;
1363
1364	var b = document.body;
1365	b.ondrag = b.onselectstart = null;
1366	b.style.MozUserSelect = this.DIV.style.MozUserSelect = '';
1367	b.style.cursor = '';
1368
1369	BX.onCustomEvent(this, 'onWindowResizeFinished')
1370};
1371
1372BX.CWindow.prototype.SetClose = function(elem)
1373{
1374	BX.bind(elem, 'click', BX.proxy(this.Close, this));
1375	this.ELEMENTS.close.push(elem);
1376};
1377
1378BX.CWindow.prototype.SetDraggable = function(elem)
1379{
1380	BX.bind(elem, 'mousedown', BX.proxy(this.__startDrag, this));
1381
1382	elem.style.cursor = 'move';
1383
1384	this.ELEMENTS.draggable.push(elem);
1385	this.SETTINGS.draggable = true;
1386};
1387
1388BX.CWindow.prototype.Move = function(x, y)
1389{
1390	var dxShadow = 1; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1391
1392	var left = parseInt(this.DIV.style.left)+x;
1393	var top = parseInt(this.DIV.style.top)+y;
1394
1395	if (this.SETTINGS.drag_restrict)
1396	{
1397		//Left side
1398		if (left < 0)
1399			left = 0;
1400
1401		//Right side
1402		var scrollSize = BX.GetWindowScrollSize();
1403		var floatWidth = this.DIV.offsetWidth;
1404		var floatHeight = this.DIV.offsetHeight;
1405
1406		if (left > (scrollSize.scrollWidth - floatWidth - dxShadow))
1407			left = scrollSize.scrollWidth - floatWidth - dxShadow;
1408
1409		var scrollHeight = Math.max(
1410			document.body.scrollHeight, document.documentElement.scrollHeight,
1411			document.body.offsetHeight, document.documentElement.offsetHeight,
1412			document.body.clientHeight, document.documentElement.clientHeight,
1413			scrollSize.scrollHeight
1414		);
1415
1416		if (top > (scrollHeight - floatHeight - dxShadow))
1417			top = scrollHeight - floatHeight - dxShadow;
1418
1419		//Top side
1420		if (top < 0)
1421			top = 0;
1422	}
1423
1424	this.DIV.style.left = left+'px';
1425	this.DIV.style.top = top+'px';
1426
1427	//this.AdjustShadow(div);
1428};
1429
1430BX.CWindow.prototype.__startDrag = function(e)
1431{
1432	if (!this.SETTINGS.draggable)
1433		return false;
1434
1435	if(!e) e = window.event;
1436
1437	this.x = e.clientX + document.body.scrollLeft;
1438	this.y = e.clientY + document.body.scrollTop;
1439
1440	this.__bWasDragged = false;
1441	BX.bind(document, "mousemove", BX.proxy(this.__moveDrag, this));
1442	BX.bind(document, "mouseup", BX.proxy(this.__stopDrag, this));
1443
1444	if(document.body.setCapture)
1445		document.body.setCapture();
1446
1447	document.onmousedown = BX.False;
1448
1449	var b = document.body;
1450	b.ondrag = b.onselectstart = BX.False;
1451	b.style.MozUserSelect = this.DIV.style.MozUserSelect = 'none';
1452	b.style.cursor = 'move';
1453	return BX.PreventDefault(e);
1454};
1455
1456BX.CWindow.prototype.__moveDrag = function(e)
1457{
1458	if(!e) e = window.event;
1459
1460	var x = e.clientX + document.body.scrollLeft;
1461	var y = e.clientY + document.body.scrollTop;
1462
1463	if(this.x == x && this.y == y)
1464		return;
1465
1466	this.Move((x - this.x), (y - this.y));
1467	this.x = x;
1468	this.y = y;
1469
1470	if (!this.__bWasDragged)
1471	{
1472		BX.onCustomEvent(this, 'onWindowDragStart');
1473		this.__bWasDragged = true;
1474		BX.bind(BX.proxy_context, "click", BX.PreventDefault);
1475	}
1476
1477	BX.onCustomEvent(this, 'onWindowDrag');
1478};
1479
1480BX.CWindow.prototype.__stopDrag = function(e)
1481{
1482	if(document.body.releaseCapture)
1483		document.body.releaseCapture();
1484
1485	BX.unbind(document, "mousemove", BX.proxy(this.__moveDrag, this));
1486	BX.unbind(document, "mouseup", BX.proxy(this.__stopDrag, this));
1487
1488	document.onmousedown = null;
1489
1490	var b = document.body;
1491	b.ondrag = b.onselectstart = null;
1492	b.style.MozUserSelect = this.DIV.style.MozUserSelect = '';
1493	b.style.cursor = '';
1494
1495	if (this.__bWasDragged)
1496	{
1497		BX.onCustomEvent(this, 'onWindowDragFinished');
1498		var _proxy_context = BX.proxy_context;
1499		setTimeout(function(){BX.unbind(_proxy_context, "click", BX.PreventDefault)}, 100);
1500		this.__bWasDragged = false;
1501	}
1502	return BX.PreventDefault(e);
1503};
1504
1505BX.CWindow.prototype.DenyClose = function()
1506{
1507	this.denyClose = true;
1508};
1509
1510BX.CWindow.prototype.AllowClose = function()
1511{
1512	this.denyClose = false;
1513};
1514
1515BX.CWindow.prototype.ShowError = function(str)
1516{
1517	BX.onCustomEvent(this, 'onWindowError', [str]);
1518
1519	if (this._wait)
1520		BX.closeWait(this._wait);
1521
1522	window.alert(str);
1523};
1524
1525BX.CWindow.prototype.__set_msover = function() {this.MOUSEOVER = true;};
1526BX.CWindow.prototype.__unset_msover = function() {this.MOUSEOVER = false;};
1527
1528/* dialog window class extends window class */
1529BX.CWindowDialog = function() {
1530	var a = arguments;
1531	a[1] = 'dialog';
1532	BX.CWindowDialog.superclass.constructor.apply(this, a);
1533
1534	this.DIV.style.top = '10px';
1535	this.OVERLAY = null;
1536};
1537BX.extend(BX.CWindowDialog, BX.CWindow);
1538
1539BX.CWindowDialog.prototype.__resizeOverlay = function()
1540{
1541	var windowSize = BX.GetWindowScrollSize();
1542	this.OVERLAY.style.width = windowSize.scrollWidth + "px";
1543};
1544
1545BX.CWindowDialog.prototype.CreateOverlay = function(zIndex)
1546{
1547	if (null == this.OVERLAY)
1548	{
1549		var windowSize = BX.GetWindowScrollSize();
1550
1551		// scrollHeight in BX.GetWindowScrollSize may be incorrect
1552		var scrollHeight = Math.max(
1553			document.body.scrollHeight, document.documentElement.scrollHeight,
1554			document.body.offsetHeight, document.documentElement.offsetHeight,
1555			document.body.clientHeight, document.documentElement.clientHeight,
1556			windowSize.scrollHeight
1557		);
1558
1559		this.OVERLAY = document.body.appendChild(BX.create("DIV", {
1560			style: {
1561				position: 'absolute',
1562				top: '0px',
1563				left: '0px',
1564				zIndex: zIndex || (parseInt(this.DIV.style.zIndex)-2),
1565				width: windowSize.scrollWidth + "px",
1566				height: scrollHeight + "px"
1567			}
1568		}));
1569
1570		var component = BX.ZIndexManager.getComponent(this.DIV);
1571		if (component)
1572		{
1573			component.setOverlay(this.OVERLAY);
1574		}
1575	}
1576
1577	return this.OVERLAY;
1578};
1579
1580BX.CWindowDialog.prototype.Show = function()
1581{
1582	BX.CWindowDialog.superclass.Show.apply(this, arguments);
1583
1584	this.CreateOverlay();
1585
1586	this.OVERLAY.style.display = 'block';
1587
1588	BX.unbind(window, 'resize', BX.proxy(this.__resizeOverlay, this));
1589	BX.bind(window, 'resize', BX.proxy(this.__resizeOverlay, this));
1590};
1591
1592BX.CWindowDialog.prototype.onUnRegister = function(clean)
1593{
1594	BX.CWindowDialog.superclass.onUnRegister.apply(this, arguments);
1595
1596	if (this.clean)
1597	{
1598		if (this.OVERLAY.parentNode)
1599			this.OVERLAY.parentNode.removeChild(this.OVERLAY);
1600	}
1601	else
1602	{
1603		this.OVERLAY.style.display = 'none';
1604	}
1605
1606	BX.unbind(window, 'resize', BX.proxy(this.__resizeOverlay, this));
1607};
1608
1609/* standard bitrix dialog extends BX.CWindowDialog */
1610/*
1611	arParams = {
1612		(
1613			title: 'dialog title',
1614			head: 'head block html',
1615			content: 'dialog content',
1616			icon: 'head icon classname or filename',
1617
1618			resize_id: 'some id to save resize information'// useless if resizable = false
1619		)
1620		or
1621		(
1622			content_url: url to content load
1623				loaded content scripts can use BX.WindowManager.Get() to get access to the current window object
1624		)
1625
1626		height: window_height_in_pixels,
1627		width: window_width_in_pixels,
1628
1629		draggable: true|false,
1630		resizable: true|false,
1631
1632		min_height: min_window_height_in_pixels, // useless if resizable = false
1633		min_width: min_window_width_in_pixels, // useless if resizable = false
1634
1635		buttons: [
1636			'html_code',
1637			BX.CDialog.btnSave, BX.CDialog.btnCancel, BX.CDialog.btnClose
1638		]
1639	}
1640*/
1641BX.CDialog = function(arParams)
1642{
1643	BX.CDialog.superclass.constructor.apply(this);
1644
1645	this._sender = 'core_window_cdialog';
1646
1647	this.PARAMS = arParams || {};
1648
1649	for (var i in this.defaultParams)
1650	{
1651		if (typeof this.PARAMS[i] == 'undefined')
1652			this.PARAMS[i] = this.defaultParams[i];
1653	}
1654
1655	this.PARAMS.width = (!isNaN(parseInt(this.PARAMS.width)))
1656		? this.PARAMS.width
1657		: this.defaultParams['width'];
1658	this.PARAMS.height = (!isNaN(parseInt(this.PARAMS.height)))
1659		? this.PARAMS.height
1660		: this.defaultParams['height'];
1661
1662	if (this.PARAMS.resize_id || this.PARAMS.content_url)
1663	{
1664		var arSize = BX.WindowManager.getRuntimeWindowSize(this.PARAMS.resize_id || this.PARAMS.content_url);
1665		if (arSize)
1666		{
1667			this.PARAMS.width = arSize.width;
1668			this.PARAMS.height = arSize.height;
1669		}
1670	}
1671
1672	BX.addClass(this.DIV, 'bx-core-adm-dialog');
1673	this.DIV.id = 'bx-admin-prefix';
1674
1675	this.PARTS = {};
1676
1677	this.DIV.style.height = null;
1678	this.DIV.style.width = null;
1679
1680	this.PARTS.TITLEBAR = this.DIV.appendChild(BX.create('DIV', {props: {
1681			className: 'bx-core-adm-dialog-head'
1682		}
1683	}));
1684
1685	this.PARTS.TITLE_CONTAINER = this.PARTS.TITLEBAR.appendChild(BX.create('SPAN', {
1686		props: {className: 'bx-core-adm-dialog-head-inner'},
1687		text: this.PARAMS.title
1688	}));
1689
1690	this.PARTS.TITLEBAR_ICONS = this.PARTS.TITLEBAR.appendChild(BX.create('DIV', {
1691		props: {
1692			className: 'bx-core-adm-dialog-head-icons'
1693		},
1694		children: (this.PARAMS.resizable ? [
1695			BX.create('SPAN', {props: {className: 'bx-core-adm-icon-expand', title: BX.message('JS_CORE_WINDOW_EXPAND')}}),
1696			BX.create('SPAN', {props: {className: 'bx-core-adm-icon-close', title: BX.message('JS_CORE_WINDOW_CLOSE')}})
1697		] : [
1698			BX.create('SPAN', {props: {className: 'bx-core-adm-icon-close', title: BX.message('JS_CORE_WINDOW_CLOSE')}})
1699		])
1700	}));
1701
1702
1703	this.PARTS.CONTENT = this.DIV.appendChild(BX.create('DIV', {
1704		props: {className: 'bx-core-adm-dialog-content-wrap adm-workarea'}
1705	}));
1706
1707	this.PARTS.CONTENT_DATA = this.PARTS.CONTENT.appendChild(BX.create('DIV', {
1708		props: {className: 'bx-core-adm-dialog-content'},
1709		style: {
1710			height: this.PARAMS.height + 'px',
1711			width: this.PARAMS.width + 'px'
1712		}
1713	}));
1714
1715	this.PARTS.HEAD = this.PARTS.CONTENT_DATA.appendChild(BX.create('DIV', {
1716		props: {
1717			className: 'bx-core-adm-dialog-head-block' + (this.PARAMS.icon ? ' ' + this.PARAMS.icon : '')
1718		}
1719	}));
1720
1721	this.SetHead(this.PARAMS.head);
1722	this.SetContent(this.PARAMS.content);
1723	this.SetTitle(this.PARAMS.title);
1724	this.SetClose(this.PARTS.TITLEBAR_ICONS.lastChild);
1725
1726	if (this.PARAMS.resizable)
1727	{
1728		this.SetExpand(this.PARTS.TITLEBAR_ICONS.firstChild);
1729		this.SetExpand(this.PARTS.TITLEBAR, 'dblclick');
1730
1731		BX.addCustomEvent(this, 'onWindowExpand', BX.proxy(this.__onexpand, this));
1732		BX.addCustomEvent(this, 'onWindowNarrow', BX.proxy(this.__onexpand, this));
1733	}
1734
1735	this.PARTS.FOOT = this.PARTS.BUTTONS_CONTAINER = this.PARTS.CONTENT.appendChild(BX.create('DIV', {
1736			props: {
1737				className: 'bx-core-adm-dialog-buttons'
1738			},
1739			//events: {
1740			//	'click': BX.delegateEvent({property:{type: /button|submit/}}, BX.delegate(function() {this.showWait(BX.proxy_context)}, this))
1741			//},
1742			children: this.ShowButtons()
1743		}
1744	));
1745
1746	if (this.PARAMS.draggable)
1747		this.SetDraggable(this.PARTS.TITLEBAR);
1748
1749	if (this.PARAMS.resizable)
1750	{
1751		this.PARTS.RESIZER = this.DIV.appendChild(BX.create('DIV', {
1752			props: {className: 'bx-core-resizer'}
1753		}));
1754
1755		this.SetResize(this.PARTS.RESIZER);
1756
1757		this.SETTINGS.min_width = this.PARAMS.min_width;
1758		this.SETTINGS.min_height = this.PARAMS.min_height;
1759	}
1760
1761	this.auth_callback = BX.delegate(function(){
1762		this.PARAMS.content = '';
1763		this.hideNotify();
1764		this.Show();
1765	}, this)
1766};
1767BX.extend(BX.CDialog, BX.CWindowDialog);
1768
1769BX.CDialog.prototype.defaultParams = {
1770	width: 700,
1771	height: 400,
1772	min_width: 500,
1773	min_height: 300,
1774
1775	resizable: true,
1776	draggable: true,
1777
1778	title: '',
1779	icon: ''
1780};
1781
1782BX.CDialog.prototype.showWait = function(el)
1783{
1784	if (BX.type.isElementNode(el) && (el.type == 'button' || el.type == 'submit'))
1785	{
1786		BX.defer(function(){el.disabled = true})();
1787
1788		var bSave = (BX.hasClass(el, 'adm-btn-save') || BX.hasClass(el, 'adm-btn-save')),
1789			pos = BX.pos(el, true);
1790
1791		el.bxwaiter = this.PARTS.FOOT.appendChild(BX.create('DIV', {
1792			props: {className: 'adm-btn-load-img' + (bSave ? '-green' : '')},
1793			style: {
1794				top: parseInt((pos.bottom + pos.top)/2 - 10) + 'px',
1795				left: parseInt((pos.right + pos.left)/2 - 10) + 'px'
1796			}
1797		}));
1798
1799		BX.addClass(el, 'adm-btn-load');
1800
1801		this.lastWaitElement = el;
1802
1803		return el.bxwaiter;
1804	}
1805	return null;
1806};
1807
1808BX.CDialog.prototype.closeWait = function(el)
1809{
1810	el = el || this.lastWaitElement;
1811
1812	if (BX.type.isElementNode(el))
1813	{
1814		if (el.bxwaiter)
1815		{
1816			if(el.bxwaiter.parentNode)
1817			{
1818				el.bxwaiter.parentNode.removeChild(el.bxwaiter);
1819			}
1820
1821			el.bxwaiter = null;
1822		}
1823
1824		el.disabled = false;
1825		BX.removeClass(el, 'adm-btn-load');
1826
1827		if (this.lastWaitElement == el)
1828			this.lastWaitElement = null;
1829	}
1830};
1831
1832BX.CDialog.prototype.Authorize = function(arAuthResult)
1833{
1834	this.bSkipReplaceContent = true;
1835	this.ShowError(BX.message('JSADM_AUTH_REQ'));
1836
1837	BX.onCustomEvent(this, 'onWindowError', []);
1838
1839	BX.closeWait();
1840
1841	(new BX.CAuthDialog({
1842		content_url: this.PARAMS.content_url,
1843		auth_result: arAuthResult,
1844		callback: BX.delegate(function(){
1845			if (this.auth_callback)
1846				this.auth_callback()
1847		}, this)
1848	})).Show();
1849};
1850
1851BX.CDialog.prototype.ShowError = function(str)
1852{
1853	BX.onCustomEvent(this, 'onWindowError', [str]);
1854
1855	this.closeWait();
1856
1857	if (this._wait)
1858		BX.closeWait(this._wait);
1859
1860	this.Notify(str, true);
1861};
1862
1863
1864BX.CDialog.prototype.__expandGetSize = function()
1865{
1866	var pDocElement = BX.GetDocElement();
1867	pDocElement.style.overflow = 'hidden';
1868
1869	var wndSize = BX.GetWindowInnerSize();
1870
1871	pDocElement.scrollTop = 0;
1872
1873	this.DIV.style.top = '-' + this.dxShadow + 'px';
1874	this.DIV.style.left = '-' + this.dxShadow + 'px';
1875
1876	return {
1877		width: (wndSize.innerWidth - parseInt(BX.style(this.PARTS.CONTENT, 'padding-right')) - parseInt(BX.style(this.PARTS.CONTENT, 'padding-left'))) + this.dxShadow,
1878		height: (wndSize.innerHeight - this.PARTS.TITLEBAR.offsetHeight - this.PARTS.FOOT.offsetHeight - parseInt(BX.style(this.PARTS.CONTENT, 'padding-top')) - parseInt(BX.style(this.PARTS.CONTENT, 'padding-bottom'))) + this.dxShadow
1879	};
1880};
1881
1882BX.CDialog.prototype.__expand = function()
1883{
1884	var pDocElement = BX.GetDocElement();
1885	this.dxShadow = 2;
1886
1887	if (!this.bExpanded)
1888	{
1889		var wndScroll = BX.GetWindowScrollPos();
1890
1891		this.__expand_settings = {
1892			resizable: this.SETTINGS.resizable,
1893			draggable: this.SETTINGS.draggable,
1894			width: this.PARTS.CONTENT_DATA.style.width,
1895			height: this.PARTS.CONTENT_DATA.style.height,
1896			left: this.DIV.style.left,
1897			top: this.DIV.style.top,
1898			scrollTop: wndScroll.scrollTop,
1899			scrollLeft: wndScroll.scrollLeft,
1900			overflow: BX.style(pDocElement, 'overflow')
1901		};
1902
1903		this.SETTINGS.resizable = false;
1904		this.SETTINGS.draggable = false;
1905
1906		var pos = this.__expandGetSize();
1907
1908		this.PARTS.CONTENT_DATA.style.width = pos.width + 'px';
1909		this.PARTS.CONTENT_DATA.style.height = pos.height + 'px';
1910
1911		window.scrollTo(0,0);
1912		pDocElement.style.overflow = 'hidden';
1913
1914		this.bExpanded = true;
1915
1916		BX.onCustomEvent(this, 'onWindowExpand');
1917		BX.onCustomEvent(this, 'onWindowResize');
1918		BX.onCustomEvent(this, 'onWindowResizeExt', [{'width': pos.width, 'height': pos.height}]);
1919
1920		BX.bind(window, 'resize', BX.proxy(this.__expand_onresize, this));
1921	}
1922	else
1923	{
1924		BX.unbind(window, 'resize', BX.proxy(this.__expand_onresize, this));
1925
1926		this.SETTINGS.resizable = this.__expand_settings.resizable;
1927		this.SETTINGS.draggable = this.__expand_settings.draggable;
1928
1929		pDocElement.style.overflow = this.__expand_settings.overflow;
1930
1931		this.DIV.style.top = this.__expand_settings.top;
1932		this.DIV.style.left = this.__expand_settings.left;
1933		this.PARTS.CONTENT_DATA.style.width = this.__expand_settings.width;
1934		this.PARTS.CONTENT_DATA.style.height = this.__expand_settings.height;
1935		window.scrollTo(this.__expand_settings.scrollLeft, this.__expand_settings.scrollTop);
1936		this.bExpanded = false;
1937
1938		BX.onCustomEvent(this, 'onWindowNarrow');
1939		BX.onCustomEvent(this, 'onWindowResize');
1940		BX.onCustomEvent(this, 'onWindowResizeExt', [{'width': parseInt(this.__expand_settings.width), 'height': parseInt(this.__expand_settings.height)}]);
1941	}
1942};
1943
1944BX.CDialog.prototype.__expand_onresize = function()
1945{
1946	var pos = this.__expandGetSize();
1947
1948	this.PARTS.CONTENT_DATA.style.width = pos.width + 'px';
1949	this.PARTS.CONTENT_DATA.style.height = pos.height + 'px';
1950
1951	BX.onCustomEvent(this, 'onWindowResize');
1952	BX.onCustomEvent(this, 'onWindowResizeExt', [pos]);
1953};
1954
1955BX.CDialog.prototype.__onexpand = function()
1956{
1957	var ob = this.PARTS.TITLEBAR_ICONS.firstChild;
1958	ob.className = BX.toggle(ob.className, ['bx-core-adm-icon-expand', 'bx-core-adm-icon-narrow']);
1959	ob.title = BX.toggle(ob.title, [BX.message('JS_CORE_WINDOW_EXPAND'), BX.message('JS_CORE_WINDOW_NARROW')]);
1960
1961	if (this.PARTS.RESIZER)
1962	{
1963		this.PARTS.RESIZER.style.display = this.bExpanded ? 'none' : 'block';
1964	}
1965};
1966
1967
1968BX.CDialog.prototype.__startResize = function(e)
1969{
1970	if (!this.SETTINGS.resizable)
1971		return false;
1972
1973	if(!e) e = window.event;
1974
1975	this.wndSize = BX.GetWindowScrollPos();
1976	this.wndSize.innerWidth = BX.GetWindowInnerSize().innerWidth;
1977
1978	this.pos = BX.pos(this.PARTS.CONTENT_DATA);
1979
1980	this.x = e.clientX + this.wndSize.scrollLeft;
1981	this.y = e.clientY + this.wndSize.scrollTop;
1982
1983	this.dx = this.pos.left + this.pos.width - this.x;
1984	this.dy = this.pos.top + this.pos.height - this.y;
1985
1986
1987	// TODO: suspicious
1988	this.dw = this.pos.width - parseInt(this.PARTS.CONTENT_DATA.style.width) + parseInt(BX.style(this.PARTS.CONTENT, 'padding-right'));
1989
1990	BX.bind(document, "mousemove", BX.proxy(this.__moveResize, this));
1991	BX.bind(document, "mouseup", BX.proxy(this.__stopResize, this));
1992
1993	if(document.body.setCapture)
1994		document.body.setCapture();
1995
1996	document.onmousedown = BX.False;
1997
1998	var b = document.body;
1999	b.ondrag = b.onselectstart = BX.False;
2000	b.style.MozUserSelect = this.DIV.style.MozUserSelect = 'none';
2001	b.style.cursor = 'se-resize';
2002
2003	BX.onCustomEvent(this, 'onWindowResizeStart');
2004
2005	return true;
2006};
2007
2008BX.CDialog.prototype.Resize = function(x, y)
2009{
2010	var new_width = Math.max(x - this.pos.left + this.dx, this.SETTINGS.min_width);
2011	var new_height = Math.max(y - this.pos.top + this.dy, this.SETTINGS.min_height);
2012
2013	if (this.SETTINGS.resize_restrict)
2014	{
2015		var scrollSize = BX.GetWindowScrollSize();
2016
2017		if (this.pos.left + new_width > scrollSize.scrollWidth - this.dw)
2018			new_width = scrollSize.scrollWidth - this.pos.left - this.dw;
2019	}
2020
2021	this.PARTS.CONTENT_DATA.style.width = new_width + 'px';
2022	this.PARTS.CONTENT_DATA.style.height = new_height + 'px';
2023
2024	BX.onCustomEvent(this, 'onWindowResize');
2025	BX.onCustomEvent(this, 'onWindowResizeExt', [{'height': new_height, 'width': new_width}]);
2026};
2027
2028BX.CDialog.prototype.SetSize = function(obSize)
2029{
2030	this.PARTS.CONTENT_DATA.style.width = obSize.width + 'px';
2031	this.PARTS.CONTENT_DATA.style.height = obSize.height + 'px';
2032
2033	BX.onCustomEvent(this, 'onWindowResize');
2034	BX.onCustomEvent(this, 'onWindowResizeExt', [obSize]);
2035};
2036
2037BX.CDialog.prototype.GetParameters = function(form_name)
2038{
2039	var form = this.GetForm();
2040
2041	if(!form)
2042		return "";
2043
2044	var i, s = "";
2045	var n = form.elements.length;
2046
2047	var delim = '';
2048	for(i=0; i<n; i++)
2049	{
2050		if (s != '') delim = '&';
2051		var el = form.elements[i];
2052		if (el.disabled)
2053			continue;
2054
2055		switch(el.type.toLowerCase())
2056		{
2057			case 'text':
2058			case 'textarea':
2059			case 'password':
2060			case 'hidden':
2061				if (null == form_name && el.name.substr(el.name.length-4) == '_alt' && form.elements[el.name.substr(0, el.name.length-4)])
2062					break;
2063				s += delim + el.name + '=' + BX.util.urlencode(el.value);
2064				break;
2065			case 'radio':
2066				if(el.checked)
2067					s += delim + el.name + '=' + BX.util.urlencode(el.value);
2068				break;
2069			case 'checkbox':
2070				s += delim + el.name + '=' + BX.util.urlencode(el.checked ? 'Y':'N');
2071				break;
2072			case 'select-one':
2073				var val = "";
2074				if (null == form_name && form.elements[el.name + '_alt'] && el.selectedIndex == 0)
2075					val = form.elements[el.name+'_alt'].value;
2076				else
2077					val = el.value;
2078				s += delim + el.name + '=' + BX.util.urlencode(val);
2079				break;
2080			case 'select-multiple':
2081				var j, bAdded = false;
2082				var l = el.options.length;
2083				for (j=0; j<l; j++)
2084				{
2085					if (el.options[j].selected)
2086					{
2087						s += delim + el.name + '=' + BX.util.urlencode(el.options[j].value);
2088						bAdded = true;
2089					}
2090				}
2091				if (!bAdded)
2092					s += delim + el.name + '=';
2093				break;
2094			default:
2095				break;
2096		}
2097	}
2098
2099	return s;
2100};
2101
2102BX.CDialog.prototype.PostParameters = function(params)
2103{
2104	var url = this.PARAMS.content_url;
2105
2106	if (null == params)
2107		params = "";
2108
2109	params += (params == "" ? "" : "&") + "bxsender=" + this._sender;
2110
2111	var index = url.indexOf('?');
2112	if (index == -1)
2113		url += '?' + params;
2114	else
2115		url = url.substring(0, index) + '?' + params + "&" + url.substring(index+1);
2116
2117	BX.showWait();
2118
2119	this.auth_callback = BX.delegate(function(){
2120		this.hideNotify();
2121		this.PostParameters(params);
2122	}, this);
2123
2124	BX.ajax.Setup({skipAuthCheck:true},true);
2125	BX.ajax.post(url, this.GetParameters(), BX.delegate(function(result) {
2126		BX.closeWait();
2127		if (!this.bSkipReplaceContent)
2128		{
2129			this.ClearButtons(); // buttons are appended during form reload, so we should clear footer
2130			this.SetContent(result);
2131			this.Show(true);
2132		}
2133
2134		this.bSkipReplaceContent = false;
2135	}, this));
2136};
2137
2138BX.CDialog.prototype.Submit = function(params, url)
2139{
2140	var FORM = this.GetForm();
2141	if (FORM)
2142	{
2143		FORM.onsubmit = null;
2144
2145		FORM.method = 'POST';
2146		if (!FORM.action || url)
2147		{
2148			url = url || this.PARAMS.content_url;
2149			if (null != params)
2150			{
2151				var index = url.indexOf('?');
2152				if (index == -1)
2153					url += '?' + params;
2154				else
2155					url = url.substring(0, index) + '?' + params + "&" + url.substring(index+1);
2156			}
2157
2158			FORM.action = url;
2159		}
2160
2161		if (!FORM._bxsender)
2162		{
2163			FORM._bxsender = FORM.appendChild(BX.create('INPUT', {
2164				attrs: {
2165					type: 'hidden',
2166					name: 'bxsender',
2167					value: this._sender
2168				}
2169			}));
2170		}
2171
2172		this._wait = BX.showWait();
2173
2174		this.auth_callback = BX.delegate(function(){
2175			this.hideNotify();
2176			this.Submit(params);
2177		}, this);
2178
2179		BX.ajax.submit(FORM, BX.delegate(function(){this.closeWait()}, this));
2180	}
2181	else
2182	{
2183		window.alert('no form registered!');
2184	}
2185};
2186
2187BX.CDialog.prototype.GetForm = function()
2188{
2189	if (null == this.__form)
2190	{
2191		var forms = this.PARTS.CONTENT_DATA.getElementsByTagName('FORM');
2192		this.__form = forms[0] ? forms[0] : null;
2193	}
2194
2195	return this.__form;
2196};
2197
2198BX.CDialog.prototype.GetRealForm = function()
2199{
2200	if (null == this.__rform)
2201	{
2202		var forms = this.PARTS.CONTENT_DATA.getElementsByTagName('FORM');
2203		this.__rform = forms[1] ? forms[1] : (forms[0] ? forms[0] : null);
2204	}
2205
2206	return this.__rform;
2207};
2208
2209BX.CDialog.prototype._checkButton = function(btn)
2210{
2211	var arCustomButtons = ['btnSave', 'btnCancel', 'btnClose'];
2212
2213	for (var i = 0; i < arCustomButtons.length; i++)
2214	{
2215		if (this[arCustomButtons[i]] && (btn == this[arCustomButtons[i]]))
2216			return arCustomButtons[i];
2217	}
2218
2219	return false;
2220};
2221
2222BX.CDialog.prototype.ShowButtons = function()
2223{
2224	var result = [];
2225	if (this.PARAMS.buttons)
2226	{
2227		if (this.PARAMS.buttons.title) this.PARAMS.buttons = [this.PARAMS.buttons];
2228
2229		for (var i=0, len=this.PARAMS.buttons.length; i<len; i++)
2230		{
2231			if (BX.type.isNotEmptyString(this.PARAMS.buttons[i]))
2232			{
2233				result.push(this.PARAMS.buttons[i]);
2234			}
2235			else if (BX.type.isElementNode(this.PARAMS.buttons[i]))
2236			{
2237				result.push(this.PARAMS.buttons[i]);
2238			}
2239			else if (this.PARAMS.buttons[i])
2240			{
2241				//if (!(this.PARAMS.buttons[i] instanceof BX.CWindowButton))
2242				if (!BX.is_subclass_of(this.PARAMS.buttons[i], BX.CWindowButton))
2243				{
2244					var b = this._checkButton(this.PARAMS.buttons[i]); // hack to set links to real CWindowButton object in btnSave etc;
2245					this.PARAMS.buttons[i] = new BX.CWindowButton(this.PARAMS.buttons[i]);
2246					if (b) this[b] = this.PARAMS.buttons[i];
2247				}
2248
2249				result.push(this.PARAMS.buttons[i].Button(this));
2250			}
2251		}
2252	}
2253
2254	return result;
2255};
2256
2257BX.CDialog.prototype.setAutosave = function () {
2258	if (!this.bSetAutosaveDelay)
2259	{
2260		this.bSetAutosaveDelay = true;
2261		setTimeout(BX.proxy(this.setAutosave, this), 10);
2262	}
2263};
2264
2265BX.CDialog.prototype.SetTitle = function(title)
2266{
2267	this.PARAMS.title = title;
2268	BX.cleanNode(this.PARTS.TITLE_CONTAINER).appendChild(document.createTextNode(this.PARAMS.title));
2269};
2270
2271BX.CDialog.prototype.SetHead = function(head)
2272{
2273	this.PARAMS.head = BX.util.trim(head);
2274	this.PARTS.HEAD.innerHTML = this.PARAMS.head || "&nbsp;";
2275	this.PARTS.HEAD.style.display = this.PARAMS.head ? 'block' : 'none';
2276	this.adjustSize();
2277};
2278
2279BX.CDialog.prototype.Notify = function(note, bError, html)
2280{
2281	if (!this.PARTS.NOTIFY)
2282	{
2283		this.PARTS.NOTIFY = this.DIV.insertBefore(BX.create('DIV', {
2284			props: {className: 'adm-warning-block'},
2285			children: [
2286				BX.create('SPAN', {
2287					props: {className: 'adm-warning-text'}
2288				}),
2289				BX.create('SPAN', {
2290					props: {className: 'adm-warning-icon'}
2291				}),
2292				BX.create('SPAN', {
2293					props: {className: 'adm-warning-close'},
2294					events: {click: BX.proxy(this.hideNotify, this)}
2295				})
2296			]
2297		}), this.DIV.firstChild);
2298	}
2299
2300	if (bError)
2301		BX.addClass(this.PARTS.NOTIFY, 'adm-warning-block-red');
2302	else
2303		BX.removeClass(this.PARTS.NOTIFY, 'adm-warning-block-red');
2304
2305	if(html !== true)
2306	{
2307		note = BX.util.htmlspecialchars(note);
2308	}
2309
2310	this.PARTS.NOTIFY.firstChild.innerHTML = note || '&nbsp;';
2311	this.PARTS.NOTIFY.firstChild.style.width = (this.PARAMS.width-50) + 'px';
2312	BX.removeClass(this.PARTS.NOTIFY, 'adm-warning-animate');
2313};
2314
2315BX.CDialog.prototype.hideNotify = function()
2316{
2317	BX.addClass(this.PARTS.NOTIFY, 'adm-warning-animate');
2318};
2319
2320BX.CDialog.prototype.__adjustHeadToIcon = function()
2321{
2322	if (!this.PARTS.HEAD.offsetHeight)
2323	{
2324		setTimeout(BX.delegate(this.__adjustHeadToIcon, this), 50);
2325	}
2326	else
2327	{
2328		if (this.icon_image && this.icon_image.height && this.icon_image.height > this.PARTS.HEAD.offsetHeight - 5)
2329		{
2330			this.PARTS.HEAD.style.height = this.icon_image.height + 5 + 'px';
2331			this.adjustSize();
2332		}
2333
2334		this.icon_image.onload = null;
2335		this.icon_image = null;
2336	}
2337};
2338
2339BX.CDialog.prototype.SetIcon = function(icon_class)
2340{
2341	if (this.PARAMS.icon != icon_class)
2342	{
2343		if (this.PARAMS.icon)
2344			BX.removeClass(this.PARTS.HEAD, this.PARAMS.icon);
2345
2346		this.PARAMS.icon = icon_class;
2347
2348		if (this.PARAMS.icon)
2349		{
2350			BX.addClass(this.PARTS.HEAD, this.PARAMS.icon);
2351
2352			var icon_file = (BX.style(this.PARTS.HEAD, 'background-image') || BX.style(this.PARTS.HEAD, 'backgroundImage'));
2353			if (BX.type.isNotEmptyString(icon_file) && icon_file != 'none')
2354			{
2355				var match = icon_file.match(new RegExp('url\\s*\\(\\s*(\'|"|)(.+?)(\\1)\\s*\\)'));
2356				if(match)
2357				{
2358					icon_file = match[2];
2359					if (BX.type.isNotEmptyString(icon_file))
2360					{
2361						this.icon_image = new Image();
2362						this.icon_image.onload = BX.delegate(this.__adjustHeadToIcon, this);
2363						this.icon_image.src = icon_file;
2364					}
2365				}
2366			}
2367		}
2368	}
2369	this.adjustSize();
2370};
2371
2372BX.CDialog.prototype.SetIconFile = function(icon_file)
2373{
2374	this.icon_image = new Image();
2375	this.icon_image.onload = BX.delegate(this.__adjustHeadToIcon, this);
2376	this.icon_image.src = icon_file;
2377
2378	BX.adjust(this.PARTS.HEAD, {style: {backgroundImage: 'url(' + icon_file + ')', backgroundPosition: 'right 9px'/*'99% center'*/}});
2379	this.adjustSize();
2380};
2381
2382/*
2383BUTTON: {
2384	title: 'title',
2385	'action': function executed in window object context
2386}
2387BX.CDialog.btnSave || BX.CDialog.btnCancel - standard buttons
2388*/
2389
2390BX.CDialog.prototype.SetButtons = function(a)
2391{
2392	if (BX.type.isString(a))
2393	{
2394		if (a.length > 0)
2395		{
2396			this.PARTS.BUTTONS_CONTAINER.innerHTML += a;
2397
2398			var btns = this.PARTS.BUTTONS_CONTAINER.getElementsByTagName('INPUT');
2399			if (btns.length > 0)
2400			{
2401				this.PARAMS.buttons = [];
2402				for (var i = 0; i < btns.length; i++)
2403				{
2404					this.PARAMS.buttons.push(new BX.CWindowButton({btn: btns[i], parentWindow: this}));
2405				}
2406			}
2407		}
2408	}
2409	else
2410	{
2411		this.PARAMS.buttons = a;
2412		BX.adjust(this.PARTS.BUTTONS_CONTAINER, {
2413			children: this.ShowButtons()
2414		});
2415	}
2416	this.adjustSize();
2417};
2418
2419BX.CDialog.prototype.ClearButtons = function()
2420{
2421	BX.cleanNode(this.PARTS.BUTTONS_CONTAINER);
2422	this.adjustSize();
2423};
2424
2425BX.CDialog.prototype.SetContent = function(html)
2426{
2427	this.__form = null;
2428
2429	if (BX.type.isElementNode(html))
2430	{
2431		if (html.parentNode)
2432			html.parentNode.removeChild(html);
2433	}
2434	else if (BX.type.isString(html))
2435	{
2436		html = BX.create('DIV', {html: html});
2437	}
2438
2439	this.PARAMS.content = html;
2440	BX.cleanNode(this.PARTS.CONTENT_DATA);
2441
2442	BX.adjust(this.PARTS.CONTENT_DATA, {
2443		children: [
2444			this.PARTS.HEAD,
2445			BX.create('DIV', {
2446				props: {
2447					className: 'bx-core-adm-dialog-content-wrap-inner'
2448				},
2449				children: [this.PARAMS.content]
2450			})
2451		]
2452	});
2453
2454	if (this.PARAMS.content_url && this.GetForm())
2455	{
2456		this.__form.submitbtn = this.__form.appendChild(BX.create('INPUT', {props:{type:'submit'},style:{display:'none'}}));
2457		this.__form.onsubmit = BX.delegate(this.__submit, this);
2458	}
2459};
2460
2461BX.CDialog.prototype.__submit = function(e)
2462{
2463	for (var i=0,len=this.PARAMS.buttons.length; i<len; i++)
2464	{
2465		if (
2466			this.PARAMS.buttons[i]
2467			&& (
2468				this.PARAMS.buttons[i].name && /save|apply/i.test(this.PARAMS.buttons[i].name)
2469				||
2470				this.PARAMS.buttons[i].btn && this.PARAMS.buttons[i].btn.name && /save|apply/i.test(this.PARAMS.buttons[i].btn.name)
2471			)
2472		)
2473		{
2474			this.PARAMS.buttons[i].emulate();
2475			break;
2476		}
2477	}
2478
2479	return BX.PreventDefault(e);
2480};
2481
2482BX.CDialog.prototype.SwapContent = function(cont)
2483{
2484	cont = BX(cont);
2485
2486	BX.cleanNode(this.PARTS.CONTENT_DATA);
2487	cont.parentNode.removeChild(cont);
2488	this.PARTS.CONTENT_DATA.appendChild(cont);
2489	cont.style.display = 'block';
2490	this.SetContent(cont.innerHTML);
2491};
2492
2493// this method deprecated
2494BX.CDialog.prototype.adjustSize = function()
2495{
2496};
2497
2498// this method deprecated
2499BX.CDialog.prototype.__adjustSize = function()
2500{
2501};
2502
2503BX.CDialog.prototype.adjustSizeEx = function()
2504{
2505	BX.defer(this.__adjustSizeEx, this)();
2506};
2507
2508BX.CDialog.prototype.__adjustSizeEx = function()
2509{
2510	var ob = this.PARTS.CONTENT_DATA.firstChild,
2511		new_height = 0,
2512		marginTop,
2513		marginBottom;
2514
2515	while (ob)
2516	{
2517		if (BX.type.isElementNode(ob))
2518		{
2519			marginTop = parseInt(BX.style(ob, 'margin-top'), 10);
2520			if (isNaN(marginTop))
2521				marginTop = 0;
2522			marginBottom = parseInt(BX.style(ob, 'margin-bottom'), 10);
2523			if (isNaN(marginBottom))
2524				marginBottom = 0;
2525			new_height += ob.offsetHeight + marginTop + marginBottom;
2526		}
2527		ob = BX.nextSibling(ob);
2528	}
2529
2530	if (new_height)
2531		this.PARTS.CONTENT_DATA.style.height = new_height + 'px';
2532};
2533
2534
2535BX.CDialog.prototype.__onResizeFinished = function()
2536{
2537	BX.WindowManager.saveWindowSize(
2538		this.PARAMS.resize_id || this.PARAMS.content_url, {height: parseInt(this.PARTS.CONTENT_DATA.style.height), width: parseInt(this.PARTS.CONTENT_DATA.style.width)}
2539	);
2540};
2541
2542BX.CDialog.prototype.Show = function(bNotRegister)
2543{
2544	if ((!this.PARAMS.content) && this.PARAMS.content_url && BX.ajax && !bNotRegister)
2545	{
2546		var wait = BX.showWait();
2547
2548		BX.WindowManager.currently_loaded = this;
2549
2550		this.CreateOverlay();
2551		this.OVERLAY.style.display = 'block';
2552		this.OVERLAY.className = 'bx-core-dialog-overlay';
2553
2554		var post_data = '', method = 'GET';
2555		if (this.PARAMS.content_post)
2556		{
2557			post_data = this.PARAMS.content_post;
2558			method = 'POST';
2559		}
2560
2561		var url = this.PARAMS.content_url
2562			+ (this.PARAMS.content_url.indexOf('?')<0?'?':'&')+'bxsender=' + this._sender;
2563
2564		this.auth_callback = BX.delegate(function(){
2565			this.PARAMS.content = '';
2566			this.hideNotify();
2567			this.Show();
2568		}, this);
2569
2570		BX.ajax({
2571			method: method,
2572			dataType: 'html',
2573			url: url,
2574			data: post_data,
2575			skipAuthCheck: true,
2576			onsuccess: BX.delegate(function(data) {
2577				BX.closeWait(null, wait);
2578
2579				this.SetContent(data || '&nbsp;');
2580				this.Show();
2581			}, this)
2582		});
2583	}
2584	else
2585	{
2586		BX.WindowManager.currently_loaded = null;
2587		BX.CDialog.superclass.Show.apply(this, arguments);
2588
2589		this.adjustPos();
2590
2591		this.OVERLAY.className = 'bx-core-dialog-overlay';
2592
2593		this.__adjustSize();
2594
2595		BX.removeCustomEvent(this, 'onWindowResize', BX.proxy(this.__adjustSize, this));
2596		BX.addCustomEvent(this, 'onWindowResize', BX.proxy(this.__adjustSize, this));
2597
2598		if (this.PARAMS.resizable && (this.PARAMS.content_url || this.PARAMS.resize_id))
2599		{
2600			BX.removeCustomEvent(this, 'onWindowResizeFinished', BX.proxy(this.__onResizeFinished, this));
2601			BX.addCustomEvent(this, 'onWindowResizeFinished', BX.proxy(this.__onResizeFinished, this));
2602		}
2603	}
2604};
2605
2606BX.CDialog.prototype.GetInnerPos = function()
2607{
2608	return {'width': parseInt(this.PARTS.CONTENT_DATA.style.width), 'height': parseInt(this.PARTS.CONTENT_DATA.style.height)};
2609};
2610
2611BX.CDialog.prototype.adjustPos = function()
2612{
2613	if (!this.bExpanded)
2614	{
2615		var currentWindow = window;
2616		var topWindow = BX.PageObject.getRootWindow();
2617		if (topWindow.BX.SidePanel && topWindow.BX.SidePanel.Instance && topWindow.BX.SidePanel.Instance.getTopSlider())
2618		{
2619			currentWindow = topWindow.BX.SidePanel.Instance.getTopSlider().getWindow();
2620		}
2621		var windowSize = currentWindow.BX.GetWindowInnerSize();
2622		var windowScroll = currentWindow.BX.GetWindowScrollPos();
2623
2624		var style = {
2625			left: parseInt(windowScroll.scrollLeft + windowSize.innerWidth / 2 - parseInt(this.DIV.offsetWidth) / 2) + 'px',
2626			top: Math.max(parseInt(windowScroll.scrollTop + windowSize.innerHe
2626ight / 2 - parseInt(this.DIV.offsetHeight) / 2), 0) + 'px'
2627		};
2628
2629		BX.adjust(this.DIV, {
2630			style: style
2631		});
2632	}
2633};
2634
2635BX.CDialog.prototype.GetContent = function () {return this.PARTS.CONTENT_DATA};
2636
2637BX.CDialog.prototype.btnSave = BX.CDialog.btnSave = {
2638	title: BX.message('JS_CORE_WINDOW_SAVE'),
2639	id: 'savebtn',
2640	name: 'savebtn',
2641	className: BX.browser.IsIE() && BX.browser.IsDoctype() && !BX.browser.IsIE10() ? '' : 'adm-btn-save',
2642	action: function () {
2643		this.disableUntilError();
2644		this.parentWindow.PostParameters();
2645	}
2646};
2647
2648BX.CDialog.prototype.btnCancel = BX.CDialog.btnCancel = {
2649	title: BX.message('JS_CORE_WINDOW_CANCEL'),
2650	id: 'cancel',
2651	name: 'cancel',
2652	action: function () {
2653		this.parentWindow.Close();
2654	}
2655};
2656
2657BX.CDialog.prototype.btnClose = BX.CDialog.btnClose = {
2658	title: BX.message('JS_CORE_WINDOW_CLOSE'),
2659	id: 'close',
2660	name: 'close',
2661	action: function () {
2662		this.parentWindow.Close();
2663	}
2664};
2665
2666/* special child for admin forms loaded into public page */
2667BX.CAdminDialog = function(arParams)
2668{
2669	BX.CAdminDialog.superclass.constructor.apply(this, arguments);
2670
2671	this._sender = 'core_window_cadmindialog';
2672
2673	BX.addClass(this.DIV, 'bx-core-adm-admin-dialog');
2674
2675	this.PARTS.CONTENT.insertBefore(this.PARTS.HEAD, this.PARTS.CONTENT.firstChild);
2676	this.PARTS.HEAD.className = 'bx-core-adm-dialog-tabs';
2677};
2678BX.extend(BX.CAdminDialog, BX.CDialog);
2679
2680BX.CAdminDialog.prototype.SetHead = function()
2681{
2682	BX.CAdminDialog.superclass.SetHead.apply(this, arguments);
2683
2684	if (this.PARTS.HEAD.firstChild && BX.type.isElementNode(this.PARTS.HEAD.firstChild))
2685	{
2686		var ob = this.PARTS.HEAD.firstChild, new_width = 0, marginLeft = 0, marginRight = 0;
2687
2688		while (ob)
2689		{
2690			if (BX.type.isElementNode(ob))
2691			{
2692				marginLeft = parseInt(BX.style(ob, 'margin-left'), 10);
2693				if (isNaN(marginLeft))
2694					marginLeft = 0;
2695				marginRight = parseInt(BX.style(ob, 'margin-right'), 10);
2696				if (isNaN(marginRight))
2697					marginRight = 0;
2698				new_width += ob.offsetWidth + marginLeft + marginRight;
2699			}
2700			ob = BX.nextSibling(ob);
2701		}
2702
2703		this.SETTINGS.min_width = Math.max(new_width, this.SETTINGS.min_width) - 2;
2704		if (this.PARAMS.width < this.SETTINGS.min_width)
2705		{
2706			BX.adjust(this.PARTS.CONTENT_DATA, {
2707				style: {
2708					width: this.SETTINGS.min_width + 'px'
2709				}
2710			});
2711		}
2712	}
2713};
2714
2715BX.CAdminDialog.prototype.SetContent = function(html)
2716{
2717	this.__form = null;
2718
2719	if (BX.type.isElementNode(html))
2720	{
2721		if (html.parentNode)
2722			html.parentNode.removeChild(html);
2723	}
2724
2725	this.PARAMS.content = html;
2726	BX.cleanNode(this.PARTS.CONTENT_DATA);
2727
2728	BX.adjust(this.PARTS.CONTENT_DATA, {
2729		children: [
2730			this.PARAMS.content || '&nbsp;'
2731		]
2732	});
2733
2734	if (this.PARAMS.content_url && this.GetForm())
2735	{
2736		this.__form.appendChild(BX.create('INPUT', {props:{type:'submit'},style:{display:'none'}}));
2737		this.__form.onsubmit = BX.delegate(this.__submit, this);
2738	}
2739};
2740
2741BX.CAdminDialog.prototype.__expandGetSize = function()
2742{
2743	var res = BX.CAdminDialog.superclass.__expandGetSize.apply(this, arguments);
2744
2745	res.width -= parseInt(BX.style(this.PARTS.CONTENT_DATA, 'padding-right')) + parseInt(BX.style(this.PARTS.CONTENT_DATA, 'padding-left'));
2746	res.height -= parseInt(BX.style(this.PARTS.CONTENT_DATA, 'padding-top')) + parseInt(BX.style(this.PARTS.CONTENT_DATA, 'padding-bottom'));
2747
2748	res.height -= this.PARTS.HEAD.offsetHeight;
2749
2750	return res;
2751};
2752
2753BX.CAdminDialog.prototype.Submit = function()
2754{
2755	var FORM = this.GetForm();
2756	if (FORM && !FORM['bxpublic'] && !/bxpublic=/.test(FORM.action))
2757	{
2758		FORM.appendChild(BX.create('INPUT', {
2759			props: {
2760				type: 'hidden',
2761				name: 'bxpublic',
2762				value: 'Y'
2763			}
2764		}));
2765	}
2766
2767	return BX.CAdminDialog.superclass.Submit.apply(this, arguments);
2768};
2769
2770BX.CAdminDialog.prototype.btnSave = BX.CAdminDialog.btnSave = {
2771	title: BX.message('JS_CORE_WINDOW_SAVE'),
2772	id: 'savebtn',
2773	name: 'savebtn',
2774	className: 'adm-btn-save',
2775	action: function () {
2776		this.disableUntilError();
2777		this.parentWindow.Submit();
2778	}
2779};
2780
2781BX.CAdminDialog.btnCancel = BX.CAdminDialog.superclass.btnCancel;
2782BX.CAdminDialog.btnClose = BX.CAdminDialog.superclass.btnClose;
2783
2784BX.CDebugDialog = function(arParams)
2785{
2786	BX.CDebugDialog.superclass.constructor.apply(this, arguments);
2787};
2788BX.extend(BX.CDebugDialog, BX.CDialog);
2789
2790BX.CDebugDialog.prototype.ShowDetails = function(div_id)
2791{
2792	var div = BX(div_id);
2793	if (div)
2794	{
2795		if (this.div_detail_current)
2796			this.div_detail_current.style.display = 'none';
2797
2798		div.style.display = 'block';
2799		this.div_detail_current = div;
2800	}
2801};
2802
2803BX.CDebugDialog.prototype.SetContent = function(html)
2804{
2805	if (!html)
2806		return;
2807
2808	var arHtml = html.split('#DIVIDER#');
2809	if (arHtml.length > 1)
2810	{
2811		this.PARAMS.content = arHtml[1];
2812
2813		this.PARTS.CONTENT_DATA.style.overflow = 'hidden';
2814
2815		BX.CDebugDialog.superclass.SetContent.apply(this, [arHtml[1]]);
2816
2817		this.PARTS.CONTENT_INNER = this.PARTS.CONTENT_DATA.firstChild.nextSibling;
2818		this.PARTS.CONTENT_TOP = this.PARTS.CONTENT_DATA.insertBefore(BX.create('DIV', {
2819			props: {
2820				className: 'bx-debug-content-top'
2821			},
2822			html: arHtml[0]
2823		}), this.PARTS.CONTENT_INNER);
2824		this.PARTS.CONTENT_INNER.style.overflow = 'auto';
2825	}
2826	else
2827	{
2828		BX.CDebugDialog.superclass.SetContent.apply(this, arguments);
2829	}
2830};
2831
2832BX.CDebugDialog.prototype.__adjustSize = function()
2833{
2834	BX.CDebugDialog.superclass.__adjustSize.apply(this, arguments);
2835
2836	if (this.PARTS.CONTENT_TOP)
2837	{
2838		var new_height = this.PARTS.CONTENT_DATA.offsetHeight - this.PARTS.HEAD.offsetHeight - this.PARTS.CONTENT_TOP.offsetHeight - 38;
2839
2840		if (new_height > 0)
2841		{
2842			this.PARTS.CONTENT_INNER.style.height = new_height + 'px';
2843		}
2844	}
2845};
2846
2847
2848/* class for dialog window with editors */
2849
2850BX.CEditorDialog = function(arParams)
2851{
2852	BX.CEditorDialog.superclass.constructor.apply(this, arguments);
2853
2854	BX.removeClass(this.PARTS.CONTENT, 'bx-core-adm-dialog-content-wrap');
2855	BX.removeClass(this.PARTS.CONTENT_DATA, 'bx-core-adm-dialog-content');
2856
2857	BX.removeClass(this.PARTS.CONTENT_DATA.lastChild, 'bx-core-adm-dialog-content-wrap-inner');
2858	BX.removeClass(this.PARTS.BUTTONS_CONTAINER, 'bx-core-adm-dialog-buttons');
2859
2860	BX.addClass(this.PARTS.CONTENT, 'bx-core-editor-dialog-content-wrap');
2861	BX.addClass(this.PARTS.CONTENT_DATA, 'bx-core-editor-dialog-content');
2862	BX.addClass(this.PARTS.BUTTONS_CONTAINER, 'bx-core-editor-dialog-buttons');
2863};
2864BX.extend(BX.CEditorDialog, BX.CDialog);
2865
2866BX.CEditorDialog.prototype.SetContent  = function()
2867{
2868	BX.CEditorDialog.superclass.SetContent.apply(this, arguments);
2869
2870	BX.removeClass(this.PARTS.CONTENT_DATA.lastChild, 'bx-core-adm-dialog-content-wrap-inner');
2871};
2872
2873/* class for wizards in admin section */
2874BX.CWizardDialog = function(arParams)
2875{
2876	BX.CWizardDialog.superclass.constructor.apply(this, arguments);
2877
2878	BX.removeClass(this.PARTS.CONTENT, 'bx-core-adm-dialog-content-wrap');
2879	BX.removeClass(this.PARTS.CONTENT_DATA, 'bx-core-adm-dialog-content');
2880	BX.removeClass(this.PARTS.CONTENT_DATA.lastChild, 'bx-core-adm-dialog-content-wrap-inner');
2881	BX.removeClass(this.PARTS.BUTTONS_CONTAINER, 'bx-core-adm-dialog-buttons');
2882
2883	BX.addClass(this.PARTS.CONTENT, 'bx-core-wizard-dialog-content-wrap');
2884};
2885
2886BX.extend(BX.CWizardDialog, BX.CDialog);
2887
2888/* class for auth dialog */
2889BX.CAuthDialog = function(arParams)
2890{
2891	arParams.resizable = false;
2892	arParams.width = 350;
2893	arParams.height = 200;
2894
2895	arParams.buttons = [this.btnSave];
2896
2897	BX.CAuthDialog.superclass.constructor.apply(this, arguments);
2898	this._sender = 'core_window_cauthdialog';
2899
2900	BX.addClass(this.DIV, 'bx-core-auth-dialog');
2901
2902	BX.AUTHAGENT = this;
2903};
2904BX.extend(BX.CAuthDialog, BX.CDialog);
2905
2906BX.CAuthDialog.prototype.btnSave = BX.CAuthDialog.btnSave = {
2907	title: BX.message('JS_CORE_WINDOW_AUTH'),
2908	id: 'savebtn',
2909	name: 'savebtn',
2910	className: 'adm-btn-save',
2911	action: function () {
2912		this.disableUntilError();
2913		this.parentWindow.Submit('', this.parentWindow.PARAMS.content_url);
2914	}
2915};
2916
2917BX.CAuthDialog.prototype.SetError = function(error)
2918{
2919	BX.closeWait();
2920
2921	if (!!error)
2922		this.ShowError(error.MESSAGE || error);
2923};
2924
2925BX.CAuthDialog.prototype.setAuthResult = function(result)
2926{
2927	BX.closeWait();
2928
2929	if (result === false)
2930	{
2931		this.Close();
2932		if (this.PARAMS.callback)
2933			this.PARAMS.callback();
2934	}
2935	else
2936	{
2937		this.SetError(result);
2938	}
2939};
2940
2941/* MENU CLASSES */
2942
2943BX.CWindowFloat = function(node)
2944{
2945	BX.CWindowFloat.superclass.constructor.apply(this, [node, 'float']);
2946
2947	this.SETTINGS.resizable = false;
2948};
2949BX.extend(BX.CWindowFloat, BX.CWindow);
2950
2951BX.CWindowFloat.prototype.adjustPos = function()
2952{
2953	if (this.PARAMS.parent)
2954		this.adjustToNode();
2955	else if (this.PARAMS.x && this.PARAMS.y)
2956		this.adjustToPos([this.PARAMS.x, this.PARAMS.y]);
2957};
2958
2959BX.CWindowFloat.prototype.adjustToPos = function(pos)
2960{
2961	this.DIV.style.left = parseInt(pos[0]) + 'px';
2962	this.DIV.style.top = parseInt(pos[1]) + 'px';
2963};
2964
2965BX.CWindowFloat.prototype.adjustToNodeGetPos = function()
2966{
2967	return BX.pos(this.PARAMS.parent);
2968};
2969
2970BX.CWindowFloat.prototype.adjustToNode = function(el)
2971{
2972	el = el || this.PARAMS.parent;
2973
2974	this.PARAMS.parent = BX(el);
2975
2976	if (this.PARAMS.parent)
2977	{
2978		var pos = this.adjustToNodeGetPos();
2979
2980		this.DIV.style.top = pos.top + 'px';//(pos.top - 26) + 'px';
2981		this.DIV.style.left = pos.left + 'px';
2982
2983		this.PARAMS.parent.OPENER = this;
2984	}
2985};
2986
2987BX.CWindowFloat.prototype.Show = function()
2988{
2989	this.adjustToPos([-1000, -1000]);
2990	BX.CWindowFloat.superclass.Show.apply(this, arguments);
2991	this.adjustPos();
2992};
2993
2994/* menu opener class */
2995/*
2996{
2997	DOMNode DIV,
2998	BX.CMenu or Array MENU,
2999	TYPE = 'hover' | 'click',
3000	TIMEOUT: 1000
3001	ATTACH_MODE: 'top' | 'right'
3002	ACTIVE_CLASS: className for opener element when menu is opened
3003}
3004*/
3005BX.COpener = function(arParams)
3006{
3007	this.PARAMS = arParams || {};
3008
3009	this.MENU = arParams.MENU || [];
3010
3011	this.DIV = arParams.DIV;
3012	this.ATTACH = arParams.ATTACH || arParams.DIV;
3013	this.ATTACH_MODE = arParams.ATTACH_MODE || 'bottom';
3014
3015	this.ACTIVE_CLASS = arParams.ACTIVE_CLASS || '';
3016	this.PUBLIC_FRAME = arParams.PUBLIC_FRAME || 0;
3017	this.LEVEL = arParams.LEVEL || 0;
3018
3019	this.CLOSE_ON_CLICK = typeof arParams.CLOSE_ON_CLICK != 'undefined' ? !!arParams.CLOSE_ON_CLICK : true;
3020	this.ADJUST_ON_CLICK = typeof arParams.ADJUST_ON_CLICK != 'undefined' ? !!arParams.ADJUST_ON_CLICK : true;
3021
3022	this.TYPE = this.PARAMS.TYPE == 'hover' ? 'hover' : 'click';
3023
3024	this._openTimeout = null;
3025
3026	if (this.PARAMS.TYPE == 'hover' && arParams.TIMEOUT !== 0)
3027		this.TIMEOUT = arParams.TIMEOUT || 1000;
3028	else
3029		this.TIMEOUT = 0;
3030
3031	this.bMenuInit = false;
3032
3033	if (!!this.PARAMS.MENU_URL)
3034	{
3035		this.bMenuLoaded = false;
3036		this.bMenuLoading = false;
3037
3038		this.MENU = [{
3039			TEXT: BX.message('JS_CORE_LOADING'),
3040			CLOSE_ON_CLICK: false
3041		}];
3042
3043		if (this.PARAMS.MENU_PRELOAD)
3044		{
3045			BX.defer(this.Load, this)();
3046		}
3047	}
3048
3049	BX.ready(BX.defer(this.Init, this));
3050};
3051
3052BX.COpener.prototype.Init = function()
3053{
3054	this.DIV = BX(this.DIV);
3055
3056	switch (this.TYPE)
3057	{
3058		case 'hover':
3059			BX.bind(this.DIV, 'mouseover', BX.proxy(this.Open, this));
3060			BX.bind(this.DIV, 'click', BX.proxy(this.Toggle, this));
3061		break;
3062
3063		case 'click':
3064			BX.bind(this.DIV, 'click', BX.proxy(this.Toggle, this));
3065		break;
3066	}
3067
3068	//BX.bind(window, 'scroll', BX.delegate(this.__close_immediately, this));
3069
3070	//this.bMenuInit = false;
3071};
3072
3073BX.COpener.prototype.Load = function()
3074{
3075	if (this.PARAMS.MENU_URL && !this.bMenuLoaded)
3076	{
3077		if (!this.bMenuLoading)
3078		{
3079			var url = this.PARAMS.MENU_URL;
3080			if (url.indexOf('sessid=') <= 0)
3081				url += (url.indexOf('?') > 0 ? '&' : '?') + 'sessid=' + BX.bitrix_sessid();
3082
3083			this.bMenuLoading = true;
3084			BX.ajax.loadJSON(url, BX.proxy(this.SetMenu, this), BX.proxy(this.LoadFailed, this));
3085		}
3086	}
3087};
3088
3089BX.COpener.prototype.SetMenu = function(menu)
3090{
3091	this.bMenuLoaded = true;
3092	this.bMenuLoading = false;
3093	if (this.bMenuInit)
3094	{
3095		this.MENU.setItems(menu);
3096	}
3097	else
3098	{
3099		this.MENU = menu;
3100	}
3101};
3102
3103BX.COpener.prototype.LoadFailed = function(type, error)
3104{
3105	this.bMenuLoading = false;
3106	this.SetMenu([{
3107		TEXT: BX.message('JS_CORE_NO_DATA'),
3108		CLOSE_ON_CLICK: true
3109	}]);
3110	BX.debug(arguments);
3111};
3112
3113BX.COpener.prototype.checkAdminMenu = function()
3114{
3115	if (document.documentElement.id == 'bx-admin-prefix')
3116		return true;
3117
3118	return !!BX.findParent(this.DIV, {property: {id: 'bx-admin-prefix'}});
3119};
3120
3121BX.COpener.prototype.Toggle = function(e)
3122{
3123	this.__clear_timeout();
3124
3125	if (!this.bMenuInit || !this.MENU.visible())
3126	{
3127		var t = this.TIMEOUT;
3128		this.TIMEOUT = 0;
3129		this.Open(e);
3130		this.TIMEOUT = t;
3131	}
3132	else
3133	{
3134		this.MENU.Close();
3135	}
3136
3137	return !!(e||window.event) && BX.PreventDefault(e);
3138};
3139
3140BX.COpener.prototype.GetMenu = function()
3141{
3142	if (!this.bMenuInit)
3143	{
3144		if (BX.type.isArray(this.MENU))
3145		{
3146			this.MENU = new BX.CMenu({
3147				ITEMS: this.MENU,
3148				ATTACH_MODE: this.ATTACH_MODE,
3149				SET_ID: this.checkAdminMenu() ? 'bx-admin-prefix' : '',
3150				CLOSE_ON_CLICK: !!this.CLOSE_ON_CLICK,
3151				ADJUST_ON_CLICK: !!this.ADJUST_ON_CLICK,
3152				PUBLIC_FRAME: !!this.PUBLIC_FRAME,
3153				LEVEL: this.LEVEL,
3154				parent: BX(this.DIV),
3155				parent_attach: BX(this.ATTACH)
3156			});
3157
3158			if (this.LEVEL > 0)
3159			{
3160				BX.bind(this.MENU.DIV, 'mouseover', BX.proxy(this._on_menu_hover, this));
3161				BX.bind(this.MENU.DIV, 'mouseout', BX.proxy(this._on_menu_hout, this));
3162			}
3163		}
3164
3165		BX.addCustomEvent(this.MENU, 'onMenuOpen', BX.proxy(this.handler_onopen, this));
3166		BX.addCustomEvent(this.MENU, 'onMenuClose', BX.proxy(this.handler_onclose, this));
3167
3168		BX.addCustomEvent('onMenuItemHover', BX.proxy(this.handler_onover, this));
3169
3170		this.bMenuInit = true;
3171	}
3172
3173	return this.MENU;
3174};
3175
3176BX.COpener.prototype.Open = function()
3177{
3178	this.GetMenu();
3179
3180	this.bOpen = true;
3181
3182	this.__clear_timeout();
3183
3184	if (this.TIMEOUT > 0)
3185	{
3186		BX.bind(this.DIV, 'mouseout', BX.proxy(this.__clear_timeout, this));
3187		this._openTimeout = setTimeout(BX.proxy(this.__open, this), this.TIMEOUT);
3188	}
3189	else
3190	{
3191		this.__open();
3192	}
3193
3194	if (!!this.PARAMS.MENU_URL && !this.bMenuLoaded)
3195	{
3196		this._loadTimeout = setTimeout(BX.proxy(this.Load, this), parseInt(this.TIMEOUT/2));
3197	}
3198
3199	return true;
3200};
3201
3202BX.COpener.prototype.__clear_timeout = function()
3203{
3204	if (!!this._openTimeout)
3205		clearTimeout(this._openTimeout);
3206	if (!!this._loadTimeout)
3207		clearTimeout(this._loadTimeout);
3208
3209	BX.unbind(this.DIV, 'mouseout', BX.proxy(this.__clear_timeout, this));
3210};
3211
3212BX.COpener.prototype._on_menu_hover = function()
3213{
3214	this.bMenuHover = true;
3215
3216	this.__clear_timeout();
3217
3218	if (this.ACTIVE_CLASS)
3219		BX.addClass(this.DIV, this.ACTIVE_CLASS);
3220
3221};
3222
3223BX.COpener.prototype._on_menu_hout = function()
3224{
3225	this.bMenuHover = false;
3226};
3227
3228BX.COpener.prototype.handler_onover = function(level, opener)
3229{
3230	if (this.bMenuHover)
3231		return;
3232
3233	if (opener != this && level == this.LEVEL-1 && this.ACTIVE_CLASS)
3234	{
3235		BX.removeClass(this.DIV, this.ACTIVE_CLASS);
3236	}
3237
3238	if (this.bMenuInit && level <= this.LEVEL-1 && this.MENU.visible())
3239	{
3240		if (opener != this)
3241		{
3242			this.__clear_timeout();
3243			this._openTimeout = setTimeout(BX.proxy(this.Close, this), this.TIMEOUT);
3244		}
3245	}
3246};
3247
3248BX.COpener.prototype.handler_onopen = function()
3249{
3250	this.bOpen = true;
3251
3252	if (this.ACTIVE_CLASS)
3253		BX.addClass(this.DIV, this.ACTIVE_CLASS);
3254
3255	BX.defer(function() {
3256		BX.onCustomEvent(this, 'onOpenerMenuOpen');
3257	}, this)();
3258};
3259
3260BX.COpener.prototype.handler_onclose = function()
3261{
3262	this.bOpen = false;
3263	BX.onCustomEvent(this, 'onOpenerMenuClose');
3264
3265	if (this.ACTIVE_CLASS)
3266		BX.removeClass(this.DIV, this.ACTIVE_CLASS);
3267};
3268
3269BX.COpener.prototype.Close = function()
3270{
3271	if (!this.bMenuInit)
3272		return;
3273
3274	if (!!this._openTimeout)
3275		clearTimeout(this._openTimeout);
3276
3277	this.bOpen = false;
3278
3279	this.__close();
3280};
3281
3282BX.COpener.prototype.__open = function()
3283{
3284	this.__clear_timeout();
3285
3286	if (this.bMenuInit && this.bOpen && !this.MENU.visible())
3287		this.MENU.Show();
3288};
3289
3290BX.COpener.prototype.__close = function()
3291{
3292	if (this.bMenuInit && !this.bOpen && this.MENU.visible())
3293		this.MENU.Hide();
3294};
3295
3296BX.COpener.prototype.__close_immediately = function() {
3297	this.bOpen = false; this.__close();
3298};
3299
3300BX.COpener.prototype.isMenuVisible = function() {
3301	return null != this.MENU.visible && this.MENU.visible()
3302};
3303
3304/* common menu class */
3305
3306BX.CMenu = function(arParams)
3307{
3308	BX.CMenu.superclass.constructor.apply(this);
3309
3310	this.DIV.style.width = 'auto';//this.DIV.firstChild.offsetWidth + 'px';
3311	this.DIV.style.height = 'auto';//this.DIV.firstChild.offsetHeight + 'px';
3312
3313	this.PARAMS = arParams || {};
3314	this.PARTS = {};
3315
3316	this.PARAMS.ATTACH_MODE = this.PARAMS.ATTACH_MODE || 'bottom';
3317	this.PARAMS.CLOSE_ON_CLICK = typeof this.PARAMS.CLOSE_ON_CLICK == 'undefined' ? true : this.PARAMS.CLOSE_ON_CLICK;
3318	this.PARAMS.ADJUST_ON_CLICK = typeof this.PARAMS.ADJUST_ON_CLICK == 'undefined' ? true : this.PARAMS.ADJUST_ON_CLICK;
3319	this.PARAMS.PUBLIC_FRAME = typeof this.PARAMS.PUBLIC_FRAME == 'undefined' ? false : this.PARAMS.PUBLIC_FRAME;
3320	this.PARAMS.LEVEL = this.PARAMS.LEVEL || 0;
3321
3322	this.DIV.className = 'bx-core-popup-menu bx-core-popup-menu-' + this.PARAMS.ATTACH_MODE + ' bx-core-popup-menu-level' + this.PARAMS.LEVEL + (typeof this.PARAMS.ADDITIONAL_CLASS != 'undefined' ? ' ' + this.PARAMS.ADDITIONAL_CLASS : '');
3323	if (!!this.PARAMS.SET_ID)
3324		this.DIV.id = this.PARAMS.SET_ID;
3325
3326	if (this.PARAMS.LEVEL == 0)
3327	{
3328		this.ARROW = this.DIV.appendChild(BX.create('SPAN', {props: {className: 'bx-core-popup-menu-angle'}, style: {left:'15px'}}));
3329	}
3330
3331	if (!!this.PARAMS.CLASS_NAME)
3332		this.DIV.className += ' ' + this.PARAMS.CLASS_NAME;
3333
3334	BX.bind(this.DIV, 'click', BX.eventCancelBubble);
3335
3336	this.ITEMS = [];
3337
3338	this.setItems(this.PARAMS.ITEMS);
3339
3340	BX.addCustomEvent('onMenuOpen', BX.proxy(this._onMenuOpen, this));
3341	BX.addCustomEvent('onMenuItemSelected', BX.proxy(this.Hide, this));
3342};
3343BX.extend(BX.CMenu, BX.CWindowFloat);
3344
3345BX.CMenu.broadcastCloseEvent = function()
3346{
3347	BX.onCustomEvent("onMenuItemSelected");
3348};
3349
3350BX.CMenu._toggleChecked = function()
3351{
3352	BX.toggleClass(this, 'bx-core-popup-menu-item-checked');
3353};
3354
3355BX.CMenu._itemDblClick = function()
3356{
3357	window.location.href = this.href;
3358};
3359
3360BX.CMenu.prototype.toggleArrow = function(v)
3361{
3362	if (!!this.ARROW)
3363	{
3364		if (typeof v == 'undefined')
3365		{
3366			v = this.ARROW.style.visibility == 'hidden';
3367		}
3368
3369		this.ARROW.style.visibility = !!v ? 'visible' : 'hidden';
3370	}
3371};
3372
3373BX.CMenu.prototype.visible = function()
3374{
3375	return this.DIV.style.display !== 'none';
3376};
3377
3378BX.CMenu.prototype._onMenuOpen = function(menu, menu_level)
3379{
3380	if (this.visible())
3381	{
3382		if (menu_level == this.PARAMS.LEVEL && menu != this)
3383		{
3384			this.Hide();
3385		}
3386	}
3387};
3388
3389BX.CMenu.prototype.onUnRegister = function()
3390{
3391	if (!this.visible())
3392		return;
3393
3394	this.Hide();
3395};
3396
3397BX.CMenu.prototype.setItems = function(items)
3398{
3399	this.PARAMS.ITEMS = items;
3400
3401	BX.cleanNode(this.DIV);
3402
3403	if (!!this.ARROW)
3404		this.DIV.appendChild(this.ARROW);
3405
3406	if (this.PARAMS.ITEMS)
3407	{
3408		this.PARAMS.ITEMS = BX.util.array_values(this.PARAMS.ITEMS);
3409
3410		var bIcons = false;
3411		var cnt = 0;
3412		for (var i = 0, len = this.PARAMS.ITEMS.length; i < len; i++)
3413		{
3414			if ((i == 0 || i == len-1) && this.PARAMS.ITEMS[i].SEPARATOR)
3415				continue;
3416
3417			cnt++;
3418
3419			if (!bIcons)
3420				bIcons = !!this.PARAMS.ITEMS[i].GLOBAL_ICON;
3421
3422			this.addItem(this.PARAMS.ITEMS[i], i);
3423		}
3424
3425		// Occam turning in his grave
3426		if (cnt === 1)
3427			BX.addClass(this.DIV, 'bx-core-popup-menu-single-item');
3428		else
3429			BX.removeClass(this.DIV, 'bx-core-popup-menu-single-item');
3430
3431		if (!bIcons)
3432			BX.addClass(this.DIV, 'bx-core-popup-menu-no-icons');
3433		else
3434			BX.removeClass(this.DIV, 'bx-core-popup-menu-no-icons');
3435
3436	}
3437};
3438
3439BX.CMenu.prototype.addItem = function(item)
3440{
3441	this.ITEMS.push(item);
3442
3443	if (item.SEPARATOR)
3444	{
3445		item.NODE = BX.create(
3446			'DIV', {props: {className: 'bx-core-popup-menu-separator'}}
3447		);
3448	}
3449	else
3450	{
3451		var bHasMenu = (!!item.MENU
3452			&& (
3453				(BX.type.isArray(item.MENU) && item.MENU.length > 0)
3454				|| item.MENU instanceof BX.CMenu
3455			) || !!item.MENU_URL
3456		);
3457
3458		if (item.DISABLED)
3459		{
3460			item.CLOSE_ON_CLICK = false;
3461			item.LINK = null;
3462			item.ONCLICK = null;
3463			item.ACTION = null;
3464		}
3465
3466		var attrs = {};
3467		if (!!item.LINK || BX.browser.IsIE() && !BX.browser.IsDoctype())
3468		{
3469			attrs.href = item.LINK || 'javascript:void(0)';
3470		}
3471		if (this.PARAMS.PUBLIC_FRAME)
3472		{
3473			attrs.target = '_top';
3474		}
3475
3476		item.NODE = BX.create(!!item.LINK || BX.browser.IsIE() && !BX.browser.IsDoctype() ? 'A' : 'SPAN', {
3477			props: {
3478				className: 'bx-core-popup-menu-item'
3479					+ (bHasMenu ? ' bx-core-popup-menu-item-opener' : '')
3480					+ (!!item.DEFAULT ? ' bx-core-popup-menu-item-default' : '')
3481					+ (!!item.DISABLED ? ' bx-core-popup-menu-item-disabled' : '')
3482					+ (!!item.CHECKED ? ' bx-core-popup-menu-item-checked' : ''),
3483					title: !!BX.message['MENU_ENABLE_TOOLTIP'] || !!item.SHOW_TITLE ? item.TITLE || '' : '',
3484				BXMENULEVEL: this.PARAMS.LEVEL
3485			},
3486			attrs: attrs,
3487			events: {
3488				mouseover: function()
3489				{
3490					BX.onCustomEvent('onMenuItemHover', [this.BXMENULEVEL, this.OPENER])
3491				}
3492			},
3493			html: '<span class="bx-core-popup-menu-item-icon' + (item.GLOBAL_ICON ? ' '+item.GLOBAL_ICON : '') + '"></span><span class="bx-core-popup-menu-item-text">'+(item.HTML||(item.TEXT? BX.util.htmlspecialchars(item.TEXT) : ''))+'</span>'
3494		});
3495
3496		if (bHasMenu && !item.DISABLED)
3497		{
3498			item.NODE.OPENER = new BX.COpener({
3499				DIV: item.NODE,
3500				ACTIVE_CLASS: 'bx-core-popup-menu-item-opened',
3501				TYPE: 'hover',
3502				MENU: item.MENU,
3503				MENU_URL: item.MENU_URL,
3504				MENU_PRELOAD: !!item.MENU_PRELOAD,
3505				LEVEL: this.PARAMS.LEVEL + 1,
3506				ATTACH_MODE:'right',
3507				TIMEOUT: 500
3508			});
3509		}
3510		else if (this.PARAMS.CLOSE_ON_CLICK && (typeof item.CLOSE_ON_CLICK == 'undefined' || !!item.CLOSE_ON_CLICK))
3511		{
3512			BX.bind(item.NODE, 'click', BX.CMenu.broadcastCloseEvent);
3513		}
3514		else if (this.PARAMS.ADJUST_ON_CLICK && (typeof item.ADJUST_ON_CLICK == 'undefined' || !!item.ADJUST_ON_CLICK))
3515		{
3516			BX.bind(item.NODE, 'click', BX.defer(this.adjustPos, this));
3517		}
3518
3519		if (bHasMenu && !!item.LINK)
3520		{
3521			BX.bind(item.NODE, 'dblclick', BX.CMenu._itemDblClick);
3522		}
3523
3524		if (typeof item.CHECKED != 'undefined')
3525		{
3526			BX.bind(item.NODE, 'click', BX.CMenu._toggleChecked);
3527		}
3528
3529		item.ONCLICK = item.ACTION || item.ONCLICK;
3530		if (!!item.ONCLICK)
3531		{
3532			if (BX.type.isString(item.ONCLICK))
3533			{
3534				item.ONCLICK = new Function("event", item.ONCLICK);
3535			}
3536
3537			BX.bind(item.NODE, 'click', item.ONCLICK);
3538		}
3539	}
3540
3541	this.DIV.appendChild(item.NODE);
3542};
3543
3544BX.CMenu.prototype._documentClickBind = function()
3545{
3546	this._documentClickUnBind();
3547	BX.bind(document, 'click', BX.proxy(this._documentClick, this));
3548};
3549
3550BX.CMenu.prototype._documentClickUnBind = function()
3551{
3552	BX.unbind(document, 'click', BX.proxy(this._documentClick, this));
3553};
3554
3555BX.CMenu.prototype._documentClick = function(e)
3556{
3557	e = e||window.event;
3558	if(!!e && !(BX.getEventButton(e) & BX.MSLEFT))
3559		return;
3560
3561	this.Close();
3562};
3563
3564BX.CMenu.prototype.Show = function()
3565{
3566	BX.onCustomEvent(this, 'onMenuOpen', [this, this.PARAMS.LEVEL]);
3567	BX.CMenu.superclass.Show.apply(this, []);
3568
3569	this.bCloseEventFired = false;
3570
3571	BX.addCustomEvent(this.PARAMS.parent_attach, 'onChangeNodePosition', BX.proxy(this.adjustToNode, this));
3572
3573	(BX.defer(this._documentClickBind, this))();
3574};
3575
3576BX.CMenu.prototype.Close = // we shouldn't 'Close' window - only hide
3577BX.CMenu.prototype.Hide = function()
3578{
3579	if (!this.visible())
3580		return;
3581
3582	BX.removeCustomEvent(this.PARAMS.parent_attach, 'onChangeNodePosition', BX.proxy(this.adjustToNode, this));
3583
3584	this._documentClickUnBind();
3585
3586	if (!this.bCloseEventFired)
3587	{
3588		BX.onCustomEvent(this, 'onMenuClose', [this, this.PARAMS.LEVEL]);
3589		this.bCloseEventFired = true;
3590	}
3591	BX.CMenu.superclass.Hide.apply(this, arguments);
3592
3593
3594//	this.DIV.onclick = null;
3595	//this.PARAMS.parent.onclick = null;
3596};
3597
3598BX.CMenu.prototype.__adjustMenuToNode = function()
3599{
3600	var pos = BX.pos(this.PARAMS.parent_attach),
3601		bFixed = !!BX.findParent(this.PARAMS.parent_attach, BX.is_fixed);
3602
3603	if (bFixed)
3604		this.DIV.style.position = 'fixed';
3605	else
3606		this.DIV.style.position = 'absolute';
3607
3608	if (!pos.top)
3609	{
3610		this.DIV.style.top = '-1000px';
3611		this.DIV.style.left = '-1000px';
3612	}
3613
3614	if (this.bTimeoutSet) return;
3615
3616	var floatWidth = this.DIV.offsetWidth, floatHeight = this.DIV.offsetHeight;
3617	if (!floatWidth)
3618	{
3619		setTimeout(BX.delegate(function(){
3620			this.bTimeoutSet = false; this.__adjustMenuToNode();
3621		}, this), 100);
3622
3623		this.bTimeoutSet = true;
3624		return;
3625	}
3626
3627	var menu_pos = {},
3628		wndSize = BX.GetWindowSize();
3629
3630/*
3631	if (BX.browser.IsIE() && !BX.browser.IsDoctype())
3632	{
3633		pos.top -= 4; pos.bottom -= 4;
3634		pos.left -= 2; pos.right -= 2;
3635	}
3636*/
3637
3638	switch (this.PARAMS.ATTACH_MODE)
3639	{
3640		case 'bottom':
3641			menu_pos.top = pos.bottom + 9;
3642			menu_pos.left = pos.left;
3643
3644			var arrowPos = 0;
3645			if (!!this.ARROW)
3646			{
3647				if (pos.width > floatWidth)
3648					arrowPos = parseInt(floatWidth/2 - 7);
3649				else
3650					arrowPos = parseInt(Math.min(floatWidth, pos.width)/2 - 7);
3651
3652				if (arrowPos < 7)
3653				{
3654					menu_pos.left -= 15;
3655					arrowPos += 15;
3656				}
3657			}
3658
3659			if (menu_pos.left > wndSize.scrollWidth - floatWidth - 10)
3660			{
3661				var orig_menu_pos = menu_pos.left;
3662				menu_pos.left = wndSize.scrollWidth - floatWidth - 10;
3663
3664				if (!!this.ARROW)
3665					arrowPos += orig_menu_pos - menu_pos.left;
3666			}
3667
3668			if (bFixed)
3669			{
3670				menu_pos.left -= wndSize.scrollLeft;
3671			}
3672
3673			if (!!this.ARROW)
3674				this.ARROW.style.left = arrowPos + 'px';
3675		break;
3676		case 'right':
3677			menu_pos.top = pos.top-1;
3678			menu_pos.left = pos.right;
3679
3680			if (menu_pos.left > wndSize.scrollWidth - floatWidth - 10)
3681			{
3682				menu_pos.left = pos.left - floatWidth - 1;
3683			}
3684		break;
3685	}
3686
3687	if (bFixed)
3688	{
3689		menu_pos.top -= wndSize.scrollTop;
3690	}
3691
3692	if (!!this.ARROW)
3693		this.ARROW.className = 'bx-core-popup-menu-angle';
3694
3695	if((menu_pos.top + floatHeight >
3695 wndSize.scrollTop + wndSize.innerHeight)
3696		|| (menu_pos.top + floatHeight > wndSize.scrollHeight))
3697	{
3698		var new_top = this.PARAMS.ATTACH_MODE == 'bottom'
3699			? pos.top - floatHeight - 9
3700			: pos.bottom - floatHeight + 1;
3701
3702		if((new_top > wndSize.scrollTop)
3703			|| (menu_pos.top + floatHeight > wndSize.scrollHeight))
3704		{
3705			if ((menu_pos.top + floatHeight > wndSize.scrollHeight))
3706			{
3707				menu_pos.top = Math.max(0, wndSize.scrollHeight-floatHeight);
3708				this.toggleArrow(false);
3709			}
3710			else
3711			{
3712				menu_pos.top = new_top;
3713
3714				if (!!this.ARROW)
3715					this.ARROW.className = 'bx-core-popup-menu-angle-bottom';
3716			}
3717		}
3718	}
3719
3720	if (menu_pos.top + menu_pos.left == 0)
3721	{
3722		this.Hide();
3723	}
3724	else
3725	{
3726		this.DIV.style.top = menu_pos.top + 'px';
3727		this.DIV.style.left = menu_pos.left + 'px';
3728	}
3729};
3730
3731BX.CMenu.prototype.adjustToNode = function(el)
3732{
3733	this.PARAMS.parent_attach = BX(el) || this.PARAMS.parent_attach || this.PARAMS.parent;
3734	this.__adjustMenuToNode();
3735};
3736
3737
3738/* components toolbar class */
3739
3740BX.CMenuOpener = function(arParams)
3741{
3742	BX.CMenuOpener.superclass.constructor.apply(this);
3743
3744	this.PARAMS = arParams || {};
3745	this.setParent(this.PARAMS.parent);
3746	this.PARTS = {};
3747
3748	this.SETTINGS.drag_restrict = true;
3749
3750	this.defaultAction = null;
3751
3752	this.timeout = 500;
3753
3754	this.DIV.className = 'bx-component-opener';
3755	this.DIV.ondblclick = BX.PreventDefault;
3756
3757	if (this.PARAMS.component_id)
3758	{
3759		this.PARAMS.transform = !!this.PARAMS.transform;
3760	}
3761
3762	this.OPENERS = [];
3763
3764	this.DIV.appendChild(BX.create('SPAN', {
3765		props: {className: 'bx-context-toolbar' + (this.PARAMS.transform ? ' bx-context-toolbar-vertical-mode' : '')}
3766	}));
3767
3768	//set internal structure and register draggable element
3769	this.PARTS.INNER = this.DIV.firstChild.appendChild(BX.create('SPAN', {
3770		props: {className: 'bx-context-toolbar-inner'},
3771		html: '<span class="bx-context-toolbar-drag-icon"></span><span class="bx-context-toolbar-vertical-line"></span><br>'
3772	}));
3773
3774	this.EXTRA_BUTTONS = {};
3775
3776	var btnCount = 0;
3777	for (var i = 0, len = this.PARAMS.menu.length; i < len; i++)
3778	{
3779		var item = this.addItem(this.PARAMS.menu[i]);
3780		if (null != item)
3781		{
3782			btnCount++;
3783			this.PARTS.INNER.appendChild(item);
3784			this.PARTS.INNER.appendChild(BX.create('BR'));
3785		}
3786	}
3787	var bHasButtons = btnCount > 0;
3788
3789	//menu items will be attached here
3790
3791	this.PARTS.ICONS = this.PARTS.INNER.appendChild(BX.create('SPAN', {
3792		props: {className: 'bx-context-toolbar-icons'}
3793	}));
3794
3795	if (this.PARAMS.component_id)
3796	{
3797		this.PARAMS.pin = !!this.PARAMS.pin;
3798
3799		if (bHasButtons)
3800			this.PARTS.ICONS.appendChild(BX.create('SPAN', {props: {className: 'bx-context-toolbar-separator'}}));
3801
3802		this.PARTS.ICON_PIN = this.PARTS.ICONS.appendChild(BX.create('A', {
3803			attrs: {
3804				href: 'javascript:void(0)'
3805			},
3806			props: {
3807				className: this.PARAMS.pin
3808							? 'bx-context-toolbar-pin-fixed'
3809							: 'bx-context-toolbar-pin'
3810			},
3811			events: {
3812				click: BX.delegate(this.__pin_btn_clicked, this)
3813			}
3814		}));
3815	}
3816
3817
3818	if (this.EXTRA_BUTTONS['components2_props'])
3819	{
3820		var btn = this.EXTRA_BUTTONS['components2_props'] || {URL: 'javascript:void(0)'};
3821		if (null == this.defaultAction)
3822		{
3823			this.defaultAction = btn.ONCLICK;
3824			this.defaultActionTitle = btn.TITLE || btn.TEXT;
3825		}
3826
3827		btn.URL = 'javascript:' + BX.util.urlencode(btn.ONCLICK);
3828
3829		this.ATTACH = this.PARTS.ICONS.appendChild(BX.create('SPAN', {
3830			props: {className: 'bx-context-toolbar-button bx-context-toolbar-button-settings' },
3831			children:
3832			[
3833				BX.create('SPAN',
3834				{
3835					props:{className: 'bx-context-toolbar-button-inner'},
3836					children:
3837					[
3838						BX.create('A', {
3839							attrs: {href: btn.URL},
3840							events: {
3841								mouseover: BX.proxy(this.__msover_text, this),
3842								mouseout: BX.proxy(this.__msout_text, this),
3843								mousedown: BX.proxy(this.__msdown_text, this)
3844							},
3845							html: '<span class="bx-context-toolbar-button-icon bx-context-toolbar-settings-icon"></span>'
3846						}),
3847						BX.create('A', {
3848							attrs: {href: 'javascript: void(0)'},
3849							props: {className: 'bx-context-toolbar-button-arrow'},
3850							events: {
3851								mouseover: BX.proxy(this.__msover_arrow, this),
3852								mouseout: BX.proxy(this.__msout_arrow, this),
3853								mousedown: BX.proxy(this.__msdown_arrow, this)
3854							},
3855							html: '<span class="bx-context-toolbar-button-arrow"></span>'
3856						})
3857					]
3858				})
3859			]
3860		}));
3861
3862		this.OPENER = this.ATTACH.firstChild.lastChild;
3863
3864		var opener = this.attachMenu(this.EXTRA_BUTTONS['components2_submenu']['MENU']);
3865
3866		BX.addCustomEvent(opener, 'onOpenerMenuOpen', BX.proxy(this.__menu_open, this));
3867		BX.addCustomEvent(opener, 'onOpenerMenuClose', BX.proxy(this.__menu_close, this));
3868	}
3869
3870	if (btnCount > 1)
3871	{
3872		this.PARTS.ICONS.appendChild(BX.create('span', { props: {className: 'bx-context-toolbar-separator bx-context-toolbar-separator-switcher'}}));
3873
3874		this.ICON_TRANSFORM = this.PARTS.ICONS.appendChild(BX.create('A', {
3875			attrs: {href: 'javascript: void(0)'},
3876			props: {className: 'bx-context-toolbar-switcher'},
3877			events: {
3878				click: BX.delegate(this.__trf_btn_clicked, this)
3879			}
3880		}));
3881	}
3882
3883	if (this.PARAMS.HINT)
3884	{
3885		this.DIV.BXHINT = this.HINT = new BX.CHint({
3886			parent: this.DIV,
3887			hint:this.PARAMS.HINT.TEXT || '',
3888			title: this.PARAMS.HINT.TITLE || '',
3889			hide_timeout: this.timeout/2,
3890			preventHide: false
3891		});
3892	}
3893
3894	BX.addCustomEvent(this, 'onWindowDragFinished', BX.delegate(this.__onMoveFinished, this));
3895	BX.addCustomEvent('onDynamicModeChange', BX.delegate(this.__onDynamicModeChange, this));
3896	BX.addCustomEvent('onTopPanelCollapse', BX.delegate(this.__onPanelCollapse, this));
3897
3898	BX.addCustomEvent('onMenuOpenerMoved', BX.delegate(this.checkPosition, this));
3899	BX.addCustomEvent('onMenuOpenerUnhide', BX.delegate(this.checkPosition, this));
3900
3901	if (this.OPENERS)
3902	{
3903		for (i=0,len=this.OPENERS.length; i<len; i++)
3904		{
3905			BX.addCustomEvent(this.OPENERS[i], 'onOpenerMenuOpen', BX.proxy(this.__hide_hint, this));
3906		}
3907	}
3908};
3909BX.extend(BX.CMenuOpener, BX.CWindowFloat);
3910
3911BX.CMenuOpener.prototype.setParent = function(new_parent)
3912{
3913	new_parent = BX(new_parent);
3914	if(new_parent.OPENER && new_parent.OPENER != this)
3915	{
3916		new_parent.OPENER.Close();
3917		new_parent.OPENER.clearHoverHoutEvents();
3918	}
3919
3920	if(this.PARAMS.parent && this.PARAMS.parent != new_parent)
3921	{
3922		this.clearHoverHoutEvents();
3923		this.PARAMS.parent.OPENER = null;
3924	}
3925
3926	this.PARAMS.parent = new_parent;
3927	this.PARAMS.parent.OPENER = this;
3928};
3929
3930BX.CMenuOpener.prototype.setHoverHoutEvents = function(hover, hout)
3931{
3932	if(!this.__opener_events_set)
3933	{
3934		BX.bind(this.Get(), 'mouseover', hover);
3935		BX.bind(this.Get(), 'mouseout', hout);
3936		this.__opener_events_set = true;
3937	}
3938};
3939
3940BX.CMenuOpener.prototype.clearHoverHoutEvents = function()
3941{
3942	if(this.Get())
3943	{
3944		BX.unbindAll(this.Get());
3945		this.__opener_events_set = false;
3946	}
3947};
3948
3949
3950BX.CMenuOpener.prototype.unclosable = true;
3951
3952BX.CMenuOpener.prototype.__check_intersection = function(pos_self, pos_other)
3953{
3954	return !(pos_other.right <= pos_self.left || pos_other.left >= pos_self.right
3955			|| pos_other.bottom <= pos_self.top || pos_other.top >= pos_self.bottom);
3956};
3957
3958
3959BX.CMenuOpener.prototype.__msover_text = function() {
3960	this.bx_hover = true;
3961	if (!this._menu_open)
3962		BX.addClass(this.ATTACH, 'bx-context-toolbar-button-text-hover');
3963};
3964
3965BX.CMenuOpener.prototype.__msout_text = function() {
3966	this.bx_hover = false;
3967	if (!this._menu_open)
3968		BX.removeClass(this.ATTACH, 'bx-context-toolbar-button-text-hover bx-context-toolbar-button-text-active');
3969};
3970
3971BX.CMenuOpener.prototype.__msover_arrow = function() {
3972	this.bx_hover = true;
3973	if (!this._menu_open)
3974		BX.addClass(this.ATTACH, 'bx-context-toolbar-button-arrow-hover');
3975};
3976
3977BX.CMenuOpener.prototype.__msout_arrow = function() {
3978	this.bx_hover = false;
3979	if (!this._menu_open)
3980		BX.removeClass(this.ATTACH, 'bx-context-toolbar-button-arrow-hover bx-context-toolbar-button-arrow-active');
3981};
3982
3983BX.CMenuOpener.prototype.__msdown_text = function() {
3984	this.bx_active = true;
3985	if (!this._menu_open)
3986		BX.addClass(this.ATTACH, 'bx-context-toolbar-button-text-active');
3987};
3988
3989BX.CMenuOpener.prototype.__msdown_arrow = function() {
3990	this.bx_active = true;
3991	if (!this._menu_open)
3992		BX.addClass(this.ATTACH, 'bx-context-toolbar-button-arrow-active');
3993};
3994
3995BX.CMenuOpener.prototype.__menu_close = function() {
3996	this._menu_open = false;
3997	this.bx_active = false;
3998	BX.removeClass(this.ATTACH, 'bx-context-toolbar-button-active bx-context-toolbar-button-text-active bx-context-toolbar-button-arrow-active');
3999	if (!this.bx_hover)
4000	{
4001		BX.removeClass(this.ATTACH, 'bx-context-toolbar-button-hover bx-context-toolbar-button-text-hover bx-context-toolbar-button-arrow-hover');
4002		this.bx_hover = false;
4003	}
4004};
4005
4006BX.CMenuOpener.prototype.__menu_open = function() {
4007	this._menu_open = true;
4008};
4009
4010BX.CMenuOpener.prototype.checkPosition = function()
4011{
4012	if (this.isMenuVisible() || this.DIV.style.display == 'none'
4013		|| this == BX.proxy_context || BX.proxy_context.zIndex > this.zIndex)
4014		return;
4015
4016	this.correctPosition(BX.proxy_context);
4017};
4018
4019BX.CMenuOpener.prototype.correctPosition = function(opener)
4020{
4021	var pos_self = BX.pos(this.DIV), pos_other = BX.pos(opener.Get());
4022	if (this.__check_intersection(pos_self, pos_other))
4023	{
4024		var new_top = pos_other.top - pos_self.height;
4025		if (new_top < 0)
4026			new_top = pos_other.bottom;
4027
4028		this.DIV.style.top = new_top + 'px';
4029
4030		BX.addCustomEvent(opener, 'onMenuOpenerHide', BX.proxy(this.restorePosition, this));
4031		BX.onCustomEvent(this, 'onMenuOpenerMoved');
4032	}
4033};
4034
4035BX.CMenuOpener.prototype.restorePosition = function()
4036{
4037	if (!this.MOUSEOVER && !this.isMenuVisible())
4038	{
4039		if (this.originalPos)
4040			this.DIV.style.top = this.originalPos.top + 'px';
4041
4042		BX.removeCustomEvent(BX.proxy_context, 'onMenuOpenerHide', BX.proxy(this.restorePosition, this));
4043		if (this.restore_pos_timeout) clearTimeout(this.restore_pos_timeout);
4044	}
4045	else
4046	{
4047		this.restore_pos_timeout = setTimeout(BX.proxy(this.restorePosition, this), this.timeout);
4048	}
4049};
4050
4051
4052BX.CMenuOpener.prototype.Show = function()
4053{
4054	BX.CMenuOpener.superclass.Show.apply(this, arguments);
4055
4056	this.SetDraggable(this.PARTS.INNER.firstChild);
4057
4058	this.DIV.style.width = 'auto';
4059	this.DIV.style.height = 'auto';
4060
4061	if (!this.PARAMS.pin)
4062	{
4063		this.DIV.style.left = '-1000px';
4064		this.DIV.style.top = '-1000px';
4065
4066		this.Hide();
4067	}
4068	else
4069	{
4070		this.bPosAdjusted = true;
4071		this.bMoved = true;
4072
4073		if (this.PARAMS.top) this.DIV.style.top = this.PARAMS.top + 'px';
4074		if (this.PARAMS.left) this.DIV.style.left = this.PARAMS.left + 'px';
4075
4076		this.DIV.style.display = (!BX.admin.dynamic_mode || BX.admin.dynamic_mode_show_borders) ? 'block' : 'none';
4077
4078		if (this.DIV.style.display == 'block')
4079		{
4080			setTimeout(BX.delegate(function() {BX.onCustomEvent(this, 'onMenuOpenerUnhide')}, this), 50);
4081		}
4082	}
4083};
4084
4085BX.CMenuOpener.prototype.executeDefaultAction = function()
4086{
4087	if (this.defaultAction)
4088	{
4089		if (BX.type.isFunction(this.defaultAction))
4090			this.defaultAction();
4091		else if(BX.type.isString(this.defaultAction))
4092			BX.evalGlobal(this.defaultAction);
4093	}
4094};
4095
4096BX.CMenuOpener.prototype.__onDynamicModeChange = function(val)
4097{
4098	this.DIV.style.display = val ? 'block' : 'none';
4099};
4100
4101BX.CMenuOpener.prototype.__onPanelCollapse = function(bCollapsed, dy)
4102{
4103	this.DIV.style.top = (parseInt(this.DIV.style.top) + dy) + 'px';
4104	if (this.PARAMS.pin)
4105	{
4106		this.__savePosition();
4107	}
4108};
4109
4110BX.CMenuOpener.prototype.__onMoveFinished = function()
4111{
4112	BX.onCustomEvent(this, 'onMenuOpenerMoved');
4113
4114	this.bMoved = true;
4115
4116	if (this.PARAMS.pin)
4117		this.__savePosition();
4118};
4119
4120BX.CMenuOpener.prototype.__savePosition = function()
4121{
4122	var arOpts = {};
4123
4124	arOpts.pin = this.PARAMS.pin;
4125	if (!this.PARAMS.pin)
4126	{
4127		arOpts.top = false; arOpts.left = false; arOpts.transform = false;
4128	}
4129	else
4130	{
4131		arOpts.transform = this.PARAMS.transform;
4132		if (this.bMoved)
4133		{
4134			arOpts.left = parseInt(this.DIV.style.left);
4135			arOpts.top = parseInt(this.DIV.style.top);
4136		}
4137	}
4138
4139	BX.WindowManager.saveWindowOptions(this.PARAMS.component_id, arOpts);
4140};
4141
4142BX.CMenuOpener.prototype.__pin_btn_clicked = function() {this.Pin()};
4143BX.CMenuOpener.prototype.Pin = function(val)
4144{
4145	if (null == val)
4146		this.PARAMS.pin = !this.PARAMS.pin;
4147	else
4148		this.PARAMS.pin = !!val;
4149
4150	this.PARTS.ICON_PIN.className = (this.PARAMS.pin ? 'bx-context-toolbar-pin-fixed' : 'bx-context-toolbar-pin');
4151
4152	this.__savePosition();
4153};
4154
4155BX.CMenuOpener.prototype.__trf_btn_clicked = function() {this.Transform()};
4156BX.CMenuOpener.prototype.Transform = function(val)
4157{
4158	var pos = {};
4159
4160	if (null == val)
4161		this.PARAMS.transform = !this.PARAMS.transform;
4162	else
4163		this.PARAMS.transform = !!val;
4164
4165	if (this.bMoved)
4166	{
4167		pos = BX.pos(this.DIV);
4168	}
4169
4170	if (this.PARAMS.transform)
4171		BX.addClass(this.DIV.firstChild, 'bx-context-toolbar-vertical-mode');
4172	else
4173		BX.removeClass(this.DIV.firstChild, 'bx-context-toolbar-vertical-mode');
4174
4175	if (!this.bMoved)
4176	{
4177		this.adjustPos();
4178	}
4179	else
4180	{
4181		this.DIV.style.left = (pos.right - this.DIV.offsetWidth - (BX.browser.IsIE() && !BX.browser.IsDoctype() ? 2 : 0)) + 'px';
4182	}
4183
4184	this.__savePosition();
4185};
4186
4187BX.CMenuOpener.prototype.adjustToNodeGetPos = function()
4188{
4189	var pos = BX.pos(this.PARAMS.parent/*, true*/);
4190
4191	var scrollSize = BX.GetWindowScrollSize();
4192	var floatWidth = this.DIV.offsetWidth;
4193
4194	pos.left -= BX.admin.__border_dx;
4195	pos.top -= BX.admin.__border_dx;
4196
4197	if (true || !this.PARAMS.transform)
4198	{
4199		pos.top -= 45;
4200	}
4201
4202	if (pos.left > scrollSize.scrollWidth - floatWidth)
4203	{
4204		pos.left = scrollSize.scrollWidth - floatWidth;
4205	}
4206
4207	return pos;
4208};
4209
4210BX.CMenuOpener.prototype.addItem = function(item)
4211{
4212	if (item.TYPE)
4213	{
4214		this.EXTRA_BUTTONS[item.TYPE] = item;
4215		return null;
4216	}
4217	else
4218	{
4219		var q = new BX.CMenuOpenerItem(item);
4220		if (null == this.defaultAction)
4221		{
4222			if (q.item.ONCLICK)
4223			{
4224				this.defaultAction = item.ONCLICK;
4225			}
4226			else if (q.item.MENU)
4227			{
4228				this.defaultAction = BX.delegate(function() {this.Open()}, q.item.OPENER);
4229			}
4230
4231			this.defaultActionTitle = item.TITLE || item.TEXT;
4232
4233			BX.addClass(q.Get(), 'bx-content-toolbar-default');
4234		}
4235		if (q.item.OPENER) this.OPENERS[this.OPENERS.length] = q.item.OPENER;
4236		return q.Get();
4237	}
4238};
4239
4240BX.CMenuOpener.prototype.attachMenu = function(menu)
4241{
4242	var opener = new BX.COpener({
4243		'DIV':  this.OPENER,
4244		'ATTACH': this.ATTACH,
4245		'MENU': menu,
4246		'TYPE': 'click'
4247	});
4248
4249	this.OPENERS[this.OPENERS.length] = opener;
4250
4251	return opener;
4252};
4253
4254BX.CMenuOpener.prototype.__hide_hint = function()
4255{
4256	if (this.HINT) this.HINT.__hide_immediately();
4257};
4258
4259BX.CMenuOpener.prototype.isMenuVisible = function()
4260{
4261	for (var i=0,len=this.OPENERS.length; i<len; i++)
4262	{
4263		if (this.OPENERS[i].isMenuVisible())
4264			return true;
4265	}
4266
4267	return false;
4268};
4269
4270BX.CMenuOpener.prototype.Hide = function()
4271{
4272	if (!this.PARAMS.pin)
4273	{
4274		this.DIV.style.display = 'none';
4275		BX.onCustomEvent(this, 'onMenuOpenerHide');
4276	}
4277};
4278BX.CMenuOpener.prototype.UnHide = function()
4279{
4280	this.DIV.style.display = 'block';
4281	if (!this.bPosAdjusted && !this.PARAMS.pin)
4282	{
4283		this.adjustPos();
4284		this.bPosAdjusted = true;
4285	}
4286
4287	if (null == this.originalPos && !this.bMoved)
4288	{
4289		this.originalPos = BX.pos(this.DIV);
4290	}
4291
4292	BX.onCustomEvent(this, 'onMenuOpenerUnhide');
4293};
4294
4295BX.CMenuOpenerItem = function(item)
4296{
4297	this.item = item;
4298
4299	if (this.item.ACTION && !this.item.ONCLICK)
4300	{
4301		this.item.ONCLICK = this.item.ACTION;
4302	}
4303
4304	this.DIV = BX.create('SPAN');
4305	this.DIV.appendChild(BX.create('SPAN', {props: {className: 'bx-context-toolbar-button-underlay'}}));
4306
4307	this.WRAPPER = this.DIV.appendChild(BX.create('SPAN', {
4308		props: {className: 'bx-context-toolbar-button-wrapper'},
4309		children: [
4310			BX.create('SPAN', {
4311				props: {className: 'bx-context-toolbar-button', title: item.TITLE},
4312				children: [
4313					BX.create('SPAN', {
4314						props: {className: 'bx-context-toolbar-button-inner'}
4315					})
4316				]
4317			})
4318		]
4319	}));
4320
4321	var btn_icon = BX.create('SPAN', {
4322		props: {className: 'bx-context-toolbar-button-icon' + (this.item.ICON || this.item.ICONCLASS ? ' ' + (this.item.ICON || this.item.ICONCLASS) : '')},
4323		attrs: (
4324				!(this.item.ICON || this.item.ICONCLASS)
4325				&&
4326				(this.item.SRC || this.item.IMAGE)
4327			)
4328			? {
4329				style: 'background: scroll transparent url(' + (this.item.SRC || this.item.IMAGE) + ') no-repeat center center !important;'
4330			}
4331			: {}
4332	}), btn_text = BX.create('SPAN', {
4333		props: {className: 'bx-context-toolbar-button-text'},
4334		text: this.item.TEXT
4335	});
4336
4337	if (this.item.ACTION && !this.item.ONCLICK)
4338	{
4339		this.item.ONCLICK = this.item.ACTION;
4340	}
4341
4342	this.bHasMenu = !!this.item.MENU;
4343	this.bHasAction = !!this.item.ONCLICK;
4344
4345	if (this.bHasAction)
4346	{
4347		this.LINK = this.WRAPPER.firstChild.firstChild.appendChild(BX.create('A', {
4348			attrs: {
4349				'href': 'javascript: void(0)'
4350			},
4351			events: {
4352				mouseover: this.bHasMenu ? BX.proxy(this.__msover_text, this) : BX.proxy(this.__msover, this),
4353				mouseout: this.bHasMenu ? BX.proxy(this.__msout_text, this) : BX.proxy(this.__msout, this),
4354				mousedown: this.bHasMenu ? BX.proxy(this.__msdown_text, this) : BX.proxy(this.__msdown, this)
4355			},
4356			children: [btn_icon, btn_text]
4357		}));
4358
4359		if (this.bHasMenu)
4360		{
4361			this.LINK_MENU = this.WRAPPER.firstChild.firstChild.appendChild(BX.create('A', {
4362				props: {className: 'bx-context-toolbar-button-arrow'},
4363				attrs: {
4364					'href': 'javascript: void(0)'
4365				},
4366				events: {
4367					mouseover: BX.proxy(this.__msover_arrow, this),
4368					mouseout: BX.proxy(this.__msout_arrow, this),
4369					mousedown: BX.proxy(this.__msdown_arrow, this)
4370				},
4371				children: [
4372					BX.create('SPAN', {props: {className: 'bx-context-toolbar-button-arrow'}})
4373				]
4374			}));
4375		}
4376
4377	}
4378	else if (this.bHasMenu)
4379	{
4380		this.item.ONCLICK = null;
4381
4382		this.LINK = this.LINK_MENU = this.WRAPPER.firstChild.firstChild.appendChild(BX.create('A', {
4383			attrs: {
4384				'href': 'javascript: void(0)'
4385			},
4386			events: {
4387				mouseover: BX.proxy(this.__msover, this),
4388				mouseout: BX.proxy(this.__msout, this),
4389				mousedown: BX.proxy(this.__msdown, this)
4390			},
4391			children: [
4392				btn_icon,
4393				btn_text
4394			]
4395		}));
4396
4397		this.LINK.appendChild(BX.create('SPAN', {props: {className: 'bx-context-toolbar-single-button-arrow'}}));
4398
4399	}
4400
4401	if (this.bHasMenu)
4402	{
4403		this.item.SUBMENU = new BX.CMenu({
4404			ATTACH_MODE:'bottom',
4405			ITEMS:this.item['MENU'],
4406			//PARENT_MENU:this.parentMenu,
4407			parent: this.LINK_MENU,
4408			parent_attach: this.WRAPPER.firstChild
4409		});
4410
4411		this.item.OPENER = new BX.COpener({
4412			DIV: this.LINK_MENU,
4413			TYPE: 'click',
4414			MENU: this.item.SUBMENU
4415		});
4416
4417		BX.addCustomEvent(this.item.OPENER, 'onOpenerMenuOpen', BX.proxy(this.__menu_open, this));
4418		BX.addCustomEvent(this.item.OPENER, 'onOpenerMenuClose', BX.proxy(this.__menu_close, this));
4419	}
4420
4421	if (this.bHasAction)
4422	{
4423		BX.bind(this.LINK, 'click', BX.delegate(this.__click, this));
4424	}
4425};
4426
4427BX.CMenuOpenerItem.prototype.Get = function() {return this.DIV;};
4428BX.CMenuOpenerItem.prototype.__msover = function() {
4429	this.bx_hover = true;
4430	if (!this._menu_open)
4431		BX.addClass(this.LINK.parentNode.parentNode, 'bx-context-toolbar-button-hover');
4432};
4433BX.CMenuOpenerItem.prototype.__msout = function() {
4434	this.bx_hover = false;
4435	if (!this._menu_open)
4436		BX.removeClass(this.LINK.parentNode.parentNode, 'bx-context-toolbar-button-hover bx-context-toolbar-button-active');
4437};
4438BX.CMenuOpenerItem.prototype.__msover_text = function() {
4439	this.bx_hover = true;
4440	if (!this._menu_open)
4441		BX.addClass(this.LINK.parentNode.parentNode, 'bx-context-toolbar-button-text-hover');
4442};
4443BX.CMenuOpenerItem.prototype.__msout_text = function() {
4444	this.bx_hover = false;
4445	if (!this._menu_open)
4446		BX.removeClass(this.LINK.parentNode.parentNode, 'bx-context-toolbar-button-text-hover bx-context-toolbar-button-text-active');
4447};
4448BX.CMenuOpenerItem.prototype.__msover_arrow = function() {
4449	this.bx_hover = true;
4450	if (!this._menu_open)
4451		BX.addClass(this.LINK.parentNode.parentNode, 'bx-context-toolbar-button-arrow-hover');
4452};
4453BX.CMenuOpenerItem.prototype.__msout_arrow = function() {
4454	this.bx_hover = false;
4455	if (!this._menu_open)
4456		BX.removeClass(this.LINK.parentNode.parentNode, 'bx-context-toolbar-button-arrow-hover bx-context-toolbar-button-arrow-active');
4457};
4458BX.CMenuOpenerItem.prototype.__msdown = function() {
4459	this.bx_active = true;
4460	if (!this._menu_open)
4461		BX.addClass(this.LINK.parentNode.parentNode, 'bx-context-toolbar-button-active');
4462};
4463BX.CMenuOpenerItem.prototype.__msdown_text = function() {
4464	this.bx_active = true;
4465	if (!this._menu_open)
4466		BX.addClass(this.LINK.parentNode.parentNode, 'bx-context-toolbar-button-text-active');
4467};
4468BX.CMenuOpenerItem.prototype.__msdown_arrow = function() {
4469	this.bx_active = true;
4470	if (!this._menu_open)
4471		BX.addClass(this.LINK.parentNode.parentNode, 'bx-context-toolbar-button-arrow-active');
4472};
4473BX.CMenuOpenerItem.prototype.__menu_close = function() {
4474
4475	this._menu_open = false;
4476	this.bx_active = false;
4477	BX.removeClass(this.LINK.parentNode.parentNode, 'bx-context-toolbar-button-active bx-context-toolbar-button-text-active bx-context-toolbar-button-arrow-active');
4478	if (!this.bx_hover)
4479	{
4480		BX.removeClass(this.LINK.parentNode.parentNode, 'bx-context-toolbar-button-hover bx-context-toolbar-button-text-hover bx-context-toolbar-button-arrow-hover');
4481		this.bx_hover = false;
4482	}
4483};
4484BX.CMenuOpenerItem.prototype.__menu_open = function() {
4485	this._menu_open = true;
4486};
4487
4488BX.CMenuOpenerItem.prototype.__click = function() {BX.evalGlobal(this.item.ONCLICK)};
4489
4490/* global page opener class */
4491BX.CPageOpener = function(arParams)
4492{
4493	//if (null == arParams.pin) arParams.pin = true;
4494	BX.CPageOpener.superclass.constructor.apply(this, arguments);
4495
4496	this.timeout = 505;
4497
4498	window.PAGE_EDIT_CONTROL = this;
4499};
4500BX.extend(BX.CPageOpener, BX.CMenuOpener);
4501
4502BX.CPageOpener.prototype.checkPosition = function()
4503{
4504	if (/*this.isMenuVisible() || this.DIV.style.display == 'none' || */this == BX.proxy_context)
4505		return;
4506
4507	this.correctPosition(BX.proxy_context);
4508};
4509
4510BX.CPageOpener.prototype.correctPosition = function(opener)
4511{
4512	if (this.bPosCorrected) return;
4513	var pos_self;
4514	if (this.DIV.style.display == 'none')
4515	{
4516		pos_self = this.adjustToNodeGetPos();
4517		pos_self.bottom = pos_self.top + 30;
4518		pos_self.right = pos_self.left + 300;
4519	}
4520	else
4521	{
4522		pos_self = BX.pos(this.DIV);
4523	}
4524
4525	var pos_other = BX.pos(opener.Get());
4526	if (this.__check_intersection(pos_self, pos_other))
4527	{
4528		this.DIV.style.display = 'none';
4529		BX.addCustomEvent(opener, 'onMenuOpenerHide', BX.proxy(this.restorePosition, this));
4530
4531		this.bPosCorrected = true;
4532	}
4533};
4534
4535BX.CPageOpener.prototype.restorePosition = function()
4536{
4537	if (BX.proxy_context && BX.proxy_context.Get().style.display == 'none')
4538	{
4539		this.bPosCorrected = false;
4540
4541		if (this.PARAMS.parent.bx_over || this.PARAMS.pin)
4542			this.UnHide();
4543
4544		BX.removeCustomEvent('onMenuOpenerHide', BX.proxy(this.restorePosition, this));
4545	}
4546};
4547
4548BX.CPageOpener.prototype.UnHide = function()
4549{
4550	if (!this.bPosCorrected)
4551		BX.CPageOpener.superclass.UnHide.apply(this, arguments);
4552};
4553
4554BX.CPageOpener.prototype.Remove = function()
4555{
4556	BX.admin.removeComponentBorder(this.PARAMS.parent);
4557	BX.userOptions.save('global', 'settings', 'page_edit_control_enable', 'N');
4558	this.DIV.style.display = 'none';
4559};
4560
4561/******* HINT ***************/
4562BX.CHintSimple = function()
4563{
4564	BX.CHintSimple.superclass.constructor.apply(this, arguments);
4565};
4566BX.extend(BX.CHintSimple, BX.CHint);
4567
4568BX.CHintSimple.prototype.Init = function()
4569{
4570	this.DIV = document.body.appendChild(BX.create('DIV', {props: {className: 'bx-tooltip-simple'}, style: {display: 'none'}, children: [(this.CONTENT = BX.create('DIV'))]}));
4571
4572	BX.ZIndexManager.register(this.DIV);
4573
4574	if (this.HINT_TITLE)
4575		this.CONTENT.appendChild(BX.create('B', {text: this.HINT_TITLE}));
4576
4577	if (this.HINT)
4578		this.CONTENT_TEXT = this.CONTENT.appendChild(BX.create('DIV')).appendChild(BX.create('SPAN', {html: this.HINT}));
4579
4580	if (this.PARAMS.preventHide)
4581	{
4582		BX.bind(this.DIV, 'mouseout', BX.proxy(this.Hide, this));
4583		BX.bind(this.DIV, 'mouseover', BX.proxy(this.Show, this));
4584	}
4585
4586	this.bInited = true;
4587};
4588
4589/*************************** admin informer **********************************/
4590BX.adminInformer = {
4591
4592	itemsShow: 3,
4593
4594	Init: function (itemsShow)
4595	{
4596		if(itemsShow)
4597			BX.adminInformer.itemsShow = itemsShow;
4598
4599		var informer = BX("admin-informer");
4600
4601		if(informer)
4602		{
4603			document.body.appendChild(informer);
4604			BX.ZIndexManager.register(informer);
4605		}
4606
4607		BX.addCustomEvent("onTopPanelCollapse", BX.proxy(BX.adminInformer.Close, BX.adminInformer));
4608	},
4609
4610	Toggle: function(notifyBlock)
4611	{
4612		var informer = BX("admin-informer");
4613
4614		if(!informer)
4615			return false;
4616
4617		var pos = BX.pos(notifyBlock);
4618
4619		informer.style.top = (parseInt(pos.top)+parseInt(pos.height)+7)+'px';
4620		informer.style.left = pos.left+'px';
4621
4622		if(!BX.hasClass(informer, "adm-informer-active"))
4623			BX.adminInformer.Show(informer);
4624		else
4625			BX.adminInformer.Hide(informer);
4626
4627		return false;
4628	},
4629
4630	Close: function()
4631	{
4632		BX.adminInformer.Hide(BX("admin-informer"));
4633	},
4634
4635	OnInnerClick: function(event)
4636	{
4637		var target = event.target || event.srcElement;
4638
4639		if(target.nodeName.toLowerCase() != 'a' || BX.hasClass(target,"adm-informer-footer"))
4640		{
4641			return BX.PreventDefault(event);
4642		}
4643
4644		return true;
4645	},
4646
4647	ToggleExtra : function()
4648	{
4649		var footerLink = BX("adm-informer-footer");
4650
4651		if (BX.hasClass(footerLink, "adm-informer-footer-collapsed"))
4652			this.ShowAll();
4653		else
4654			this.HideExtra();
4655
4656		return false;
4657	},
4658
4659	ShowAll: function()
4660	{
4661		var informer = BX("admin-informer");
4662		for(var i=0; i<informer.children.length; i++)
4663
4664			if(BX.hasClass(informer.children[i], "adm-informer-item") && informer.children[i].style.display == "none") {
4665				informer.children[i].style.display = "block";
4666			}
4667
4668		var footerLink = BX("adm-informer-footer");
4669
4670		if(footerLink.textContent !== undefined)
4671			footerLink.textContent = BX.message('JSADM_AI_HIDE_EXTRA');
4672		else
4673			footerLink.innerText = BX.message('JSADM_AI_HIDE_EXTRA');
4674
4675		BX.removeClass(footerLink, "adm-informer-footer-collapsed");
4676
4677		return false;
4678	},
4679
4680	HideExtra: function()
4681	{
4682		var informer = BX("admin-informer");
4683		var hided = 0;
4684
4685		for(var i=BX.adminInformer.itemsShow+1; i<informer.children.length; i++)
4686		{
4687			if (BX.hasClass(informer.children[i], "adm-informer-item") && informer.children[i].style.display == "block") {
4688				informer.children[i].style.display = "none";
4689				hided++;
4690			}
4691		}
4692
4693		var footerLink = BX("adm-informer-footer");
4694
4695		var linkText = BX.message('JSADM_AI_ALL_NOTIF')+" ("+(BX.adminInformer.itemsShow+parseInt(hided))+")";
4696
4697		if(footerLink.textContent !== undefined)
4698			footerLink.textContent = linkText;
4699		else
4700			footerLink.innerText = linkText;
4701
4702		BX.addClass(footerLink, "adm-informer-footer-collapsed");
4703
4704		return false;
4705	},
4706
4707	Show: function(informer)
4708	{
4709		var notifButton = BX("adm-header-notif-block");
4710		if (notifButton)
4711			BX.addClass(notifButton, "adm-header-notif-block-active");
4712
4713		BX.onCustomEvent(informer, 'onBeforeAdminInformerShow');
4714		setTimeout(
4715			BX.proxy(function() {
4716					BX.bind(document, "click", BX.proxy(BX.adminInformer.Close, BX.adminInformer));
4717				},
4718				BX.adminInformer
4719			),0
4720		);
4721		BX.addClass(informer, "adm-informer-active");
4722
4723		BX.ZIndexManager.bringToFront(informer);
4724
4725		setTimeout(function() {BX.addClass(informer, "adm-informer-animate");},0);
4726	},
4727
4728	Hide: function(informer)
4729	{
4730		var notifButton = BX("adm-header-notif-block");
4731		if (notifButton)
4732			BX.removeClass(notifButton, "adm-header-notif-block-active");
4733
4734		BX.unbind(document, "click", BX.proxy(BX.adminInformer.Close, BX.adminInformer));
4735
4736		BX.removeClass(informer, "adm-informer-animate");
4737
4738		if (this.IsAnimationSupported())
4739			setTimeout(function() {BX.removeClass(informer, "adm-informer-active");}, 300);
4740		else
4741			BX.removeClass(informer, "adm-informer-active");
4742
4743		BX.onCustomEvent(informer, 'onAdminInformerHide');
4744		//setTimeout(function() {BX.adminInformer.HideExtra();},500);
4745	},
4746
4747	IsAnimationSupported : function()
4748	{
4749		var d = document.body || document.documentElement;
4750		if (typeof(d.style.transition) == "string")
4751			return true;
4752		else if (typeof(d.style.MozTransition) == "string")
4753			return true;
4754		else if (typeof(d.style.OTransition) == "string")
4755			return true;
4756		else if (typeof(d.style.WebkitTransition) == "string")
4757			return true;
4758		else if (typeof(d.style.msTransition) == "string")
4759			return true;
4760
4761		return false;
4762	},
4763
4764
4765	SetItemHtml: function(itemIdx, html)
4766	{
4767		var itemHtmlDiv = BX("adm-informer-item-html-"+itemIdx);
4768
4769		if(!itemHtmlDiv)
4770			return false;
4771
4772		itemHtmlDiv.innerHTML = html;
4773
4774		return true;
4775	},
4776
4777	SetItemFooter: function(itemIdx, html)
4778	{
4779		var itemFooterDiv = BX("adm-informer-item-footer-"+itemIdx);
4780
4781		if(!itemFooterDiv)
4782			return false;
4783
4784		itemFooterDiv.innerHTML = html;
4785
4786		if(html)
4787			itemFooterDiv.style.display = "block";
4788		else
4789			itemFooterDiv.style.display = "none";
4790
4791		return true;
4792	}
4793
4794};
4795
4796}
4796)(window);
4797
4798
4799/* End */
4800;
4801; /* Start:"a:4:{s:4:"full";s:40:"/bitrix/js/main/utils.js?167415717929279";s:6:"source";s:24:"/bitrix/js/main/utils.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
4802var phpVars;
4803if(!phpVars)
4804{
4805	phpVars = {
4806		ADMIN_THEME_ID: '.default',
4807		LANGUAGE_ID: 'en',
4808		FORMAT_DATE: 'DD.MM.YYYY',
4809		FORMAT_DATETIME: 'DD.MM.YYYY HH:MI:SS',
4810		opt_context_ctrl: false,
4811		cookiePrefix: 'BITRIX_SM',
4812		titlePrefix: '',
4813		bitrix_sessid: '',
4814		messHideMenu: '',
4815		messShowMenu: '',
4816		messHideButtons: '',
4817		messShowButtons: '',
4818		messFilterInactive: '',
4819		messFilterActive: '',
4820		messFilterLess: '',
4821		messLoading: 'Loading...',
4822		messMenuLoading: '',
4823		messMenuLoadingTitle: '',
4824		messNoData: '',
4825		messExpandTabs: '',
4826		messCollapseTabs: '',
4827		messPanelFixOn: '',
4828		messPanelFixOff: '',
4829		messPanelCollapse: '',
4830		messPanelExpand: ''
4831	};
4832}
4833
4834var jsUtils =
4835{
4836	arEvents: Array(),
4837
4838	addEvent: function(el, evname, func, capture)
4839	{
4840		if(el.attachEvent) // IE
4841			el.attachEvent("on" + evname, func);
4842		else if(el.addEventListener) // Gecko / W3C
4843			el.addEventListener(evname, func, false);
4844		else
4845			el["on" + evname] = func;
4846		this.arEvents[this.arEvents.length] = {'element': el, 'event': evname, 'fn': func};
4847	},
4848
4849	removeEvent: function(el, evname, func)
4850	{
4851		if(el.detachEvent) // IE
4852			el.detachEvent("on" + evname, func);
4853		else if(el.removeEventListener) // Gecko / W3C
4854			el.removeEventListener(evname, func, false);
4855		else
4856			el["on" + evname] = null;
4857	},
4858
4859	removeAllEvents: function(el)
4860	{
4861		var i;
4862		for(i=0; i<this.arEvents.length; i++)
4863		{
4864			if(this.arEvents[i] && (el==false || el==this.arEvents[i].element))
4865			{
4866				jsUtils.removeEvent(this.arEvents[i].element, this.arEvents[i].event, this.arEvents[i].fn);
4867				this.arEvents[i] = null;
4868			}
4869		}
4870		if(el==false)
4871			this.arEvents.length = 0;
4872	},
4873
4874	IsDoctype: function()
4875	{
4876		if (document.compatMode)
4877			return (document.compatMode == "CSS1Compat");
4878
4879		if (document.documentElement && document.documentElement.clientHeight)
4880			return true;
4881
4882		return false;
4883	},
4884
4885	GetRealPos: function(el)
4886	{
4887		if(window.BX)
4888			return BX.pos(el);
4889
4890		if(!el || !el.offsetParent)
4891			return false;
4892
4893		var res = Array();
4894		res["left"] = el.offsetLeft;
4895		res["top"] = el.offsetTop;
4896		var objParent = el.offsetParent;
4897
4898		while(objParent && objParent.tagName != "BODY")
4899		{
4900			res["left"] += objParent.offsetLeft;
4901			res["top"] += objParent.offsetTop;
4902			objParent = objParent.offsetParent;
4903		}
4904		res["right"] = res["left"] + el.offsetWidth;
4905		res["bottom"] = res["top"] + el.offsetHeight;
4906
4907		return res;
4908	},
4909
4910	FindChildObject: function(obj, tag_name, class_name, recursive)
4911	{
4912		if(!obj)
4913			return null;
4914		var tag = tag_name.toUpperCase();
4915		var cl = (class_name? class_name.toLowerCase() : null);
4916		var n = obj.childNodes.length;
4917		for(var j=0; j<n; j++)
4918		{
4919			var child = obj.childNodes[j];
4920			if(child.tagName && child.tagName.toUpperCase() == tag)
4921				if(!class_name || child.className.toLowerCase() == cl)
4922					return child;
4923			if(recursive == true)
4924			{
4925				var deepChild;
4926				if((deepChild = jsUtils.FindChildObject(child, tag_name, class_name, true)))
4927					return deepChild;
4928			}
4929		}
4930		return null;
4931	},
4932
4933	FindParentObject: function(obj, tag_name, class_name)
4934	{
4935		if(!obj)
4936			return null;
4937		var o = obj;
4938		var tag = tag_name.toUpperCase();
4939		var cl = (class_name? class_name.toLowerCase() : null);
4940		while(o.parentNode)
4941		{
4942			var parent = o.parentNode;
4943			if(parent.tagName && parent.tagName.toUpperCase() == tag)
4944				if(!class_name || parent.className.toLowerCase() == cl)
4945					return parent;
4946			o = parent;
4947		}
4948		return null;
4949	},
4950
4951	FindNextSibling: function(obj, tag_name)
4952	{
4953		if(!obj)
4954			return null;
4955		var o = obj;
4956		var tag = tag_name.toUpperCase();
4957		while(o.nextSibling)
4958		{
4959			var sibling = o.nextSibling;
4960			if(sibling.tagName && sibling.tagName.toUpperCase() == tag)
4961				return sibling;
4962			o = sibling;
4963		}
4964		return null;
4965	},
4966
4967	FindPreviousSibling: function(obj, tag_name)
4968	{
4969		if(!obj)
4970			return null;
4971		var o = obj;
4972		var tag = tag_name.toUpperCase();
4973		while(o.previousSibling)
4974		{
4975			var sibling = o.previousSibling;
4976			if(sibling.tagName && sibling.tagName.toUpperCase() == tag)
4977				return sibling;
4978			o = sibling;
4979		}
4980		return null;
4981	},
4982
4983	bOpera : navigator.userAgent.toLowerCase().indexOf('opera') != -1,
4984	bIsIE : document.attachEvent && navigator.userAgent.toLowerCase().indexOf('opera') == -1,
4985
4986	IsIE: function()
4987	{
4988		return this.bIsIE;
4989	},
4990
4991	IsOpera: function()
4992	{
4993		return this.bOpera;
4994	},
4995
4996	IsSafari: function()
4997	{
4998		var userAgent = navigator.userAgent.toLowerCase();
4999		return (/webkit/.test(userAgent));
5000	},
5001
5002	IsEditor: function()
5003	{
5004		var userAgent = navigator.userAgent.toLowerCase();
5005		var version = (userAgent.match( /.+(msie)[\/: ]([\d.]+)/ ) || [])[2];
5006		var safari = /webkit/.test(userAgent);
5007
5008		if (this.IsOpera() || (document.all && !document.compatMode && version < 6) || safari)
5009			return false;
5010
5011		return true;
5012	},
5013
5014	ToggleDiv: function(div)
5015	{
5016		var style = document.getElementById(div).style;
5017		if(style.display!="none")
5018			style.display = "none";
5019		else
5020			style.display = "block";
5021		return (style.display != "none");
5022	},
5023
5024	urlencode: function(s)
5025	{
5026		return escape(s).replace(new RegExp('\\+','g'), '%2B');
5027	},
5028
5029	OpenWindow: function(url, width, height)
5030	{
5031		var w = screen.width, h = screen.height;
5032		if(this.IsOpera())
5033		{
5034			w = document.body.offsetWidth;
5035			h = document.body.offsetHeight;
5036		}
5037		window.open(url, '', 'status=no,scrollbars=yes,resizable=yes,width='+width+',height='+height+',top='+Math.floor((h - height)/2-14)+',left='+Math.floor((w - width)/2-5));
5038	},
5039
5040	SetPageTitle: function(s)
5041	{
5042		document.title = phpVars.titlePrefix+s;
5043		var h1 = document.getElementsByTagName("H1");
5044		if(h1)
5045			h1[0].innerHTML = s;
5046	},
5047
5048	LoadPageToDiv: function(url, div_id)
5049	{
5050		var div = document.getElementById(div_id);
5051		if(!div)
5052			return;
5053		CHttpRequest.Action = function(result)
5054		{
5055			CloseWaitWindow();
5056			document.getElementById(div_id).innerHTML = result;
5057		}
5058		ShowWaitWindow();
5059		CHttpRequest.Send(url);
5060	},
5061
5062	trim: function(s)
5063	{
5064		if (typeof s == 'string' || typeof s == 'object' && s.constructor == String)
5065		{
5066			var r, re;
5067
5068			re = /^[\s\r\n]+/g;
5069			r = s.replace(re, "");
5070			re = /[\s\r\n]+$/g;
5071			r = r.replace(re, "");
5072			return r;
5073		}
5074		else
5075			return s;
5076	},
5077
5078	Redirect: function(args, url)
5079	{
5080		var e = null, bShift = false;
5081		if(args && args.length > 0)
5082			e = args[0];
5083		if(!e)
5084			e = window.event;
5085		if(e)
5086			bShift = e.shiftKey;
5087
5088		if(bShift)
5089			window.open(url);
5090		else
5091		{
5092			window.location.href=url;
5093		}
5094	},
5095
5096	False: function(){return false;},
5097
5098	AlignToPos: function(pos, w, h)
5099	{
5100		var x = pos["left"], y = pos["bottom"];
5101
5102		var scroll = jsUtils.GetWindowScrollPos();
5103		var size = jsUtils.GetWindowInnerSize();
5104
5105		if((size.innerWidth + scroll.scrollLeft) - (pos["left"] + w) < 0)
5106		{
5107			if(pos["right"] - w >= 0 )
5108				x = pos["right"] - w;
5109			else
5110				x = scroll.scrollLeft;
5111		}
5112
5113		if((size.innerHeight + scroll.scrollTop) - (pos["bottom"] + h) < 0)
5114		{
5115			if(pos["top"] - h >= 0)
5116				y = pos["top"] - h;
5117			else
5118				y = scroll.scrollTop;
5119		}
5120
5121		return {'left':x, 'top':y};
5122	},
5123
5124	// evaluate js string in window scope
5125	EvalGlobal: function(script)
5126	{
5127		try {
5128		if (window.execScript)
5129			window.execScript(script, 'javascript');
5130		else if (jsUtils.IsSafari())
5131			window.setTimeout(script, 0);
5132		else
5133			window.eval(script);
5134		} catch (e) {/*alert("Error! jsUtils.EvalGlobal");*/}
5135	},
5136
5137	GetStyleValue: function(el, styleProp)
5138	{
5139		var res;
5140		if(el.currentStyle)
5141			res = el.currentStyle[styleProp];
5142		else if(window.getComputedStyle)
5143			res = document.defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
5144		if(!res)
5145			res = '';
5146		return res;
5147	},
5148
5149	GetWindowInnerSize: function(pDoc)
5150	{
5151		var width, height;
5152		if (!pDoc)
5153			pDoc = document;
5154
5155		if (self.innerHeight) // all except Explorer
5156		{
5157			width = self.innerWidth;
5158			height = self.innerHeight;
5159		}
5160		else if (pDoc.documentElement && (pDoc.documentElement.clientHeight || pDoc.documentElement.clientWidth)) // Explorer 6 Strict Mode
5161		{
5162			width = pDoc.documentElement.clientWidth;
5163			height = pDoc.documentElement.clientHeight;
5164		}
5165		else if (pDoc.body) // other Explorers
5166		{
5167			width = pDoc.body.clientWidth;
5168			height = pDoc.body.clientHeight;
5169		}
5170		return {innerWidth : width, innerHeight : height};
5171	},
5172
5173	GetWindowScrollPos: function(pDoc)
5174	{
5175		var left, top;
5176		if (!pDoc)
5177			pDoc = document;
5178
5179		if (self.pageYOffset) // all except Explorer
5180		{
5181			left = self.pageXOffset;
5182			top = self.pageYOffset;
5183		}
5184		else if (pDoc.documentElement && (pDoc.documentElement.scrollTop || pDoc.documentElement.scrollLeft)) // Explorer 6 Strict
5185		{
5186			left = document.documentElement.scrollLeft;
5187			top = document.documentElement.scrollTop;
5188		}
5189		else if (pDoc.body) // all other Explorers
5190		{
5191			left = pDoc.body.scrollLeft;
5192			top = pDoc.body.scrollTop;
5193		}
5194		return {scrollLeft : left, scrollTop : top};
5195	},
5196
5197	GetWindowScrollSize: function(pDoc)
5198	{
5199		var width, height;
5200		if (!pDoc)
5201			pDoc = document;
5202
5203		if ( (pDoc.compatMode && pDoc.compatMode == "CSS1Compat"))
5204		{
5205			width = pDoc.documentElement.scrollWidth;
5206			height = pDoc.documentElement.scrollHeight;
5207		}
5208		else
5209		{
5210			if (pDoc.body.scrollHeight > pDoc.body.offsetHeight)
5211				height = pDoc.body.scrollHeight;
5212			else
5213				height = pDoc.body.offsetHeight;
5214
5215			if (pDoc.body.scrollWidth > pDoc.body.offsetWidth ||
5216				(pDoc.compatMode && pDoc.compatMode == "BackCompat") ||
5217				(pDoc.documentElement && !pDoc.documentElement.clientWidth)
5218			)
5219				width = pDoc.body.scrollWidth;
5220			else
5221				width = pDoc.body.offsetWidth;
5222		}
5223		return {scrollWidth : width, scrollHeight : height};
5224	},
5225
5226	GetWindowSize: function()
5227	{
5228		var innerSize = jsUtils.GetWindowInnerSize();
5229		var scrollPos = jsUtils.GetWindowScrollPos();
5230		var scrollSize = jsUtils.GetWindowScrollSize();
5231
5232		return  {
5233			innerWidth : innerSize.innerWidth, innerHeight : innerSize.innerHeight,
5234			scrollLeft : scrollPos.scrollLeft, scrollTop : scrollPos.scrollTop,
5235			scrollWidth : scrollSize.scrollWidth, scrollHeight : scrollSize.scrollHeight
5236		};
5237	},
5238
5239
5240	arCustomEvents: {},
5241
5242	addCustomEvent: function(eventName, eventHandler, arParams, handlerContextObject)
5243	{
5244		if (!this.arCustomEvents[eventName])
5245			this.arCustomEvents[eventName] = [];
5246
5247		if (!arParams)
5248			arParams = [];
5249		if (!handlerContextObject)
5250			handlerContextObject = false;
5251
5252		this.arCustomEvents[eventName].push(
5253			{
5254				handler: eventHandler,
5255				arParams: arParams,
5256				obj: handlerContextObject
5257			}
5258		);
5259	},
5260
5261	removeCustomEvent: function(eventName, eventHandler)
5262	{
5263		if (!this.arCustomEvents[eventName])
5264			return;
5265
5266		var l = this.arCustomEvents[eventName].length;
5267		if (l == 1)
5268		{
5269			delete this.arCustomEvents[eventName];
5270			return;
5271		}
5272
5273		for (var i = 0; i < l; i++)
5274		{
5275			if (!this.arCustomEvents[eventName][i])
5276				continue;
5277			if (this.arCustomEvents[eventName][i].handler == eventHandler)
5278			{
5279				delete this.arCustomEvents[eventName][i];
5280				return;
5281			}
5282		}
5283	},
5284
5285	onCustomEvent: function(eventName, arEventParams)
5286	{
5287		if (!this.arCustomEvents[eventName])
5288			return;
5289
5290		if (!arEventParams)
5291			arEventParams = [];
5292
5293		var h;
5294		for (var i = 0, l = this.arCustomEvents[eventName].length; i < l; i++)
5295		{
5296			h = this.arCustomEvents[eventName][i];
5297			if (!h || !h.handler)
5298				continue;
5299
5300			if (h.obj)
5301				h.handler.call(h.obj, h.arParams, arEventParams);
5302			else
5303				h.handler(h.arParams, arEventParams);
5304		}
5305	},
5306
5307	loadJSFile: function(arJs, oCallBack, pDoc)
5308	{
5309		if (!pDoc)
5310			pDoc = document;
5311		if (typeof arJs == 'string')
5312			arJs = [arJs];
5313		var callback = function()
5314		{
5315			if (!oCallBack)
5316				return;
5317			if (typeof oCallBack == 'function')
5318				return oCallBack();
5319			if (typeof oCallBack != 'object' || !oCallBack.func)
5320				return;
5321			var p = oCallBack.params || {};
5322			if (oCallBack.obj)
5323				oCallBack.func.apply(oCallBack.obj, p);
5324			else
5325				oCallBack.func(p);
5326		};
5327		var load_js = function(ind)
5328		{
5329			if (ind >= arJs.length)
5330				return callback();
5331			var oSript = pDoc.body.appendChild(pDoc.createElement('script'));
5332			oSript.src = arJs[ind];
5333			var bLoaded = false;
5334			oSript.onload = oSript.onreadystatechange = function()
5335			{
5336				if (!bLoaded && (!oSript.readyState || oSript.readyState == "loaded" || oSript.readyState == "complete"))
5337				{
5338					bLoaded = true;
5339					setTimeout(function (){load_js(++ind);}, 50);
5340				}
5341			};
5342		};
5343		load_js(0);
5344	},
5345
5346	loadCSSFile: function(arCSS, pDoc, pWin)
5347	{
5348		if (typeof arCSS == 'string')
5349		{
5350			var bSingle = true;
5351			arCSS = [arCSS];
5352		}
5353		var i, l = arCSS.length, pLnk = [];
5354		if (l == 0)
5355			return;
5356		if (!pDoc)
5357			pDoc = document;
5358		if (!pWin)
5359			pWin = window;
5360		if (!pWin.bxhead)
5361		{
5362			var heads = pDoc.getElementsByTagName('HEAD');
5363			pWin.bxhead = heads[0];
5364		}
5365		if (!pWin.bxhead)
5366			return;
5367		for (i = 0; i < l; i++)
5368		{
5369			var lnk = document.createElement('LINK');
5370			lnk.href = arCSS[i];
5371			lnk.rel = 'stylesheet';
5372			lnk.type = 'text/css';
5373			pWin.bxhead.appendChild(lnk);
5374			pLnk.push(lnk);
5375		}
5376		if (bSingle)
5377			return lnk;
5378		return pLnk;
5379	},
5380
5381	appendBXHint : function(node, html)
5382	{
5383		if (!node || !node.parentNode || !html)
5384			return;
5385		var oBXHint = new BXHint(html);
5386		node.parentNode.insertBefore(oBXHint.oIcon, node);
5387		node.parentNode.removeChild(node);
5388		oBXHint.oIcon.style.marginLeft = "5px";
5389	},
5390
5391	PreventDefault : function(e)
5392	{
5393		if(!e) e = window.event;
5394		if(e.stopPropagation)
5395		{
5396			e.preventDefault();
5397			e.stopPropagation();
5398		}
5399		else
5400		{
5401			e.cancelBubble = true;
5402			e.returnValue = false;
5403		}
5404		return false;
5405	},
5406
5407	CreateElement: function(tag, arAttr, arStyles, pDoc)
5408	{
5409		if (!pDoc)
5410			pDoc = document;
5411		var pEl = pDoc.createElement(tag), p;
5412		if(arAttr)
5413		{
5414			for(p in arAttr)
5415			{
5416				if(p == 'className' || p == 'class')
5417				{
5418					pEl.setAttribute('class', arAttr[p]);
5419					if (jsUtils.IsIE())
5420						pEl.setAttribute('className', arAttr[p]);
5421					continue;
5422				}
5423
5424				if (arAttr[p] != undefined && arAttr[p] != null)
5425					pEl.setAttribute(p, arAttr[p]);
5426			}
5427		}
5428		if(arStyles)
5429		{
5430			for(p in arStyles)
5431				pEl.style[p] = arStyles[p];
5432		}
5433		return pEl;
5434	},
5435
5436	in_array: function(needle, haystack)
5437	{
5438		for(var i=0; i<haystack.length; i++)
5439		{
5440			if(haystack[i] == needle)
5441				return true;
5442		}
5443		return false;
5444	},
5445
5446	htmlspecialchars: function(str)
5447	{
5448		if(!str.replace)
5449			return str;
5450
5451		return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
5452	}
5453}
5454
5455/************************************************/
5456
5457function JCFloatDiv()
5458{
5459	var _this = this;
5460	this.floatDiv = null;
5461	this.x = this.y = 0;
5462
5463	this.Create = function(arParams)
5464	{
5465		var div = document.body.appendChild(document.createElement("DIV"));
5466		div.id = arParams.id;
5467		div.style.position = 'absolute';
5468		div.style.left = '-10000px';
5469		div.style.top = '-10000px';
5470		if(arParams.className)
5471			div.className = arParams.className;
5472		if(arParams.zIndex)
5473			div.style.zIndex = arParams.zIndex;
5474		if(arParams.width)
5475			div.style.width = arParams.width+'px';
5476		if(arParams.height)
5477			div.style.height = arParams.height+'px';
5478		return div;
5479	}
5480
5481	this.Show = function(div, left, top, dxShadow, restrictDrag)
5482	{
5483		var component = BX.ZIndexManager.getComponent(div);
5484		if (!component)
5485		{
5486			BX.ZIndexManager.register(div);
5487		}
5488
5489		BX.ZIndexManager.bringToFront(div);
5490
5491		if (left < 0)
5492			left = 0;
5493
5494		if (top < 0)
5495			top = 0;
5496
5497		div.style.left = parseInt(left) + "px";
5498		div.style.top = parseInt(top) + "px";
5499
5500		/*Restrict drag*/
5501		div.restrictDrag = restrictDrag || false;
5502
5503		/*shadow*/
5504		if(isNaN(dxShadow))
5505			dxShadow = 5;
5506
5507		div.dxShadow = dxShadow;
5508	}
5509
5510	this.Close = function(div)
5511	{
5512		if(!div)
5513			return;
5514		var sh = document.getElementById(div.id+"_shadow");
5515		if(sh)
5516			sh.style.visibility = 'hidden';
5517
5518		var frame = document.getElementById(div.id+"_frame");
5519		if(frame)
5520			frame.style.visibility = 'hidden';
5521	}
5522
5523	this.Move = function(div, x, y)
5524	{
5525		if(!div)
5526			return;
5527
5528		var dxShadow = div.dxShadow;
5529		var left = parseInt(div.style.left)+x;
5530		var top = parseInt(div.style.top)+y;
5531
5532		if (div.restrictDrag)
5533		{
5534			//Left side
5535			if (left < 0)
5536				left = 0;
5537
5538			//Right side
5539			if ( (document.compatMode && document.compatMode == "CSS1Compat"))
5540				windowWidth = document.documentElement.scrollWidth;
5541			else
5542			{
5543				if (document.body.scrollWidth > document.body.offsetWidth ||
5544					(document.compatMode && document.compatMode == "BackCompat") ||
5545					(document.documentElement && !document.documentElement.clientWidth)
5546				)
5547					windowWidth = document.body.scrollWidth;
5548				else
5549					windowWidth = document.body.offsetWidth;
5550			}
5551
5552			var floatWidth = div.offsetWidth;
5553			if (left > (windowWidth - floatWidth - dxShadow))
5554				left = windowWidth - floatWidth - dxShadow;
5555
5556			//Top side
5557			if (top < 0)
5558				top = 0;
5559		}
5560
5561		div.style.left = left+'px';
5562		div.style.top = top+'px';
5563
5564		this.AdjustShadow(div);
5565	}
5566
5567	this.HideShadow = function(div)
5568	{
5569		var sh = document.getElementById(div.id + "_shadow");
5570		sh.style.visibility = 'hidden';
5571	}
5572
5573	this.UnhideShadow = function(div)
5574	{
5575		var sh = document.getElementById(div.id + "_shadow");
5576		sh.style.visibility = 'visible';
5577	}
5578
5579	this.AdjustShadow = function(div)
5580	{
5581		var sh = document.getElementById(div.id + "_shadow");
5582		if(sh && sh.style.visibility != 'hidden')
5583		{
5584			var dxShadow = div.dxShadow;
5585
5586			sh.style.width = div.offsetWidth+'px';
5587			sh.style.height = div.offsetHeight+'px';
5588			sh.style.left = parseInt(div.style.left)+dxShadow+'px';
5589			sh.style.top = parseInt(div.style.top)+dxShadow+'px';
5590		}
5591
5592		var frame = document.getElementById(div.id+"_frame");
5593		if(frame)
5594		{
5595			frame.style.width = div.offsetWidth + "px";
5596			frame.style.height = div.offsetHeight + "px";
5597			frame.style.left = div.style.left;
5598			frame.style.top = div.style.top;
5599		}
5600	}
5601
5602	this.StartDrag = function(e, div)
5603	{
5604		if(!e)
5605			e = window.event;
5606		this.x = e.clientX + document.body.scrollLeft;
5607		this.y = e.clientY + document.body.scrollTop;
5608		this.floatDiv = div;
5609
5610		jsUtils.addEvent(document, "mousemove", this.MoveDrag);
5611		document.onmouseup = this.StopDrag;
5612		if(document.body.setCapture)
5613			document.body.setCapture();
5614
5615		document.onmousedown = jsUtils.False;
5616		var b = document.body;
5617		b.ondrag = jsUtils.False;
5618		b.onselectstart = jsUtils.False;
5619		b.style.MozUserSelect = _this.floatDiv.style.MozUserSelect = 'none';
5620		b.style.cursor = 'move';
5621	}
5622
5623	this.StopDrag = function(e)
5624	{
5625		if(document.body.releaseCapture)
5626			document.body.releaseCapture();
5627
5628		jsUtils.removeEvent(document, "mousemove", _this.MoveDrag);
5629		document.onmouseup = null;
5630
5631		this.floatDiv = null;
5632
5633		document.onmousedown = null;
5634		var b = document.body;
5635		b.ondrag = null;
5636		b.onselectstart = null;
5637		b.style.MozUserSelect = _this.floatDiv.style.MozUserSelect = '';
5638		b.style.cursor = '';
5639	}
5640
5641	this.MoveDrag = function(e)
5642	{
5643		var x = e.clientX + document.body.scrollLeft;
5644		var y = e.clientY + document.body.scrollTop;
5645
5646		if(_this.x == x && _this.y == y)
5647			return;
5648
5649		_this.Move(_this.floatDiv, (x - _this.x), (y - _this.y));
5650		_this.x = x;
5651		_this.y = y;
5652	}
5653}
5654var jsFloatDiv = new JCFloatDiv();
5655
5656/************************************************/
5657
5658var BXHint = function(innerHTML, element, addParams)
5659{
5660	this.oDivOver = false;
5661	this.timeOutID = null;
5662	this.oIcon = null;
5663	this.freeze = false;
5664	this.x = 0;
5665	this.y = 0;
5666	this.time = 700;
5667
5668	if (!innerHTML)
5669		innerHTML = "";
5670	this.Create(innerHTML, element, addParams);
5671}
5672
5673BXHint.prototype.Create = function(innerHTML, element, addParams)
5674{
5675	var
5676		_this = this,
5677		width = 0,
5678		height = 0,
5679		className = null,
5680		type = "icon";
5681	this.bWidth = true;
5682
5683	if (addParams)
5684	{
5685		if (addParams.width === false)
5686			this.bWidth = false;
5687		else if (addParams.width)
5688			width = addParams.width;
5689
5690		if (addParams.height)
5691			height = addParams.height;
5692
5693		if (addParams.className)
5694			className = addParams.className;
5695
5696		if (addParams.type && (addParams.type == "link" || addParams.type == "icon"))
5697			type = addParams.type;
5698		if (addParams.time > 0)
5699			this.time = addParams.time;
5700	}
5701
5702	if (element)
5703		type = "element";
5704
5705	if (type == "icon")
5706	{
5707		var element = document.createElement("IMG");
5708		element.src = (addParams && addParams.iconSrc) ? addParams.iconSrc : "/bitrix/themes/"+phpVars.ADMIN_THEME_ID+"/public/popup/hint.gif";
5709		element.ondrag = jsUtils.False;
5710	}
5711	else if (type == "link")
5712	{
5713		var element = document.createElement("A");
5714		element.href = "";
5715		element.onclick = function(e){return false;}
5716		element.innerHTML = "[?]";
5717	}
5718
5719	this.element = element;
5720	if (type == "element")
5721	{
5722		if(addParams && addParams.show_on_click)
5723		{
5724			jsUtils.addEvent(
5725				element,
5726				"click",
5727				function (event)
5728				{
5729					if (!event)
5730						event = window.event;
5731					_this.GetMouseXY(event);
5732					_this.timeOutID = setTimeout(function () {_this.Show(innerHTML,width,height,className) }, 10);
5733				}
5734			);
5735		}
5736		else
5737		{
5738			jsUtils.addEvent(
5739				element,
5740				"mouseover",
5741				function (event)
5742				{
5743					if (!event)
5744						event = window.event;
5745					_this.GetMouseXY(event);
5746					_this.timeOutID = setTimeout(function () {_this.Show(innerHTML,width,height,className) }, 750);
5747				}
5748			);
5749		}
5750
5751		jsUtils.addEvent(
5752			element,
5753			"mouseout",
5754			function(event)
5755			{
5756				if (_this.timeOutID)
5757					clearTimeout(_this.timeOutID);
5758				_this.SmartHide(_this);
5759			}
5760		);
5761	}
5762	else
5763	{
5764		this.oIcon = element;
5765		element.onmouseover = function(event) {if (!event) event = window.event; _this.GetMouseXY(event); _this.Show(innerHTML,width,height,className)};
5766		element.onmouseout = function() {_this.SmartHide(_this);};
5767	}
5768}
5769
5770BXHint.prototype.IsFrozen = function()
5771{
5772	return this.freeze;
5773}
5774
5775BXHint.prototype.Freeze = function()
5776{
5777	this.freeze = true;
5778	this.Hide();
5779}
5780
5781BXHint.prototype.UnFreeze = function()
5782{
5783	this.freeze = false;
5784}
5785
5786BXHint.prototype.GetMouseXY = function(event)
5787{
5788	if (event.pageX || event.pageY)
5789	{
5790		this.x = event.pageX;
5791		this.y = event.pageY;
5792	}
5793	else if (event.clientX || event.clientY)
5794	{
5795		this.x = event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
5796		this.y = event.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
5797	}
5798}
5799
5800BXHint.prototype.Show = function(innerHTML, width, height, className)
5801{
5802	//Delete previous hint
5803	var old = document.getElementById("__BXHint_div");
5804	if (old)
5805		this.Hide();
5806
5807	if (this.freeze)
5808		return;
5809
5810	var _this = this;
5811	var oDiv = document.body.appendChild(document.createElement("DIV"));
5812	oDiv.onmouseover = function(){_this.oDivOver = true};
5813	oDiv.onmouseout = function(){_this.oDivOver = false; _this.SmartHide(_this);}
5814	oDiv.id = "__BXHint_div";
5815	oDiv.className = (className) ? className : "bxhint";
5816	oDiv.style.position = 'absolute';
5817	if (width && this.bWidth)
5818		oDiv.style.width = width + "px";
5819
5820	if (height)
5821		oDiv.style.height = height + "px";
5822	oDiv.innerHTML = innerHTML;
5823
5824	var w = oDiv.offsetWidth;
5825	var h = oDiv.offsetHeight;
5826	if (this.bWidth)
5827	{
5828		if (!width && w>200)
5829			w = Math.round(Math.sqrt(1.618*w*h));
5830		oDiv.style.width = w + "px";
5831		h = oDiv.offsetHeight;
5832	}
5833
5834	var pos = {left : this.x + 10, right : this.x + w, top : this.y, bottom : this.y + h};
5835
5836	pos = this.AlignToPos(pos, w, h);
5837
5838	jsFloatDiv.Show(oDiv, pos.left, pos.top,3);
5839
5840//	oDiv.ondrag = jsUtils.False;
5841//	oDiv.onselectstart = jsUtils.False;
5842//	oDiv.style.MozUserSelect = 'none';
5843	oDiv = null;
5844}
5845
5846BXHint.prototype.AlignToPos = function(pos, w, h)
5847{
5848	var body = document.body;
5849	if((body.clientWidth + body.scrollLeft) < (pos.left + w))
5850		pos.left = (pos.left - w >= 0) ? (pos.left - w) : body.scrollLeft;
5851
5852	if((body.clientHeight + body.scrollTop) - (pos["bottom"]) < 0)
5853		pos.top = (pos.top - h >= 0) ? (pos.top - h) : body.scrollTop;
5854
5855	return pos;
5856}
5857
5858BXHint.prototype.Hide = function()
5859{
5860	var oDiv = document.getElementById("__BXHint_div");
5861
5862	if (!oDiv)
5863		return;
5864
5865	BX.ZIndexManager.unregister(oDiv);
5866
5867	jsFloatDiv.Close(oDiv);
5868	oDiv.parentNode.removeChild(oDiv);
5869	oDiv = null;
5870}
5871
5872BXHint.prototype.SmartHide = function(_this)
5873{
5874	setTimeout(function ()
5875		{
5876			if (!_this.oDivOver)
5877				_this.Hide();
5878		}, 100
5879	);
5880}
5881
5882/************************************************/
5883
5884function WaitOnKeyPress(e)
5885{
5886	if(!e) e = window.event
5887	if(!e) return;
5888	if(e.keyCode == 27)
5889		CloseWaitWindow();
5890}
5891
5892function ShowWaitWindow()
5893{
5894	CloseWaitWindow();
5895
5896	var obWndSize = jsUtils.GetWindowSize();
5897
5898	var div = document.body.appendChild(document.createElement("DIV"));
5899	div.id = "wait_window_div";
5900	div.innerHTML = phpVars.messLoading;
5901	div.className = "waitwindow";
5902	//div.style.left = obWndSize.scrollLeft + (obWndSize.innerWidth - div.offsetWidth) - (jsUtils.IsIE() ? 5 : 20) + "px";
5903	div.style.right = (5 - obWndSize.scrollLeft) + 'px';
5904	div.style.top = obWndSize.scrollTop + 5 + "px";
5905
5906	if(jsUtils.IsIE())
5907	{
5908		var frame = document.createElement("IFRAME");
5909		frame.src = "javascript:''";
5910		frame.id = "wait_window_frame";
5911		frame.className = "waitwindow";
5912		frame.style.width = div.offsetWidth + "px";
5913		frame.style.height = div.offsetHeight + "px";
5914		frame.style.right = div.style.right;
5915		frame.style.top = div.style.top;
5916		document.body.appendChild(frame);
5917	}
5918	jsUtils.addEvent(document, "keypress", WaitOnKeyPress);
5919}
5920
5921function CloseWaitWindow()
5922{
5923	jsUtils.removeEvent(document, "keypress", WaitOnKeyPress);
5924
5925	var frame = document.getElementById("wait_window_frame");
5926	if(frame)
5927		frame.parentNode.removeChild(frame);
5928
5929	var div = document.getElementById("wait_window_div");
5930	if(div)
5931		div.parentNode.removeChild(div);
5932}
5933
5934/************************************************/
5935
5936var jsSelectUtils =
5937{
5938	addNewOption: function(select_id, opt_value, opt_name, do_sort, check_unique)
5939	{
5940		var oSelect = (typeof(select_id) == 'string' || select_id instanceof String? document.getElementById(select_id) : select_id);
5941		if(oSelect)
5942		{
5943			var n = oSelect.length;
5944			if(check_unique !== false)
5945			{
5946				for(var i=0;i<n;i++)
5947					if(oSelect[i].value==opt_value)
5948						return;
5949			}
5950			var newoption = new Option(opt_name, opt_value, false, false);
5951			oSelect.options[n]=newoption;
5952		}
5953		if(do_sort === true)
5954			this.sortSelect(select_id);
5955	},
5956
5957	deleteOption: function(select_id, opt_value)
5958	{
5959		var oSelect = (typeof(select_id) == 'string' || select_id instanceof String? document.getElementById(select_id) : select_id);
5960		if(oSelect)
5961		{
5962			for(var i=0;i<oSelect.length;i++)
5963				if(oSelect[i].value==opt_value)
5964				{
5965					oSelect.remove(i);
5966					break;
5967				}
5968		}
5969	},
5970
5971	deleteSelectedOptions: function(select_id)
5972	{
5973		var oSelect = (typeof(select_id) == 'string' || select_id instanceof String? document.getElementById(select_id) : select_id);
5974		if(oSelect)
5975		{
5976			var i=0;
5977			while(i<oSelect.length)
5978				if(oSelect[i].selected)
5979				{
5980					oSelect[i].selected=false;
5981					oSelect.remove(i);
5982				}
5983				else
5984					i++;
5985		}
5986	},
5987
5988	deleteAllOptions: function(oSelect)
5989	{
5990		if(oSelect)
5991		{
5992			for(var i=oSelect.length-1; i>=0; i--)
5993				oSelect.remove(i);
5994		}
5995	},
5996
5997	optionCompare: function(record1, record2)
5998	{
5999		var value1 = record1.optText.toLowerCase();
6000		var value2 = record2.optText.toLowerCase();
6001		if (value1 > value2) return(1);
6002		if (value1 < value2) return(-1);
6003		return(0);
6004	},
6005
6006	sortSelect: function(select_id)
6007	{
6008		var oSelect = (typeof(select_id) == 'string' || select_id instanceof String? document.getElementById(select_id) : select_id);
6009		if(oSelect)
6010		{
6011			var myOptions = [];
6012			var n = oSelect.options.length;
6013			for (var i=0;i<n;i++)
6014			{
6015				myOptions[i] = {
6016					optText:oSelect[i].text,
6017					optValue:oSelect[i].value
6018				};
6019			}
6020			myOptions.sort(this.optionCompare);
6021			oSelect.length=0;
6022			n = myOptions.length;
6023			for(var i=0;i<n;i++)
6024			{
6025				var newoption = new Option(myOptions[i].optText, myOptions[i].optValue, false, false);
6026				oSelect[i]=newoption;
6027			}
6028		}
6029	},
6030
6031	selectAllOptions: function(select_id)
6032	{
6033		var oSelect = (typeof(select_id) == 'string' || select_id instanceof String? document.getElementById(select_id) : select_id);
6034		if(oSelect)
6035		{
6036			var n = oSelect.length;
6037			for(var i=0;i<n;i++)
6038				oSelect[i].selected=true;
6039		}
6040	},
6041
6042	selectOption: function(select_id, opt_value)
6043	{
6044		var oSelect = (typeof(select_id) == 'string' || select_id instanceof String? document.getElementById(select_id) : select_id);
6045		if(oSelect)
6046		{
6047			var n = oSelect.length;
6048			for(var i=0;i<n;i++)
6049				oSelect[i].selected = (oSelect[i].value == opt_value);
6050		}
6051	},
6052
6053	addSelectedOptions: function(oSelect, to_select_id, check_unique, do_sort)
6054	{
6055		if(!oSelect)
6056			return;
6057		var n = oSelect.length;
6058		for(var i=0; i<n; i++)
6059			if(oSelect[i].selected)
6060				this.addNewOption(to_select_id, oSelect[i].value, oSelect[i].text, do_sort, check_unique);
6061	},
6062
6063	moveOptionsUp: function(oSelect)
6064	{
6065		if(!oSelect)
6066			return;
6067		var n = oSelect.length;
6068		for(var i=0; i<n; i++)
6069		{
6070			if(oSelect[i].selected && i>0 && oSelect[i-1].selected == false)
6071			{
6072				var option1 = new Option(oSelect[i].text, oSelect[i].value);
6073				var option2 = new Option(oSelect[i-1].text, oSelect[i-1].value);
6074				oSelect[i] = option2;
6075				oSelect[i].selected = false;
6076				oSelect[i-1] = option1;
6077				oSelect[i-1].selected = true;
6078			}
6079		}
6080	},
6081
6082	moveOptionsDown: function(oSelect)
6083	{
6084		if(!oSelect)
6085			return;
6086		var n = oSelect.length;
6087		for(var i=n-1; i>=0; i--)
6088		{
6089			if(oSelect[i].selected && i<n-1 && oSelect[i+1].selected == false)
6090			{
6091				var option1 = new Option(oSelect[i].text, oSelect[i].value);
6092				var option2 = new Option(oSelect[i+1].text, oSelect[i+1].value);
6093				oSelect[i] = option2;
6094				oSelect[i].selected = false;
6095				oSelect[i+1] = option1;
6096				oSelect[i+1].selected = true;
6097			}
6098		}
6099	}
6100
6101}
6102
6103/************************************************/
6104
6105/* End */
6106;
6107; /* Start:"a:4:{s:4:"full";s:49:"/bitrix/js/main/date/main.date.js?167415717634530";s:6:"source";s:33:"/bitrix/js/main/date/main.date.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
6108;(function(window)
6109{
6110	/****************** ATTENTION *******************************
6111	 * Please do not use Bitrix CoreJS in this class.
6112	 * This class can be called on page without Bitrix Framework
6113	*************************************************************/
6114
6115	if (!window.BX)
6116	{
6117		window.BX = {};
6118	}
6119
6120	if (!window.BX.Main)
6121	{
6122		window.BX.Main = {};
6123	}
6124	else if (window.BX.Main.Date)
6125	{
6126		return;
6127	}
6128
6129	var BX = window.BX;
6130
6131	BX.Main.Date = {
6132
6133		AM_PM_MODE: {
6134			UPPER: 1,
6135			LOWER: 2,
6136			NONE: false
6137		},
6138
6139		format: function(format, timestamp, now, utc)
6140		{
6141			var _this = this;
6142
6143			/*
6144			PHP to Javascript:
6145				time() = new Date()
6146				mktime(...) = new Date(...)
6147				gmmktime(...) = new Date(Date.UTC(...))
6148				mktime(0,0,0, 1, 1, 1970) != 0          new Date(1970,0,1).getTime() != 0
6149				gmmktime(0,0,0, 1, 1, 1970) == 0        new Date(Date.UTC(1970,0,1)).getTime() == 0
6150				date("d.m.Y H:i:s") = BX.Main.Date.format("d.m.Y H:i:s")
6151				gmdate("d.m.Y H:i:s") = BX.Main.Date.format("d.m.Y H:i:s", null, null, true);
6152			*/
6153			var date = Utils.isDate(timestamp) ? new Date(timestamp.getTime()) : Utils.isNumber(timestamp) ? new Date(timestamp * 1000) : new Date();
6154			var nowDate = Utils.isDate(now) ? new Date(now.getTime()) : Utils.isNumber(now) ? new Date(now * 1000) : new Date();
6155			var isUTC = !!utc;
6156
6157			if (Utils.isArray(format))
6158				return _formatDateInterval(format, date, nowDate, isUTC);
6159			else if (!Utils.isNotEmptyString(format))
6160				return "";
6161
6162			var replaceMap = (format.match(/{{([^{}]*)}}/g) || []).map(function(x) { return (x.match(/[^{}]+/) || [''])[0]; });
6163			if (replaceMap.length > 0)
6164			{
6165				replaceMap.forEach(function(element, index) {
6166					format = format.replace("{{"+element+"}}", "{{"+index+"}}");
6167				});
6168			}
6169
6170			var formatRegex = /\\?(sago|iago|isago|Hago|dago|mago|Yago|sdiff|idiff|Hdiff|ddiff|mdiff|Ydiff|sshort|ishort|Hshort|dshort|mhort|Yshort|yesterday|today|tommorow|tomorrow|[a-z])/gi;
6171
6172			var dateFormats = {
6173				d : function() {
6174					// Day of the month 01 to 31
6175					return Utils.strPadLeft(getDate(date).toString(), 2, "0");
6176				},
6177
6178				D : function() {
6179					//Mon through Sun
6180					return _this._getMessage("DOW_" + getDay(date));
6181				},
6182
6183				j : function() {
6184					//Day of the month 1 to 31
6185					return getDate(date);
6186				},
6187
6188				l : function() {
6189					//Sunday through Saturday
6190					return _this._getMessage("DAY_OF_WEEK_" + getDay(date));
6191				},
6192
6193				N : function() {
6194					//1 (for Monday) through 7 (for Sunday)
6195					return getDay(date) || 7;
6196				},
6197
6198				S : function() {
6199					//st, nd, rd or th. Works well with j
6200					if (getDate(date) % 10 == 1 && getDate(date) != 11)
6201						return "st";
6202					else if (getDate(date) % 10 == 2 && getDate(date) != 12)
6203						return "nd";
6204					else if (getDate(date) % 10 == 3 && getDate(date) != 13)
6205						return "rd";
6206					else
6207						return "th";
6208				},
6209
6210				w : function() {
6211					//0 (for Sunday) through 6 (for Saturday)
6212					return getDay(date);
6213				},
6214
6215				z : function() {
6216					//0 through 365
6217					var firstDay = new Date(getFullYear(date), 0, 1);
6218					var currentDay = new Date(getFullYear(date), getMonth(date), getDate(date));
6219					return Math.ceil( (currentDay - firstDay) / (24 * 3600 * 1000) );
6220				},
6221
6222				W : function() {
6223					//ISO-8601 week number of year
6224					var newDate  = new Date(date.getTime());
6225					var dayNumber   = (getDay(date) + 6) % 7;
6226					setDate(newDate, getDate(newDate) - dayNumber + 3);
6227					var firstThursday = newDate.getTime();
6228					setMonth(newDate, 0, 1);
6229					if (getDay(newDate) != 4)
6230						setMonth(newDate, 0, 1 + ((4 - getDay(newDate)) + 7) % 7);
6231					var weekNumber = 1 + Math.ceil((firstThursday - newDate) / (7 * 24 * 3600 * 1000));
6232					return Utils.strPadLeft(weekNumber.toString(), 2, "0");
6233				},
6234
6235				F : function() {
6236					//January through December
6237					return _this._getMessage("MONTH_" + (getMonth(date) + 1) + "_S");
6238				},
6239
6240				f : function() {
6241					//January through December
6242					return _this._getMessage("MONTH_" + (getMonth(date) + 1));
6243				},
6244
6245				m : function() {
6246					//Numeric representation of a month 01 through 12
6247					return Utils.strPadLeft((getMonth(date) + 1).toString(), 2, "0");
6248				},
6249
6250				M : function() {
6251					//A short textual representation of a month, three letters Jan through Dec
6252					return _this._getMessage("MON_" + (getMonth(date) + 1));
6253				},
6254
6255				n : function() {
6256					//Numeric representation of a month 1 through 12
6257					return getMonth(date) + 1;
6258				},
6259
6260				t : function() {
6261					//Number of days in the given month 28 through 31
6262					var lastMonthDay = isUTC ? new Date(Date.UTC(getFullYear(date), getMonth(date) + 1, 0)) : new Date(getFullYear(date), getMonth(date) + 1, 0);
6263					return getDate(lastMonthDay);
6264				},
6265
6266				L : function() {
6267					//1 if it is a leap year, 0 otherwise.
6268					var year = getFullYear(date);
6269					return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0 ? 1 : 0);
6270				},
6271
6272				o : function() {
6273					//ISO-8601 year number
6274					var correctDate  = new Date(date.getTime());
6275					setDate(correctDate, getDate(correctDate) - ((getDay(date) + 6) % 7) + 3);
6276					return getFullYear(correctDate);
6277				},
6278
6279				Y : function() {
6280					//A full numeric representation of a year, 4 digits
6281					return getFullYear(date);
6282				},
6283
6284				y : function() {
6285					//A two digit representation of a year
6286					return getFullYear(date).toString().slice(2);
6287				},
6288
6289				a : function() {
6290					//am or pm
6291					return getHours(date) > 11 ? "pm" : "am";
6292				},
6293
6294				A : function() {
6295					//AM or PM
6296					return getHours(date) > 11 ? "PM" : "AM";
6297				},
6298
6299				B : function() {
6300					//000 through 999
6301					var swatch = ((date.getUTCHours() + 1) % 24) + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;
6302					return Utils.strPadLeft(Math.floor(swatch * 1000 / 24).toString(), 3, "0");
6303				},
6304
6305				g : function() {
6306					//12-hour format of an hour without leading zeros 1 through 12
6307					return getHours(date) % 12 || 12;
6308				},
6309
6310				G : function() {
6311					//24-hour format of an hour without leading zeros 0 through 23
6312					return getHours(date);
6313				},
6314
6315				h : function() {
6316					//12-hour format of an hour with leading zeros 01 through 12
6317					return Utils.strPadLeft((getHours(date) % 12 || 12).toString(), 2, "0");
6318				},
6319
6320				H : function() {
6321					//24-hour format of an hour with leading zeros 00 through 23
6322					return Utils.strPadLeft(getHours(date).toString(), 2, "0");
6323				},
6324
6325				i : function() {
6326					//Minutes with leading zeros 00 to 59
6327					return Utils.strPadLeft(getMinutes(date).toString(), 2, "0");
6328				},
6329
6330				s : function() {
6331					//Seconds, with leading zeros 00 through 59
6332					return Utils.strPadLeft(getSeconds(date).toString(), 2, "0");
6333				},
6334
6335				u : function() {
6336					//Microseconds
6337					return Utils.strPadLeft((getMilliseconds(date) * 1000).toString(), 6, "0");
6338				},
6339
6340				e : function() {
6341					if (isUTC)
6342						return "UTC";
6343					return "";
6344				},
6345
6346				I : function() {
6347					if (isUTC)
6348						return 0;
6349
6350					//Whether or not the date is in daylight saving time 1 if Daylight Saving Time, 0 otherwise
6351					var firstJanuary = new Date(getFullYear(date), 0, 1);
6352					var firstJanuaryUTC = Date.UTC(getFullYear(date), 0, 1);
6353					var firstJuly = new Date(getFullYear(date), 6, 0);
6354					var firstJulyUTC = Date.UTC(getFullYear(date), 6, 0);
6355					return 0 + ((firstJanuary - firstJanuaryUTC) !== (firstJuly - firstJulyUTC));
6356				},
6357
6358				O : function() {
6359					if (isUTC)
6360						return "+0000";
6361
6362					//Difference to Greenwich time (GMT) in hours +0200
6363					var timezoneOffset = date.getTimezoneOffset();
6364					var timezoneOffsetAbs = Math.abs(timezoneOffset);
6365					return (timezoneOffset > 0 ? "-" : "+") + Utils.strPadLeft((Math.floor(timezoneOffsetAbs / 60) * 100 + timezoneOffsetAbs % 60).toString(), 4, "0");
6366				},
6367
6368				P : function() {
6369					if (isUTC)
6370						return "+00:00";
6371
6372					//Difference to Greenwich time (GMT) with colon between hours and minutes +02:00
6373					var difference = this.O();
6374					return difference.substr(0, 3) + ":" + difference.substr(3);
6375				},
6376
6377				Z : function() {
6378					if (isUTC)
6379						return 0;
6380					//Timezone offset in seconds. The offset for timezones west of UTC is always negative,
6381					//and for those east of UTC is always positive.
6382					return -date.getTimezoneOffset() * 60;
6383				},
6384
6385				c : function() {
6386					//ISO 8601 date
6387					return "Y-m-d\\TH:i:sP".replace(formatRegex, _replaceDateFormat);
6388				},
6389
6390				r : function() {
6391					//RFC 2822 formatted date
6392					return "D, d M Y H:i:s O".replace(formatRegex, _replaceDateFormat);
6393				},
6394
6395				U : function() {
6396					//Seconds since the Unix Epoch
6397					return Math.floor(date.getTime() / 1000);
6398				},
6399
6400				sago : function() {
6401					return _formatDateMessage(intval((nowDate - date) / 1000), {
6402						"0" : "FD_SECOND_AGO_0",
6403						"1" : "FD_SECOND_AGO_1",
6404						"10_20" : "FD_SECOND_AGO_10_20",
6405						"MOD_1" : "FD_SECOND_AGO_MOD_1",
6406						"MOD_2_4" : "FD_SECOND_AGO_MOD_2_4",
6407						"MOD_OTHER" : "FD_SECOND_AGO_MOD_OTHER"
6408					});
6409				},
6410
6411				sdiff : function() {
6412					return _formatDateMessage(intval((nowDate - date) / 1000), {
6413						"0" : "FD_SECOND_DIFF_0",
6414						"1" : "FD_SECOND_DIFF_1",
6415						"10_20" : "FD_SECOND_DIFF_10_20",
6416						"MOD_1" : "FD_SECOND_DIFF_MOD_1",
6417						"MOD_2_4" : "FD_SECOND_DIFF_MOD_2_4",
6418						"MOD_OTHER" : "FD_SECOND_DIFF_MOD_OTHER"
6419					});
6420				},
6421
6422				sshort : function() {
6423					return _this._getMessage("FD_SECOND_SHORT").replace(/#VALUE#/g, intval((nowDate - date) / 1000));
6424				},
6425
6426				iago : function() {
6427					return _formatDateMessage(intval((nowDate - date) / 60 / 1000), {
6428						"0" : "FD_MINUTE_AGO_0",
6429						"1" : "FD_MINUTE_AGO_1",
6430						"10_20" : "FD_MINUTE_AGO_10_20",
6431						"MOD_1" : "FD_MINUTE_AGO_MOD_1",
6432						"MOD_2_4" : "FD_MINUTE_AGO_MOD_2_4",
6433						"MOD_OTHER" : "FD_MINUTE_AGO_MOD_OTHER"
6434					});
6435				},
6436
6437				idiff : function() {
6438					return _formatDateMessage(intval((nowDate - date) / 60 / 1000), {
6439						"0" : "FD_MINUTE_DIFF_0",
6440						"1" : "FD_MINUTE_DIFF_1",
6441						"10_20" : "FD_MINUTE_DIFF_10_20",
6442						"MOD_1" : "FD_MINUTE_DIFF_MOD_1",
6443						"MOD_2_4" : "FD_MINUTE_DIFF_MOD_2_4",
6444						"MOD_OTHER" : "FD_MINUTE_DIFF_MOD_OTHER"
6445					});
6446				},
6447
6448				isago : function() {
6449					var minutesAgo = intval((nowDate - date) / 60 / 1000);
6450					var result = _formatDateMessage(minutesAgo, {
6451						"0" : "FD_MINUTE_0",
6452						"1" : "FD_MINUTE_1",
6453						"10_20" : "FD_MINUTE_10_20",
6454						"MOD_1" : "FD_MINUTE_MOD_1",
6455						"MOD_2_4" : "FD_MINUTE_MOD_2_4",
6456						"MOD_OTHER" : "FD_MINUTE_MOD_OTHER"
6457					});
6458
6459					result += " ";
6460
6461					var secondsAgo = intval((nowDate - date) / 1000) - (minutesAgo * 60);
6462					result += _formatDateMessage(secondsAgo, {
6463						"0" : "FD_SECOND_AGO_0",
6464						"1" : "FD_SECOND_AGO_1",
6465						"10_20" : "FD_SECOND_AGO_10_20",
6466						"MOD_1" : "FD_SECOND_AGO_MOD_1",
6467						"MOD_2_4" : "FD_SECOND_AGO_MOD_2_4",
6468						"MOD_OTHER" : "FD_SECOND_AGO_MOD_OTHER"
6469					});
6470					return result;
6471				},
6472
6473				ishort : function() {
6474					return _this._getMessage("FD_MINUTE_SHORT").replace(/#VALUE#/g, intval((nowDate - date) / 60 / 1000));
6475				},
6476
6477				Hago : function() {
6478					return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 1000), {
6479						"0" : "FD_HOUR_AGO_0",
6480						"1" : "FD_HOUR_AGO_1",
6481						"10_20" : "FD_HOUR_AGO_10_20",
6482						"MOD_1" : "FD_HOUR_AGO_MOD_1",
6483						"MOD_2_4" : "FD_HOUR_AGO_MOD_2_4",
6484						"MOD_OTHER" : "FD_HOUR_AGO_MOD_OTHER"
6485					});
6486				},
6487
6488				Hdiff : function() {
6489					return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 1000), {
6490						"0" : "FD_HOUR_DIFF_0",
6491						"1" : "FD_HOUR_DIFF_1",
6492						"10_20" : "FD_HOUR_DIFF_10_20",
6493						"MOD_1" : "FD_HOUR_DIFF_MOD_1",
6494						"MOD_2_4" : "FD_HOUR_DIFF_MOD_2_4",
6495						"MOD_OTHER" : "FD_HOUR_DIFF_MOD_OTHER"
6496					});
6497				},
6498
6499				Hshort : function() {
6500					return _this._getMessage("FD_HOUR_SHORT").replace(/#VALUE#/g, intval((nowDate - date) / 60 / 60 / 1000));
6501				},
6502
6503				yesterday : function() {
6504					return _this._getMessage("FD_YESTERDAY");
6505				},
6506
6507				today : function() {
6508					return _this._getMessage("FD_TODAY");
6509				},
6510
6511				tommorow : function() {
6512					return _this._getMessage("FD_TOMORROW");
6513				},
6514
6515				tomorrow : function() {
6516					return _this._getMessage("FD_TOMORROW");
6517				},
6518
6519				dago : function() {
6520					return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 1000), {
6521						"0" : "FD_DAY_AGO_0",
6522						"1" : "FD_DAY_AGO_1",
6523						"10_20" : "FD_DAY_AGO_10_20",
6524						"MOD_1" : "FD_DAY_AGO_MOD_1",
6525						"MOD_2_4" : "FD_DAY_AGO_MOD_2_4",
6526						"MOD_OTHER" : "FD_DAY_AGO_MOD_OTHER"
6527					});
6528				},
6529
6530				ddiff : function() {
6531					return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 1000), {
6532						"0" : "FD_DAY_DIFF_0",
6533						"1" : "FD_DAY_DIFF_1",
6534						"10_20" : "FD_DAY_DIFF_10_20",
6535						"MOD_1" : "FD_DAY_DIFF_MOD_1",
6536						"MOD_2_4" : "FD_DAY_DIFF_MOD_2_4",
6537						"MOD_OTHER" : "FD_DAY_DIFF_MOD_OTHER"
6538					});
6539				},
6540
6541				dshort : function() {
6542					return _this._getMessage("FD_DAY_SHORT").replace(/#VALUE#/g, intval((nowDate - date) / 60 / 60 / 24 / 1000));
6543				},
6544
6545				mago : function() {
6546					return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 31 / 1000), {
6547						"0" : "FD_MONTH_AGO_0",
6548						"1" : "FD_MONTH_AGO_1",
6549						"10_20" : "FD_MONTH_AGO_10_20",
6550						"MOD_1" : "FD_MONTH_AGO_MOD_1",
6551						"MOD_2_4" : "FD_MONTH_AGO_MOD_2_4",
6552						"MOD_OTHER" : "FD_MONTH_AGO_MOD_OTHER"
6553					});
6554				},
6555
6556				mdiff : function() {
6557					return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 31 / 1000), {
6558						"0" : "FD_MONTH_DIFF_0",
6559						"1" : "FD_MONTH_DIFF_1",
6560						"10_20" : "FD_MONTH_DIFF_10_20",
6561						"MOD_1" : "FD_MONTH_DIFF_MOD_1",
6562						"MOD_2_4" : "FD_MONTH_DIFF_MOD_2_4",
6563						"MOD_OTHER" : "FD_MONTH_DIFF_MOD_OTHER"
6564					});
6565				},
6566
6567				mshort : function() {
6568					return _this._getMessage("FD_MONTH_SHORT").replace(/#VALUE#/g, intval((nowDate - date) / 60 / 60 / 24 / 31 / 1000));
6569				},
6570
6571				Yago : function() {
6572					return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 365 / 1000), {
6573						"0" : "FD_YEARS_AGO_0",
6574						"1" : "FD_YEARS_AGO_1",
6575						"10_20" : "FD_YEARS_AGO_10_20",
6576						"MOD_1" : "FD_YEARS_AGO_MOD_1",
6577						"MOD_2_4" : "FD_YEARS_AGO_MOD_2_4",
6578						"MOD_OTHER" : "FD_YEARS_AGO_MOD_OTHER"
6579					});
6580				},
6581
6582				Ydiff : function() {
6583					return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 365 / 1000), {
6584						"0" : "FD_YEARS_DIFF_0",
6585						"1" : "FD_YEARS_DIFF_1",
6586						"10_20" : "FD_YEARS_DIFF_10_20",
6587						"MOD_1" : "FD_YEARS_DIFF_MOD_1",
6588						"MOD_2_4" : "FD_YEARS_DIFF_MOD_2_4",
6589						"MOD_OTHER" : "FD_YEARS_DIFF_MOD_OTHER"
6590					});
6591				},
6592
6593				Yshort : function() {
6594					return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 365 / 1000), {
6595						"0" : "FD_YEARS_SHORT_0",
6596						"1" : "FD_YEARS_SHORT_1",
6597						"10_20" : "FD_YEARS_SHORT_10_20",
6598						"MOD_1" : "FD_YEARS_SHORT_MOD_1",
6599						"MOD_2_4" : "FD_YEARS_SHORT_MOD_2_4",
6600						"MOD_OTHER" : "FD_YEARS_SHORT_MOD_OTHER"
6601					});
6602				},
6603
6604				x : function() {
6605					var ampm = _this.isAmPmMode(true);
6606					var timeFormat = (ampm === _this.AM_PM_MODE.LOWER? "g:i a" : (ampm === _this.AM_PM_MODE.UPPER? "g:i A" : "H:i"));
6607
6608					return _this.format([
6609						["tomorrow", "tomorrow, "+timeFormat],
6610						["-", _this.convertBitrixFormat(_this._getMessage("FORMAT_DATETIME")).replace(/:s/g, "")],
6611						["s", "sago"],
6612						["i", "iago"],
6613						["today", "today, "+timeFormat],
6614						["yesterday", "yesterday, "+timeFormat],
6615						["", _this.convertBitrixFormat(_this._getMessage("FORMAT_DATETIME")).replace(/:s/g, "")]
6616					], date, nowDate, isUTC);
6617				},
6618
6619				X : function() {
6620
6621					var ampm = _this.isAmPmMode(true);
6622					var timeFormat = (ampm === _this.AM_PM_MODE.LOWER? "g:i a" : (ampm === _this.AM_PM_MODE.UPPER? "g:i A" : "H:i"));
6623
6624					var day = _this.format([
6625						["tomorrow", "tomorrow"],
6626						["-", _this.convertBitrixFormat(_this._getMessage("FORMAT_DATE"))],
6627						["today", "today"],
6628						["yesterday", "yesterday"],
6629						["", _this.convertBitrixFormat(_this._getMessage("FORMAT_DATE"))]
6630					], date, nowDate, isUTC);
6631
6632					var time = _this.format([
6633						["tomorrow", timeFormat],
6634						["today", timeFormat],
6635						["yesterday", timeFormat],
6636						["", ""]
6637					], date, nowDate, isUTC);
6638
6639					if (time.length > 0)
6640						return _this._getMessage("FD_DAY_AT_TIME").replace(/#DAY#/g, day).replace(/#TIME#/g, time);
6641					else
6642						return day;
6643				},
6644
6645				Q : function() {
6646					var daysAgo = intval((nowDate - date) / 60 / 60 / 24 / 1000);
6647					if(daysAgo == 0)
6648						return _this._getMessage("FD_DAY_DIFF_1").replace(/#VALUE#/g, 1);
6649					else
6650						return _this.format([ ["d", "ddiff"], ["m", "mdiff"], ["", "Ydiff"] ], date, nowDate);
6651				}
6652			};
6653
6654			var cutZeroTime = false;
6655			if (format[0] && format[0] == "^")
6656			{
6657				cutZeroTime = true;
6658				format = format.substr(1);
6659			}
6660
6661			var result = format.replace(formatRegex, _replaceDateFormat);
6662
6663			if (cutZeroTime)
6664			{
6665				/* 	15.04.12 13:00:00 => 15.04.12 13:00
6666					00:01:00 => 00:01
6667					4 may 00:00:00 => 4 may
6668					01-01-12 00:00 => 01-01-12
6669				*/
6670
6671				result = result.replace(/\s*00:00:00\s*/g, "").
6672								replace(/(\d\d:\d\d)(:00)/g, "$1").
6673								replace(/(\s*00:00\s*)(?!:)/g, "");
6674			}
6675
6676			if (replaceMap.length > 0)
6677			{
6678				replaceMap.forEach(function(element, index) {
6679					result = result.replace("{{"+index+"}}", element);
6680				});
6681			}
6682
6683			return result;
6684
6685			function _formatDateInterval(formats, date, nowDate, isUTC)
6686			{
6687				var secondsAgo = intval((nowDate - date) / 1000);
6688				for (var i = 0; i < formats.length; i++)
6689				{
6690					var formatInterval = formats[i][0];
6691					var formatValue = formats[i][1];
6692					var match = null;
6693					if (formatInterval == "s")
6694					{
6695						if (secondsAgo < 60)
6696							return _this.format(formatValue, date, nowDate, isUTC);
6697					}
6698					else if ((match = /^s(\d+)\>?(\d+)?/.exec(formatInterval)) != null)
6699					{
6700						if (match[1] && match[2])
6701						{
6702							if (
6703								secondsAgo < match[1]
6704								&& secondsAgo > match[2]
6705							)
6706							{
6707								return _this.format(formatValue, date, nowDate, isUTC);
6708							}
6709						}
6710						else if (secondsAgo < match[1])
6711						{
6712							return _this.format(formatValue, date, nowDate, isUTC);
6713						}
6714					}
6715					else if (formatInterval == "i")
6716					{
6717						if (secondsAgo < 60 * 60)
6718							return _this.format(formatValue, date, nowDate, isUTC);
6719					}
6720					else if ((match = /^i(\d+)\>?(\d+)?/.exec(formatInterval)) != null)
6721					{
6722						if (match[1] && match[2])
6723						{
6724							if (
6725								secondsAgo < match[1] * 60
6726								&& secondsAgo > match[2] * 60
6727							)
6728							{
6729								return _this.format(formatValue, date, nowDate, isUTC);
6730							}
6731						}
6732						else if (secondsAgo < match[1] * 60)
6733						{
6734							return _this.format(formatValue, date, nowDate, isUTC);
6735						}
6736					}
6737					else if (formatInterval == "H")
6738					{
6739						if (secondsAgo < 24 * 60 * 60)
6740							return _this.format(formatValue, date, nowDate, isUTC);
6741					}
6742					else if ((match = /^H(\d+)\>?(\d+)?/.exec(formatInterval)) != null)
6743					{
6744						if (match[1] && match[2])
6745						{
6746							if (
6747								secondsAgo < match[1] * 60 * 60
6748								&& secondsAgo > match[2] * 60 * 60
6749							)
6750							{
6751								return _this.format(formatValue, date, nowDate, isUTC);
6752							}
6753						}
6754						else if (secondsAgo < match[1] * 60 * 60)
6755						{
6756							return _this.format(formatValue, date, nowDate, isUTC);
6757						}
6758					}
6759					else if (formatInterval == "d")
6760					{
6761						if (secondsAgo < 31 *24 * 60 * 60)
6762							return _this.format(formatValue, date, nowDate, isUTC);
6763					}
6764					else if ((match = /^d(\d+)\>?(\d+)?/.exec(formatInterval)) != null)
6765					{
6766						if (match[1] && match[2])
6767						{
6768							if (
6769								secondsAgo < match[1] * 24 * 60 * 60
6770								&& secondsAgo > match[2] * 24 * 60 * 60
6771							)
6772							{
6773								return _this.format(formatValue, date, nowDate, isUTC);
6774							}
6775						}
6776						else if (secondsAgo < match[1] * 24 * 60 * 60)
6777						{
6778							return _this.format(formatValue, date, nowDate, isUTC);
6779						}
6780					}
6781					else if (formatInterval == "m")
6782					{
6783						if (secondsAgo < 365 * 24 * 60 * 60)
6784							return _this.format(formatValue, date, nowDate, isUTC);
6785					}
6786					else if ((match = /^m(\d+)\>?(\d+)?/.exec(formatInterval)) != null)
6787					{
6788						if (match[1] && match[2])
6789						{
6790							if (
6791								secondsAgo < match[1] * 31 * 24 * 60 * 60
6792								&& secondsAgo > match[2] * 31 * 24 * 60 * 60
6793							)
6794							{
6795								return _this.format(formatValue, date, nowDate, isUTC);
6796							}
6797						}
6798						else if (secondsAgo < match[1] * 31 * 24 * 60 * 60)
6799						{
6800							return _this.format(formatValue, date, nowDate, isUTC);
6801						}
6802					}
6803					else if (formatInterval == "now")
6804					{
6805						if (date.getTime() == nowDate.getTime())
6806						{
6807							return _this.format(formatValue, date, nowDate, isUTC);
6808						}
6809					}
6810					else if (formatInterval == "today")
6811					{
6812						var year = getFullYear(nowDate), month = getMonth(nowDate), day = getDate(nowDate);
6813						var todayStart = isUTC ? new Date(Date.UTC(year, month, day, 0, 0, 0, 0)) : new Date(year, month, day, 0, 0, 0, 0);
6814						var todayEnd = isUTC ? new Date(Date.UTC(year, month, day+1, 0, 0, 0, 0)) : new Date(year, month, day+1, 0, 0, 0, 0);
6815						if (date >= todayStart && date < todayEnd)
6816							return _this.format(formatValue, date, nowDate, isUTC);
6817					}
6818					else if (formatInterval == "todayFuture")
6819					{
6820						var year = getFullYear(nowDate), month = getMonth(nowDate), day = getDate(nowDate);
6821						var todayStart = nowDate.getTime();
6822						var todayEnd = isUTC ? new Date(Date.UTC(year, month, day+1, 0, 0, 0, 0)) : new Date(year, month, day+1, 0, 0, 0, 0);
6823						if (date >= todayStart && date < todayEnd)
6824							return _this.format(formatValue, date, nowDate, isUTC);
6825					}
6826					else if (formatInterval == "yesterday")
6827					{
6828						year = getFullYear(nowDate); month = getMonth(nowDate); day = getDate(nowDate);
6829						var yesterdayStart = isUTC ? new Date(Date.UTC(year, month, day-1, 0, 0, 0, 0)) : new Date(year, month, day-1, 0, 0, 0, 0);
6830						var yesterdayEnd = isUTC ? new Date(Date.UTC(year, month, day, 0, 0, 0, 0)) : new Date(year, month, day, 0, 0, 0, 0);
6831						if (date >= yesterdayStart && date < yesterdayEnd)
6832							return _this.format(formatValue, date, nowDate, isUTC);
6833					}
6834					else if (formatInterval == "tommorow" || formatInterval == "tomorrow")
6835					{
6836						year = getFullYear(nowDate); month = getMonth(nowDate); day = getDate(nowDate);
6837						var tomorrowStart = isUTC ? new Date(Date.UTC(year, month, day+1, 0, 0, 0, 0)) : new Date(year, month, day+1, 0, 0, 0, 0);
6838						var tomorrowEnd = isUTC ? new Date(Date.UTC(year, month, day+2, 0, 0, 0, 0)) : new Date(year, month, day+2, 0, 0, 0, 0);
6839						if (date >= tomorrowStart && date < tomorrowEnd)
6840							return _this.format(formatValue, date, nowDate, isUTC);
6841					}
6842					else if (formatInterval == "-")
6843					{
6844						if (secondsAgo < 0)
6845							return _this.format(formatValue, date, nowDate, isUTC);
6846					}
6847				}
6848
6849				//return formats.length > 0 ? _this.format(formats.pop()[1], date, nowDate, isUTC) : "";
6850				return formats.length > 0 ? _this.format(formats[formats.length - 1][1], date, nowDate, isUTC) : "";
6851			}
6852
6853			function getFullYear(date) { return isUTC ? date.getUTCFullYear() : date.getFullYear(); }
6854			function getDate(date) { return isUTC ? date.getUTCDate() : date.getDate(); }
6855			function getMonth(date) { return isUTC ? date.getUTCMonth() : date.getMonth(); }
6856			function getHours(date) { return isUTC ? date.getUTCHours() : date.getHours(); }
6857			function getMinutes(date) { return isUTC ? date.getUTCMinutes() : date.getMinutes(); }
6858			function getSeconds(date) { return isUTC ? date.getUTCSeconds() : date.getSeconds(); }
6859			function getMilliseconds(date) { return isUTC ? date.getUTCMilliseconds() : date.getMilliseconds(); }
6860			function getDay(date) { return isUTC ? date.getUTCDay() : date.getDay(); }
6861			function setDate(date, dayValue) { return isUTC ? date.setUTCDate(dayValue) : date.setDate(dayValue); }
6862			function setMonth(date, monthValue, dayValue) { return isUTC ? date.setUTCMonth(monthValue, dayValue) : date.setMonth(monthValue, dayValue); }
6863
6864			function _formatDateMessage(value, messages)
6865			{
6866				var val = value < 100 ? Math.abs(value) : Math.abs(value % 100);
6867				var dec = val % 10;
6868				var message = "";
6869
6870				if(val == 0)
6871					message = _this._getMessage(messages["0"]);
6872				else if (val == 1)
6873					message = _this._getMessage(messages["1"]);
6874				else if (val >= 10 && val <= 20)
6875					message = _this._getMessage(messages["10_20"]);
6876				else if (dec == 1)
6877					message = _this._getMessage(messages["MOD_1"]);
6878				else if (2 <= dec && dec <= 4)
6879					message = _this._getMessage(messages["MOD_2_4"]);
6880				else
6881					message = _this._getMessage(messages["MOD_OTHER"]);
6882
6883				return message.replace(/#VALUE#/g, value);
6884			}
6885
6886			function _replaceDateFormat(match, matchFull)
6887			{
6888				if (dateFormats[match])
6889					return dateFormats[match]();
6890				else
6891					return matchFull;
6892			}
6893
6894			function intval(number)
6895			{
6896				return number >= 0 ? Math.floor(number) : Math.ceil(number);
6897			}
6898		},
6899
6900		convertBitrixFormat: function(format)
6901		{
6902			if (!Utils.isNotEmptyString(format))
6903				return "";
6904
6905			return format.replace("YYYY", "Y")	// 1999
6906						 .replace("MMMM", "F")	// January - December
6907						 .replace("MM", "m")	// 01 - 12
6908						 .replace("M", "M")	// Jan - Dec
6909						 .replace("DD", "d")	// 01 - 31
6910						 .replace("G", "g")	//  1 - 12
6911						 .replace(/GG/i, "G")	//  0 - 23
6912						 .replace("H", "h")	// 01 - 12
6913						 .replace(/HH/i, "H")	// 00 - 24
6914						 .replace("MI", "i")	// 00 - 59
6915						 .replace("SS", "s")	// 00 - 59
6916						 .replace("TT", "A")	// AM - PM
6917						 .replace("T", "a");	// am - pm
6918		},
6919
6920		convertToUTC: function(date)
6921		{
6922			if (!Utils.isDate(date))
6923				return null;
6924
6925			return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()));
6926		},
6927
6928		/**
6929		 * Function creates and returns Javascript Date() object from server timestamp regardless of local browser (system) timezone.
6930		 * For example can be used to convert timestamp from some exact date on server to the JS Date object with the same value.
6931		 *
6932		 * @param timestamp - timestamp in seconds
6933		 * @returns {Date}
6934		 */
6935		getNewDate: function(timestamp)
6936		{
6937			return new Date(this.getBrowserTimestamp(timestamp));
6938		},
6939
6940		/**
6941		 * Function transforms server timestamp (in sec) to javascript timestamp (calculated depend on local browser timezone offset). Returns timestamp in milliseconds.
6942		 * Also see BX.Main.Date.getNewDate description.
6943		 *
6944		 * @param timestamp - timestamp in seconds
6945		 * @returns {number}
6946		 */
6947		getBrowserTimestamp: function(timestamp)
6948		{
6949			timestamp = parseInt(timestamp, 10);
6950			var browserOffset = new Date(timestamp * 1000).getTimezoneOffset() * 60;
6951			return (parseInt(timestamp, 10) + parseInt(this._getMessage('SERVER_TZ_OFFSET')) + browserOffset) * 1000;
6952		},
6953
6954		/**
6955		 * Function transforms local browser timestamp (in ms) to server timestamp (calculated depend on local browser timezone offset). Returns timestamp in seconds.
6956		 *
6957		 * @param timestamp - timestamp in milliseconds
6958		 * @returns {number}
6959		 */
6960		getServerTimestamp: function(timestamp)
6961		{
6962			timestamp = parseInt(timestamp, 10);
6963			var browserOffset = new Date(timestamp).getTimezoneOffset() * 60;
6964			return Math.round(timestamp / 1000 - (parseInt(this._getMessage('SERVER_TZ_OFFSET'), 10) + parseInt(browserOffset, 10)));
6965		},
6966
6967		formatLastActivityDate: function(timestamp, now, utc)
6968		{
6969			var ampm = this.isAmPmMode(true);
6970			var timeFormat = (ampm === this.AM_PM_MODE.LOWER? "g:i a" : (ampm === this.AM_PM_MODE.UPPER? "g:i A" : "H:i"));
6971
6972			var format = [
6973			   ["tomorrow", "#01#"+timeFormat],
6974			   ["now" , "#02#"],
6975			   ["todayFuture", "#03#"+timeFormat],
6976			   ["yesterday", "#04#"+timeFormat],
6977			   ["-", this.convertBitrixFormat(this._getMessage("FORMAT_DATETIME")).replace(/:s/g, "")],
6978			   ["s60", "sago"],
6979			   ["i60", "iago"],
6980			   ["H5", "Hago"],
6981			   ["H24", "#03#"+timeFormat],
6982			   ["d31", "dago"],
6983			   ["m12>1", "mago"],
6984			   ["m12>0", "dago"],
6985			   ["", "#05#"]
6986			];
6987			var formattedDate = this.format(format, timestamp, now, utc);
6988			var match = null;
6989			if ((match = /^#(\d+)#(.*)/.exec(formattedDate)) != null)
6990			{
6991				switch (match[1])
6992				{
6993					case "01":
6994						formattedDate = this._getMessage('FD_LAST_SEEN_TOMORROW').replace("#TIME#", match[2]);
6995					break;
6996					case "02":
6997						formattedDate = this._getMessage('FD_LAST_SEEN_NOW');
6998					break;
6999					case "03":
7000						formattedDate = this._getMessage('FD_LAST_SEEN_TODAY').replace("#TIME#", match[2]);
7001					break;
7002					case "04":
7003						formattedDate = this._getMessage('FD_LAST_SEEN_YESTERDAY').replace("#TIME#", match[2]);
7004					break;
7005					case "05":
7006						formattedDate = this._getMessage('FD_LAST_SEEN_MORE_YEAR');
7007					break;
7008					default:
7009						formattedDate = match[2];
7010					break;
7011				}
7012			}
7013
7014			return formattedDate;
7015		},
7016
7017		isAmPmMode: function(returnConst)
7018		{
7019			if (returnConst === true)
7020			{
7021				return this._getMessage('AMPM_MODE');
7022			}
7023
7024			return this._getMessage('AMPM_MODE') !== false;
7025		},
7026
7027		/**
7028		 * The method is designed to replace the localization storage on sites without Bitrix Framework.
7029		 *
7030		 * @param message
7031		 * @returns {*}
7032		 * @private
7033		 */
7034		_getMessage: function(message)
7035		{
7036			return BX.message(message);
7037		},
7038
7039		/**
7040		 * The method used to parse date from string by given format.
7041		 *
7042		 * @param {string} str - date in given format
7043		 * @param {boolean} isUTC - is date in UTC
7044		 * @param {string} formatDate - format of the date without time
7045		 * @param {string} formatDatetime - format of the date with time
7046		 * @returns {Date|null} - returns Date object if string was parsed or null
7047		 */
7048		parse: function(str, isUTC, formatDate, formatDatetime)
7049		{
7050			if (Utils.isNotEmptyString(str))
7051			{
7052				if (!formatDate)
7053					formatDate = this._getMessage('FORMAT_DATE');
7054				if (!formatDatetime)
7055					formatDatetime = this._getMessage('FORMAT_DATETIME');
7056
7057				var regMonths = '';
7058				for (i = 1; i <= 12; i++)
7059				{
7060					regMonths = regMonths + '|' + this._getMessage('MON_'+i);
7061				}
7062
7063				var
7064					expr = new RegExp('([0-9]+|[a-z]+' + regMonths + ')', 'ig'),
7065					aDate = str.match(expr),
7066					aFormat = formatDate.match(/(DD|MI|MMMM|MM|M|YYYY)/ig),
7067					i, cnt,
7068					aDateArgs=[], aFormatArgs=[],
7069					aResult={};
7070
7071				if (!aDate)
7072				{
7073					return null;
7074				}
7075
7076				if(aDate.length > aFormat.length)
7077				{
7078					aFormat = formatDatetime.match(/(DD|MI|MMMM|MM|M|YYYY|HH|H|SS|TT|T|GG|G)/ig);
7079				}
7080
7081				for(i = 0, cnt = aDate.length; i < cnt; i++)
7082				{
7083					if(aDate[i].trim() !== '')
7084					{
7085						aDateArgs[aDateArgs.length] = aDate[i];
7086					}
7087				}
7088
7089				for(i = 0, cnt = aFormat.length; i < cnt; i++)
7090				{
7091					if(aFormat[i].trim() !== '')
7092					{
7093						aFormatArgs[aFormatArgs.length] = aFormat[i];
7094					}
7095				}
7096
7097				var m = Utils.array_search('MMMM', aFormatArgs);
7098				if (m > 0)
7099				{
7100					aDateArgs[m] = this.getMonthIndex(aDateArgs[m]);
7101					aFormatArgs[m] = "MM";
7102				}
7103				else
7104				{
7105					m = Utils.array_search('M', aFormatArgs);
7106					if (m > 0)
7107					{
7108						aDateArgs[m] = this.getMonthIndex(aDateArgs[m]);
7109						aFormatArgs[m] = "MM";
7110					}
7111				}
7112
7113				for(i = 0, cnt = aFormatArgs.length; i < cnt; i++)
7114				{
7115					var k = aFormatArgs[i].toUpperCase();
7116					aResult[k] = k === 'T' || k === 'TT' ? aDateArgs[i] : parseInt(aDateArgs[i], 10);
7117				}
7118
7119				if(aResult['DD'] > 0 && aResult['MM'] > 0 && aResult['YYYY'] > 0)
7120				{
7121					var d = new Date();
7122
7123					if(isUTC)
7124					{
7125						d.setUTCDate(1);
7126						d.setUTCFullYear(aResult['YYYY']);
7127						d.setUTCMonth(aResult['MM'] - 1);
7128						d.setUTCDate(aResult['DD']);
7129						d.setUTCHours(0, 0, 0, 0);
7130					}
7131					else
7132					{
7133						d.setDate(1);
7134						d.setFullYear(aResult['YYYY']);
7135						d.setMonth(aResult['MM'] - 1);
7136						d.setDate(aResult['DD']);
7137						d.setHours(0, 0, 0, 0);
7138					}
7139
7140					if(
7141						(!isNaN(aResult['HH']) || !isNaN(aResult['GG']) || !isNaN(aResult['H']) || !isNaN(aResult['G']))
7142						&& !isNaN(aResult['MI'])
7143					)
7144					{
7145						if (!isNaN(aResult['H']) || !isNaN(aResult['G']))
7146						{
7147							var
7148								bPM = (aResult['T']||aResult['TT']||'am').toUpperCase() === 'PM',
7149								h = parseInt(aResult['H']||aResult['G']||0, 10);
7150
7151							if(bPM)
7152							{
7153								aResult['HH'] = h + (h === 12 ? 0 : 12);
7154							}
7155							else
7156							{
7157								aResult['HH'] = h < 12 ? h : 0;
7158							}
7159						}
7160						else
7161						{
7162							aResult['HH'] = parseInt(aResult['HH']||aResult['GG']||0, 10);
7163						}
7164
7165						if (isNaN(aResult['SS']))
7166							aResult['SS'] = 0;
7167
7168						if(isUTC)
7169						{
7170							d.setUTCHours(aResult['HH'], aResult['MI'], aResult['SS']);
7171						}
7172						else
7173						{
7174							d.setHours(aResult['HH'], aResult['MI'], aResult['SS']);
7175						}
7176					}
7177
7178					return d;
7179				}
7180			}
7181
7182			return null;
7183		},
7184
7185		getMonthIndex: function(month)
7186		{
7187			var
7188				i,
7189				q = month.toUpperCase(),
7190				wordMonthCut = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'],
7191				wordMonth = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
7192
7193			for (i = 1; i <= 12; i++)
7194			{
7195				if (q === this._getMessage('MON_'+i).toUpperCase()
7196					|| q === this._getMessage('MONTH_'+i).toUpperCase()
7197					|| q === wordMonthCut[i-1].toUpperCase()
7198					|| q === wordMonth[i-1].toUpperCase())
7199				{
7200					return i;
7201				}
7202			}
7203			return month;
7204		}
7205	};
7206
7207	/**
7208	 * @private
7209	 */
7210	var Utils = {
7211		isDate: function(item) {
7212			return item && Object.prototype.toString.call(item) == "[object Date]";
7213		},
7214		isNumber: function(item) {
7215			return item === 0 ? true : (item ? (typeof (item) == "number" || item instanceof Number) : false);
7216		},
7217		isArray: function(item) {
7218			return item && Object.prototype.toString.call(item) == "[object Array]";
7219		},
7220		isString: function(item) {
7221			return item === '' ? true : (item ? (typeof (item) == "string" || item instanceof String) : false);
7222		},
7223		isNotEmptyString: function(item) {
7224			return this.isString(item) ? item.length > 0 : false;
7225		},
7226		strPadLeft: function(input, padLength, padString)
7227		{
7228			var i = input.length, q=padString.length;
7229			if (i >= padLength) return input;
7230
7231			for(;i<padLength;i+=q)
7232				input = padString + input;
7233
7234			return input;
7235		},
7236		/**
7237		 * @deprecated
7238		 * @use myArr.findIndex(item => item === needle);
7239		 */
7240		array_search: function(needle, haystack)
7241		{
7242			for(var i = 0; i < haystack.length; i++)
7243			{
7244				if(haystack[i] == needle)
7245					return i;
7246			}
7247			return -1;
7248		},
7249	};
7250
7251})(window);
7252
7253/* End */
7254;
7255; /* Start:"a:4:{s:4:"full";s:49:"/bitrix/js/main/core/core_date.js?167415717636080";s:6:"source";s:33:"/bitrix/js/main/core/core_date.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
7256;(function(){
7257
7258if (BX.date)
7259	return;
7260
7261BX.date = BX.Main.Date;
7262
7263/************************************** calendar class **********************************/
7264
7265var obCalendarSingleton = null;
7266
7267/*
7268params: {
7269	node: bind element || document.body
7270
7271	value - start value in site format (using 'field' param if 'value' does not exist)
7272	callback - date check handler. can return false to prevent calendar closing.
7273	callback_after - another handler, called after date picking
7274
7275	field - field to read/write data
7276
7277	bTime = true - whether to enable time control
7278	bHideTime = false - whether to hide time control by default
7279
7280	currentTime - current UTC time()
7281
7282}
7283*/
7284
7285
7286BX.calendar = function(params)
7287{
7288	return BX.calendar.get().Show(params);
7289};
7290
7291BX.calendar.get = function()
7292{
7293	if (!obCalendarSingleton)
7294		obCalendarSingleton = new BX.JCCalendar();
7295
7296	return obCalendarSingleton;
7297};
7298
7299// simple func for compatibility with the oldies
7300BX.calendar.InsertDaysBack = function(input, days)
7301{
7302	if (days != '')
7303	{
7304		var d = new Date();
7305		if(days > 0)
7306		{
7307			d.setTime(d.valueOf() - days*86400000);
7308		}
7309
7310		input.value = BX.date.format(BX.date.convertBitrixFormat(BX.message('FORMAT_DATE')), d, null);
7311	}
7312	else
7313	{
7314		input.value = '';
7315	}
7316};
7317
7318BX.calendar.ValueToString = function(value, bTime, bUTC)
7319{
7320	return BX.date.format(
7321		BX.date.convertBitrixFormat(BX.message(bTime ? 'FORMAT_DATETIME' : 'FORMAT_DATE')),
7322		value,
7323		null,
7324		!!bUTC
7325	);
7326};
7327
7328BX.calendar.ValueToStringFormat = function(value, bitrixFormat, bUTC)
7329{
7330	return BX.date.format(
7331		BX.date.convertBitrixFormat(bitrixFormat),
7332		value,
7333		null,
7334		!!bUTC
7335	);
7336};
7337
7338
7339BX.CalendarPeriod =
7340{
7341	Init: function(inputFrom, inputTo, selPeriod)
7342	{
7343		if((inputFrom.value != "" || inputTo.value != "") && selPeriod.value == "")
7344			selPeriod.value = "interval";
7345
7346		selPeriod.onchange();
7347	},
7348
7349	ChangeDirectOpts: function(peroidValue, selPParent) // "week" || "others"
7350	{
7351		var selDirect = BX.findChild(selPParent, {'className':'adm-select adm-calendar-direction'}, true);
7352
7353		if(peroidValue == "week")
7354		{
7355			selDirect.options[0].text = BX.message('JSADM_CALEND_PREV_WEEK');
7356			selDirect.options[1].text = BX.message('JSADM_CALEND_CURR_WEEK');
7357			selDirect.options[2].text = BX.message('JSADM_CALEND_NEXT_WEEK');
7358		}
7359		else
7360		{
7361			selDirect.options[0].text = BX.message('JSADM_CALEND_PREV');
7362			selDirect.options[1].text = BX.message('JSADM_CALEND_CURR');
7363			selDirect.options[2].text = BX.message('JSADM_CALEND_NEXT');
7364		}
7365	},
7366
7367	SaveAndClearInput: function(oInput)
7368	{
7369		if(!window.SavedPeriodValues)
7370			window.SavedPeriodValues = {};
7371
7372		window.SavedPeriodValues[oInput.id] = oInput.value;
7373		oInput.value="";
7374	},
7375
7376	RestoreInput: function(oInput)
7377	{
7378		if(!window.SavedPeriodValues || !window.SavedPeriodValues[oInput.id])
7379			return;
7380
7381		oInput.value = window.SavedPeriodValues[oInput.id];
7382		delete(window.SavedPeriodValues[oInput.id]);
7383	},
7384
7385	OnChangeP: function(sel)
7386	{
7387		var selPParent = sel.parentNode.parentNode;
7388		var bShowFrom, bShowTo, bShowDirect, bShowSeparate;
7389		bShowFrom = bShowTo = bShowDirect = bShowSeparate = false;
7390
7391		var inputFromWrap = BX.findChild(selPParent, {'className':'adm-input-wrap adm-calendar-inp adm-calendar-first'});
7392		var inputToWrap = BX.findChild(selPParent, {'className':'adm-input-wrap adm-calendar-second'});
7393		var selDirectWrap = BX.findChild(selPParent, {'className':'adm-select-wrap adm-calendar-direction'});
7394		var separator = BX.findChild(selPParent, {'className':'adm-calendar-separate'});
7395		var inputFrom = BX.findChild(selPParent, {'className':'adm-input adm-calendar-from'},true);
7396		var inputTo = BX.findChild(selPParent, {'className':'adm-input adm-calendar-to'},true);
7397
7398		// define who must be shown
7399		switch (sel.value)
7400		{
7401			case "day":
7402			case "week":
7403			case "month":
7404			case "quarter":
7405			case "year":
7406				bShowDirect=true;
7407				BX.CalendarPeriod.OnChangeD(selDirectWrap.children[0]);
7408				break;
7409
7410			case "before":
7411				bShowTo = true;
7412				break;
7413
7414			case "after":
7415				bShowFrom = true;
7416				break;
7417
7418			case "exact":
7419				bShowFrom= true;
7420				break;
7421
7422			case "interval":
7423				bShowFrom = bShowTo = bShowSeparate = true;
7424				BX.CalendarPeriod.RestoreInput(inputFrom);
7425				BX.CalendarPeriod.RestoreInput(inputTo);
7426
7427				break;
7428
7429			case "":
7430				BX.CalendarPeriod.SaveAndClearInput(inputFrom);
7431				BX.CalendarPeriod.SaveAndClearInput(inputTo);
7432				break;
7433
7434			default:
7435				break;
7436
7437		}
7438
7439		BX.CalendarPeriod.ChangeDirectOpts(sel.value, selPParent);
7440
7441		inputFromWrap.style.display = (bShowFrom? 'inline-block':'none');
7442		inputToWrap.style.display = (bShowTo? 'inline-block':'none');
7443		selDirectWrap.style.display = (bShowDirect? 'inline-block':'none');
7444		separator.style.display = (bShowSeparate? 'inline-block':'none');
7445	},
7446
7447
7448	OnChangeD: function(sel)
7449	{
7450		var selPParent = sel.parentNode.parentNode;
7451		var inputFrom = BX.findChild(selPParent, {'className':'adm-input adm-calendar-from'},true);
7452		var inputTo = BX.findChild(selPParent, {'className':'adm-input adm-calendar-to'},true);
7453		var selPeriod = BX.findChild(selPParent, {'className':'adm-select adm-calendar-period'},true);
7454
7455		var offset=0;
7456
7457		switch (sel.value)
7458		{
7459			case "previous":
7460				offset = -1;
7461				break;
7462
7463			case "next":
7464				offset = 1;
7465				break;
7466
7467			case "current":
7468			default:
7469				break;
7470
7471		}
7472
7473		var from = false;
7474		var to = false;
7475
7476		var today = new Date();
7477		var year = today.getFullYear();
7478		var month = today.getMonth();
7479		var day = today.getDate();
7480		var dayW = today.getDay();
7481
7482		if (dayW == 0)
7483				dayW = 7;
7484
7485		switch (selPeriod.value)
7486		{
7487			case "day":
7488				from = new Date(year, month, day+offset, 0, 0, 0);
7489				to = new Date(year, month, day+offset, 23, 59, 59);
7490				break;
7491
7492			case "week":
7493				from = new Date(year, month, day-dayW+1+offset*7, 0, 0, 0);
7494				to = new Date(year, month, day+(7-dayW)+offset*7, 23, 59, 59);
7495				break;
7496
7497			case "month":
7498				from = new Date(year, month+offset, 1, 0, 0, 0);
7499				to = new Date(year, month+1+offset, 0, 23, 59, 59);
7500				break;
7501
7502			case "quarter":
7503				var quarterNum = Math.floor((month/3))+offset;
7504				from = new Date(year, 3*(quarterNum), 1, 0, 0, 0);
7505				to = new Date(year, 3*(quarterNum+1), 0, 23, 59, 59);
7506				break;
7507
7508			case "year":
7509				from = new Date(year+offset, 0, 1, 0, 0, 0);
7510				to = new Date(year+1+offset, 0, 0, 23, 59, 59);
7511				break;
7512
7513			default:
7514				break;
7515		}
7516
7517		var format = window[inputFrom.name+"_bTime"] ? BX.message('FORMAT_DATETIME') : BX.message('FORMAT_DATE');
7518
7519		if(from)
7520		{
7521			inputFrom.value = BX.formatDate(from, format);
7522			BX.addClass(inputFrom,"adm-calendar-inp-setted");
7523		}
7524
7525		if(to)
7526		{
7527			inputTo.value = BX.formatDate(to, format);
7528			BX.addClass(inputTo,"adm-calendar-inp-setted");
7529		}
7530	}
7531};
7532
7533
7534BX.JCCalendar = function()
7535{
7536	this.params = {};
7537
7538	this.bAmPm = BX.isAmPmMode();
7539
7540	this.popup = null;
7541	this.popup_month = null;
7542	this.popup_year = null;
7543	this.month_popup_classname = '';
7544	this.year_popup_classname = '';
7545	this.value = null;
7546	this._layers = {};
7547	this._current_layer = null;
7548
7549	this.DIV = null;
7550	this.PARTS = {};
7551
7552	this.weekStart = 0;
7553	this.numRows = 6;
7554
7555	this._create = function(params)
7556	{
7557		this.popup = new BX.PopupWindow('calendar_popup_' + Math.random(), params.node, {
7558			closeByEsc: true,
7559			autoHide: false,
7560			content: this._get_content(),
7561			bindOptions: {forceBindPosition: true}
7562		});
7563
7564		BX.bind(this.popup.popupContainer, 'click', function(event) {
7565			event.stopPropagation();
7566		});
7567	};
7568
7569	this._auto_hide_disable = function()
7570	{
7571		BX.unbind(document, 'click', BX.proxy(this._auto_hide, this));
7572	};
7573
7574	this._auto_hide_enable = function()
7575	{
7576		BX.bind(document, 'click', BX.proxy(this._auto_hide, this));
7577	};
7578
7579	this._auto_hide = function(e)
7580	{
7581		this._auto_hide_disable();
7582		this.popup.close();
7583	};
7584
7585	this._get_content = function()
7586	{
7587		var _layer_onclick = BX.delegate(function(e) {
7588			e = e||window.event;
7589			this.SetDate(
7590				new Date(parseInt(BX.proxy_context.getAttribute('data-date'))),
7591				(e.type === 'dblclick' || (this.params.bCompatibility && !this.params.bTimeVisibility))
7592			)
7593		}, this);
7594
7595		this.DIV = BX.create('DIV', {
7596			props: {className: 'bx-calendar'},
7597			children: [
7598				BX.create('DIV', {
7599					props: {
7600						className: 'bx-calendar-header'
7601					},
7602					children: [
7603						BX.create('A', {
7604							attrs: {href: 'javascript:void(0)'},
7605							props: {className: 'bx-calendar-left-arrow'},
7606							events: {click: BX.proxy(this._prev, this)}
7607						}),
7608
7609						BX.create('SPAN', {
7610							props: {className: 'bx-calendar-header-content'},
7611							children: [
7612								(this.PARTS.MONTH = BX.create('A', {
7613									attrs: {href: 'javascript:void(0)'},
7614									props: {className: 'bx-calendar-top-month'},
7615									events: {click: BX.proxy(this._menu_month, this)}
7616								})),
7617
7618								(this.PARTS.YEAR = BX.create('A', {
7619									attrs: {href: 'javascript:void(0)'},
7620									props: {className: 'bx-calendar-top-year'},
7621									events: {click: BX.proxy(this._menu_year, this)}
7622								}))
7623							]
7624						}),
7625
7626						BX.create('A', {
7627							attrs: {href: 'javascript:void(0)'},
7628							props: {className: 'bx-calendar-right-arrow'},
7629							events: {click: BX.proxy(this._next, this)}
7630						})
7631					]
7632				}),
7633
7634				(this.PARTS.WEEK = BX.create('DIV', {
7635					props: {
7636						className: 'bx-calendar-name-day-wrap'
7637					}
7638				})),
7639
7640				(this.PARTS.LAYERS = BX.create('DIV', {
7641					props: {
7642						className: 'bx-calendar-cell-block'
7643					},
7644					events: {
7645						click: BX.delegateEvent({className: 'bx-calendar-cell'}, _layer_onclick),
7646						dblclick: BX.delegateEvent({className: 'bx-calendar-cell'}, _layer_onclick)
7647					}
7648				})),
7649
7650				(this.PARTS.TIME = BX.create('DIV', {
7651					props: {
7652						className: 'bx-calendar-set-time-wrap'
7653					},
7654					events: {
7655						click: BX.delegateEvent(
7656							{attr: 'data-action'},
7657							BX.delegate(this._time_actions, this)
7658						)
7659					},
7660					html: '<a href="javascript:void(0)" data-action="time_show" class="bx-calendar-set-time"><i></i>'+BX.message('CAL_TIME_SET')+'</a><div class="bx-calendar-form-block"><span class="bx-calendar-form-text">'+BX.message('CAL_TIME')+'</span><span class="bx-calendar-form"><input type="text" class="bx-calendar-form-input" maxwidth="2" onkeyup="BX.calendar.get()._check_time()" /><span class="bx-calendar-form-separator"></span><input type="text" class="bx-calendar-form-input" maxwidth="2" onkeyup="BX.calendar.get()._check_time()" />'+(this.bAmPm?'<span class="bx-calendar-AM-PM-block"><span class="bx-calendar-AM-PM-text" data-action="time_ampm"></span><span class="bx-calendar-form-arrow-r"><a href="javascript:void(0)" class="bx-calendar-form-arrow-top" data-action="time_ampm_up"><i></i></a><a href="javascript:void(0)" class="bx-calendar-form-arrow-bottom" data-action="time_ampm_down"><i></i></a></span></span>':'')+'</span><a href="javascript:void(0)" data-action="time_hide" class="bx-calendar-form-close"><i></i></a></div>'
7661				})),
7662
7663				(this.PARTS.BUTTONS = BX.create('DIV', {
7664					props: {className: 'bx-calendar-button-block'},
7665					events: {
7666						click: BX.delegateEvent(
7667							{attr: 'data-action'},
7668							BX.delegate(this._button_actions, this)
7669						)
7670					},
7671					html: '<a href="javascript:void(0)" class="bx-calendar-button bx-calendar-button-select" data-action="submit"><span class="bx-calendar-button-left"></span><span class="bx-calendar-button-text">'+BX.message('CAL_BUTTON')+'</span><span class="bx-calendar-button-right"></span></a><a href="javascript:void(0)" class="bx-calendar-button bx-calendar-button-cancel" data-action="cancel"><span class="bx-calendar-button-left"></span><span class="bx-calendar-button-text">'+BX.message('JS_CORE_WINDOW_CLOSE')+'</span><span class="bx-calendar-button-right"></span></a>'
7672				}))
7673			]
7674		});
7675
7676		this.PARTS.TIME_INPUT_H = BX.findChild(this.PARTS.TIME, {tag: 'INPUT'}, true);
7677		this.PARTS.TIME_INPUT_M = this.PARTS.TIME_INPUT_H.nextSibling.nextSibling;
7678
7679		if (this.bAmPm)
7680			this.PARTS.TIME_AMPM = this.PARTS.TIME_INPUT_M.nextSibling.firstChild;
7681
7682		var spinner = (new BX.JCSpinner({
7683			input: this.PARTS.TIME_INPUT_H,
7684			callback_change: BX.proxy(this._check_time, this),
7685			bSaveValue: false
7686		})).Show();
7687		spinner.className = 'bx-calendar-form-arrow-l';
7688		this.PARTS.TIME_INPUT_H.parentNode.insertBefore(spinner, this.PARTS.TIME_INPUT_H);
7689
7690		spinner = (new BX.JCSpinner({
7691			input: this.PARTS.TIME_INPUT_M,
7692			callback_change: BX.proxy(this._check_time, this),
7693			bSaveValue: true
7694		})).Show();
7695		spinner.className = 'bx-calendar-form-arrow-r';
7696		if (!this.PARTS.TIME_INPUT_M.nextSibling)
7697			this.PARTS.TIME_INPUT_M.parentNode.appendChild(spinner);
7698		else
7699			this.PARTS.TIME_INPUT_M.parentNode.insertBefore(spinner, this.PARTS.TIME_INPUT_M.nextSibling);
7700
7701		for (var i = 0; i < 7; i++)
7702		{
7703			this.PARTS.WEEK.appendChild(BX.create('SPAN', {
7704				props: {
7705					className: 'bx-calendar-name-day'
7706				},
7707				text: BX.message('DOW_' + ((i + this.weekStart) % 7))
7708			}));
7709		}
7710
7711		return this.DIV;
7712	};
7713
7714	this._time_actions = function()
7715	{
7716		switch (BX.proxy_context.getAttribute('data-action'))
7717		{
7718			case 'time_show':
7719				BX.addClass(this.PARTS.TIME, 'bx-calendar-set-time-opened');
7720				if (this.params.bCompatibility)
7721				{
7722					BX.removeClass(this.PARTS.BUTTONS, 'bx-calendar-buttons-disabled');
7723				}
7724				this.popup.adjustPosition();
7725			break;
7726			case 'time_hide':
7727				BX.removeClass(this.PARTS.TIME, 'bx-calendar-set-time-opened');
7728				if (this.params.bCompatibility)
7729				{
7730					this._saveChoice('hide');
7731					BX.addClass(this.PARTS.BUTTONS, 'bx-calendar-buttons-disabled');
7732				}
7733				this.popup.adjustPosition();
7734			break;
7735			case 'time_ampm':
7736				this.PARTS.TIME_AMPM.innerHTML = this.PARTS.TIME_AMPM.innerHTML == 'AM' ? 'PM' : 'AM';
7737			break;
7738			case 'time_ampm_up':
7739				this._check_time({bSaveValue: false}, null, 12);
7740				return;
7741			break;
7742			case 'time_ampm_down':
7743				this._check_time({bSaveValue: false}, null, -12);
7744				return;
7745			break;
7746		}
7747
7748		this._check_time();
7749	};
7750
7751	this._button_actions = function()
7752	{
7753		switch (BX.proxy_context.getAttribute('data-action'))
7754		{
7755			case 'submit':
7756				if (this.params.bCompatibility)
7757				{
7758					this._saveChoice('show');
7759				}
7760				this.SaveValue();
7761			break;
7762			case 'cancel':
7763				this.Close();
7764			break;
7765		}
7766	};
7767
7768	this._saveChoice = function(state)
7769	{
7770		if (this.params.bCategoryTimeVisibilityOption)
7771		{
7772			BX.userOptions.save(
7773				this.params.bCategoryTimeVisibilityOption,
7774				this.params.bNameTimeVisibilityOption,
7775				'visibility',
7776				(state === 'show' ? 'Y' : 'N')
7777			);
7778		}
7779
7780		this._bTimeVisibility = (state === 'show');
7781		this.params.bTimeVisibility = this._bTimeVisibility;
7782	};
7783
7784	this._check_time = function(params, value, direction)
7785	{
7786		var h = parseInt(this.PARTS.TIME_INPUT_H.value.substring(0,5),10)||0,
7787			m = parseInt(this.PARTS.TIME_INPUT_M.value.substring(0,5),10)||0,
7788			bChanged = false;
7789
7790		if (!!params && !params.bSaveValue)
7791		{
7792			this.value.setUTCHours(this.value.getUTCHours() + direction);
7793		}
7794		else if (!isNaN(h))
7795		{
7796			if (this.bAmPm)
7797			{
7798				if (h != 12 && this.PARTS.TIME_AMPM.innerHTML == 'PM')
7799				{
7800					h += 12;
7801				}
7802			}
7803
7804			bChanged = true;
7805			this.value.setUTCHours(h % 24);
7806		}
7807
7808		if (!isNaN(m))
7809		{
7810			bChanged = true;
7811			this.value.setUTCMinutes(m % 60);
7812		}
7813
7814		if (bChanged)
7815		{
7816			this.SetValue(this.value);
7817		}
7818	};
7819
7820	this._set_layer = function()
7821	{
7822		var layerId = parseInt(this.value.getUTCFullYear() + '' + BX.util.str_pad_left(this.value.getUTCMonth()+'', 2, "0"));
7823
7824		if (!this._layers[layerId])
7825		{
7826			this._layers[layerId] = this._create_layer();
7827			this._layers[layerId].BXLAYERID = layerId;
7828		}
7829
7830		if (this._current_layer)
7831		{
7832			var v = new Date(this.value.valueOf());
7833			v.setUTCHours(0); v.setUTCMinutes(0);
7834
7835			var cur_value = BX.findChild(this._layers[layerId], {
7836					tag: 'A',
7837					className: 'bx-calendar-active'
7838				}, true),
7839				new_value = BX.findChild(this._layers[layerId], {
7840					tag: 'A',
7841					attr: {
7842						'data-date' : v.valueOf() + ''
7843					}
7844				}, true);
7845
7846			if (cur_value)
7847			{
7848				BX.removeClass(cur_value, 'bx-calendar-active');
7849			}
7850
7851			if (new_value)
7852			{
7853				BX.addClass(new_value, 'bx-calendar-active');
7854			}
7855
7856			this._replace_layer(this._current_layer, this._layers[layerId]);
7857		}
7858		else
7859		{
7860			this.PARTS.LAYERS.appendChild(this._layers[layerId]);
7861		}
7862
7863		this._current_layer = this._layers[layerId];
7864	};
7865
7866	this._replace_layer = function(old_layer, new_layer)
7867	{
7868		if (old_layer != new_layer)
7869		{
7870			if (!BX.browser.IsIE() || BX.browser.IsDoctype())
7871			{
7872				var dir = old_layer.BXLAYERID > new_layer.BXLAYERID ? 1 : -1;
7873
7874				var old_top = 0;
7875				var new_top = -dir * old_layer.offsetHeight;
7876
7877				old_layer.style.position = 'relative';
7878				old_layer.style.top = "0px";
7879				old_layer.style.zIndex = 5;
7880
7881				new_layer.style.position = 'absolute';
7882				new_layer.style.top = new_top + 'px';
7883				new_layer.style.zIndex = 6;
7884
7885				this.PARTS.LAYERS.appendChild(new_layer);
7886
7887				var delta = 15;
7888
7889				var f;
7890				(f = function() {
7891					new_top += dir * delta;
7892					old_top += dir * delta;
7893
7894					if (dir * new_top < 0)
7895					{
7896						old_layer.style.top = old_top + 'px';
7897						new_layer.style.top = new_top + 'px';
7898						setTimeout(f, 10);
7899					}
7900					else
7901					{
7902						old_layer.parentNode.removeChild(old_layer);
7903
7904						new_layer.style.top = "0px";
7905						new_layer.style.position = 'static';
7906						new_layer.style.zIndex = 0;
7907					}
7908				})();
7909			}
7910			else
7911			{
7912				this.PARTS.LAYERS.replaceChild(new_layer, old_layer);
7913			}
7914		}
7915	};
7916
7917	this._create_layer = function()
7918	{
7919		var l = BX.create('DIV', {
7920			props: {
7921				className: 'bx-calendar-layer'
7922			}
7923		});
7924
7925		var month_start = new Date(this.value);
7926		month_start.setUTCHours(0);
7927		month_start.setUTCMinutes(0);
7928
7929		month_start.setUTCDate(1);
7930
7931		if (month_start.getUTCDay() != this.weekStart)
7932		{
7933			var d = month_start.getUTCDay() - this.weekStart;
7934			d += d < 0 ? 7 : 0;
7935			month_start.setUTCDate(month_start.getUTCDate()-d);
7936		}
7937
7938		var cur_month = this.value.getUTCMonth(),
7939			cur_day = this.value.getUTCDate(),
7940			s = '';
7941		for (var i = 0; i < this.numRows; i++)
7942		{
7943			s += '<div class="bx-calendar-range'
7944				+(i == this.numRows-1 ? ' bx-calendar-range-noline' : '')
7945				+'">';
7946
7947			for (var j = 0; j < 7; j++)
7948			{
7949				d = month_start.getUTCDate();
7950				var wd = month_start.getUTCDay();
7951				var className = 'bx-calendar-cell';
7952
7953				if (cur_month != month_start.getUTCMonth())
7954					className += ' bx-calendar-date-hidden';
7955				else if (cur_day == d)
7956					className += ' bx-calendar-active';
7957
7958
7959				if (wd == 0 || wd == 6)
7960					className += ' bx-calendar-weekend';
7961
7962				s += '<a href="javascript:void(0)" class="'+className+'" data-date="' + month_start.valueOf() + '">' + d + '</a>';
7963
7964				month_start.setUTCDate(month_start.getUTCDate()+1);
7965			}
7966			s += '</div>';
7967		}
7968
7969		l.innerHTML = s;
7970
7971		return l;
7972	};
7973
7974	this._prev = function()
7975	{
7976		this.SetMonth(this.value.getUTCMonth()-1);
7977	};
7978
7979	this._next = function()
7980	{
7981		this.SetMonth(this.value.getUTCMonth()+1);
7982	};
7983
7984	this._menu_month_content = function()
7985	{
7986		var months = '', cur_month = this.value.getMonth(), i;
7987		for (i = 0; i < 12; i++)
7988		{
7989			months += '<span class="bx-calendar-month'+(i == cur_month ? ' bx-calendar-month-active' : '')+'" data-bx-month="' + i + '">' + BX.message('MONTH_' + (i + 1)) + '</span>';
7990		}
7991
7992		return '<div class="bx-calendar-month-popup"><div class="bx-calendar-month-title" data-bx-month="' + this.value.getUTCMonth() + '">' + BX.message('MONTH_' + (this.value.getUTCMonth() + 1)) + '</div><div class="bx-calendar-month-content">' + months + '</div></div>';
7993	};
7994
7995	this._menu_month = function()
7996	{
7997		if (!this.popup_month)
7998		{
7999			this.popup_month = new BX.PopupWindow(
8000				'calendar_popup_month_' + Math.random(), this.PARTS.MONTH,
8001				{
8002					content: this._menu_month_content(),
8003					closeByEsc: true,
8004					autoHide: true,
8005					offsetTop: -29,
8006					offsetLeft: -1,
8007					className: this.month_popup_classname,
8008					events: {
8009						onPopupShow: BX.delegate(function() {
8010							if (this.popup_year)
8011							{
8012								this.popup_year.close();
8013							}
8014						}, this)
8015					}
8016				}
8017			);
8018
8019			BX.bind(this.popup_month.popupContainer, 'click', BX.proxy(this.month_popup_click, this));
8020			this.popup_month.BXMONTH = this.value.getUTCMonth();
8021		}
8022		else if (this.popup_month.BXMONTH != this.value.getUTCMonth())
8023		{
8024			this.popup_month.setContent(this._menu_month_content());
8025			this.popup_month.BXMONTH = this.value.getUTCMonth();
8026		}
8027
8028		this.popup_month.show();
8029	};
8030
8031	this.month_popup_click = function(e)
8032	{
8033		var target = e.target || e.srcElement;
8034		if (target && target.getAttribute && target.getAttribute('data-bx-month'))
8035		{
8036			this.SetMonth(parseInt(target.getAttribute('data-bx-month')));
8037			this.popup_month.close();
8038		}
8039	};
8040
8041	this._menu_year_content = function()
8042	{
8043		var s = '<div class="bx-calendar-year-popup"><div class="bx-calendar-year-title" data-bx-year="' + this.value.getUTCFullYear() + '">' + this.value.getUTCFullYear() + '</div><div class="bx-calendar-year-content" id="bx-calendar-year-content">';
8044
8045		for (var i=-3; i <= 3; i++)
8046		{
8047			s += '<span class="bx-calendar-year-number' + (i == 0?' bx-calendar-year-active' : '') + '" data-bx-year="' + (this.value.getUTCFullYear() - i) + '">' + (this.value.getUTCFullYear() - i)+'</span>';
8048		}
8049
8050		s += '</div><input data-bx-year-input="Y" type="text" class="bx-calendar-year-input" maxlength="4" /></div>';
8051
8052		return s;
8053	};
8054
8055	this._menu_year = function()
8056	{
8057		if (!this.popup_year)
8058		{
8059			this.popup_year = new BX.PopupWindow(
8060				'calendar_popup_year_' + Math.random(), this.PARTS.YEAR,
8061				{
8062					content: this._menu_year_content(),
8063					closeByEsc: true,
8064					autoHide: true,
8065					offsetTop: -29,
8066					offsetLeft: -1,
8067					className: this.year_popup_classname,
8068					events: {
8069						onPopupShow: BX.delegate(function() {
8070							if (this.popup_month)
8071							{
8072								this.popup_month.close();
8073							}
8074						}, this)
8075					}
8076				}
8077			);
8078
8079			BX.bind(this.popup_year.popupContainer, 'click', BX.proxy(this.year_popup_click, this));
8080			BX.bind(this.popup_year.popupContainer, 'keyup', BX.proxy(this.year_popup_keyup, this));
8081			this.popup_year.BXYEAR = this.value.getUTCFullYear();
8082		}
8083		else if (this.popup_year.BXYEAR != this.value.getUTCFullYear())
8084		{
8085			this.popup_year.setContent(this._menu_year_content());
8086			this.popup_year.BXYEAR = this.value.getUTCFullYear();
8087		}
8088
8089		this.popup_year.show();
8090	};
8091
8092	this.year_popup_click = function(e)
8093	{
8094		var target = e.target || e.srcElement;
8095		if (target && target.getAttribute && target.getAttribute('data-bx-year'))
8096		{
8097			this.SetYear(parseInt(target.getAttribute('data-bx-year')));
8098			this.popup_year.close();
8099		}
8100	};
8101	this.year_popup_keyup = function(e)
8102	{
8103		var target = e.target || e.srcElement;
8104		if (target && target.getAttribute && target.getAttribute('data-bx-year-input') == 'Y')
8105		{
8106			var value = parseInt(target.value);
8107			if(value >= 1900 && value <= 2100)
8108			{
8109				this.SetYear(value);
8110				this.popup_year.close();
8111			}
8112		}
8113	};
8114
8115	this._check_date = function(v)
8116	{
8117		var res = v;
8118
8119		if (BX.type.isString(v))
8120		{
8121			res = BX.parseDate(v, true);
8122		}
8123
8124		if (!BX.type.isDate(res) || isNaN(res.valueOf()))
8125		{
8126			res = BX.date.convertToUTC(new Date());
8127			if (this.params.bHideTime)
8128			{
8129				res.setUTCHours(0);
8130				res.setUTCMinutes(0);
8131			}
8132		}
8133
8134		res.setUTCMilliseconds(0);
8135		res.setUTCSeconds(0);
8136
8137		res.BXCHECKED = true;
8138
8139		return res;
8140	};
8141};
8142
8143BX.JCCalendar.prototype.Show = function(params)
8144{
8145	if (!BX.isReady)
8146	{
8147		BX.ready(BX.delegate(function() {this.Show(params)}, this));
8148		return;
8149	}
8150
8151	params.node = params.node||document.body;
8152
8153	if (BX.type.isNotEmptyString(params.node))
8154	{
8155		var n = BX(params.node);
8156		if (!n)
8157		{
8158			n = document.getElementsByName(params.node);
8159			if (n && n.length > 0)
8160			{
8161				n = n[0]
8162			}
8163		}
8164		params.node = n;
8165	}
8166
8167	if (!params.node)
8168		return;
8169
8170	if (!!params.field)
8171	{
8172		if (BX.type.isString(params.field))
8173		{
8174			n = BX(params.field);
8175			if (!!n)
8176			{
8177				params.field = n;
8178			}
8179			else
8180			{
8181				if (params.form)
8182				{
8183					if (BX.type.isString(params.form))
8184					{
8185						params.form = document.forms[params.form];
8186					}
8187				}
8188
8189				if (BX.type.isDomNode(params.form) && !!params.form[params.field])
8190				{
8191					params.field = params.form[params.field];
8192				}
8193				else
8194				{
8195					n = document.getElementsByName(params.field);
8196					if (n && n.length > 0)
8197					{
8198						n = n[0];
8199						params.field = n;
8200					}
8201				}
8202			}
8203
8204			if (BX.type.isString(params.field))
8205			{
8206				params.field = BX(params.field);
8207			}
8208		}
8209	}
8210
8211	var bShow = !this.popup || !this.popup.isShown() || this.params.node != params.node;
8212
8213	this.params = params;
8214
8215	this.params.bCompatibility = (typeof this.params.bCompatibility == 'undefined' ? false : this.params.bCompatibility);
8216	this.params.bTimeVisibility = (typeof this.params.bTimeVisibility == 'undefined' ? !this.params.bCompatibility : this.params.bTimeVisibility);
8217	if (this.params.bCompatibility)
8218	{
8219		this.params.bCategoryTimeVisibilityOption = (
8220			this.params.bCategoryTimeVisibilityOption ? this.params.bCategoryTimeVisibilityOption : ''
8221		);
8222		this.params.bNameTimeVisibilityOption = (
8223			this.params.bNameTimeVisibilityOption ? this.params.bNameTimeVisibilityOption : 'time_visibility'
8224		);
8225
8226		if (typeof this._bTimeVisibility !== 'undefined')
8227		{
8228			this.params.bTimeVisibility = this._bTimeVisibility;
8229		}
8230	}
8231
8232	this.params.bTime = typeof this.params.bTime == 'undefined' ? true : !!this.params.bTime;
8233	this.params.bHideTime = typeof this.params.bHideTime == 'undefined' ? true : !!this.params.bHideTime;
8234	this.params.bUseSecond = typeof this.params.bUseSecond == 'undefined' ? true : !!this.params.bUseSecond;
8235
8236	this.weekStart = parseInt(this.params.weekStart || this.params.weekStart || BX.message('WEEK_START'));
8237	if (isNaN(this.weekStart))
8238		this.weekStart = 1;
8239
8240	if (!this.popup)
8241	{
8242		this._create(this.params);
8243	}
8244	else
8245	{
8246		this.popup.setBindElement(this.params.node);
8247	}
8248
8249	var bHideTime = !!this.params.bHideTime;
8250	if (this.params.value)
8251	{
8252		this.SetValue(this.params.value);
8253		bHideTime = this.value.getUTCHours() <= 0 && this.value.getUTCMinutes() <= 0;
8254	}
8255	else if (this.params.field)
8256	{
8257		this.SetValue(this.params.field.value);
8258		bHideTime = this.value.getUTCHours() <= 0 && this.value.getUTCMinutes() <= 0;
8259	}
8260	else if (!!this.params.currentTime)
8261	{
8262		this.SetValue(this.params.currentTime);
8263	}
8264	else
8265	{
8266		this.SetValue();
8267	}
8268
8269	if (!!this.params.bTime)
8270	{
8271		this.activateTimeStyle(bHideTime);
8272	}
8273	else
8274	{
8275		this.activateDateStyle(bHideTime);
8276	}
8277
8278	if (bShow)
8279	{
8280		this._auto_hide_disable();
8281		this.popup.show();
8282		setTimeout(BX.proxy(this._auto_hide_enable, this), 0);
8283	}
8284
8285	this.params.bSetFocus = typeof this.params.bSetFocus == 'undefined' ? true : !!this.params.bSetFocus;
8286	if(this.params.bSetFocus)
8287	{
8288		params.node.blur();
8289	}
8290	else
8291	{
8292		BX.bind(params.node, 'keyup', BX.defer(function(){
8293			this.SetValue(params.node.value);
8294			if(!!this.params.bTime)
8295			{
8296				if(this.value.getUTCHours() <= 0 && this.value.getUTCMinutes() <= 0)
8297					BX.removeClass(this.PARTS.TIME, 'bx-calendar-set-time-opened');
8298				else
8299					BX.addClass(this.PARTS.TIME, 'bx-calendar-set-time-opened');
8300			}
8301		}, this));
8302	}
8303
8304	return this;
8305};
8306
8307BX.JCCalendar.prototype.activateDateStyle = function(bHideTime)
8308{
8309	BX.addClass(this.DIV, 'bx-calendar-time-disabled');
8310
8311	if (!!bHideTime)
8312		BX.removeClass(this.PARTS.TIME, 'bx-calendar-set-time-opened');
8313	else
8314		BX.addClass(this.PARTS.TIME, 'bx-calendar-set-time-opened');
8315};
8316
8317BX.JCCalendar.prototype.activateTimeStyle = function(bHideTime)
8318{
8319	if (this.params.bCompatibility && !this.params.bTimeVisibility)
8320	{
8321		BX.addClass(this.PARTS.BUTTONS, 'bx-calendar-buttons-disabled');
8322		BX.addClass(this.PARTS.TIME, 'bx-calendar-set-time-wrap-simple');
8323		BX.removeClass(this.PARTS.TIME, 'bx-calendar-set-time-opened');
8324	}
8325	else
8326	{
8327		BX.removeClass(this.DIV, 'bx-calendar-time-disabled');
8328
8329		if (!!bHideTime)
8330			BX.removeClass(this.PARTS.TIME, 'bx-calendar-set-time-opened');
8331		else
8332			BX.addClass(this.PARTS.TIME, 'bx-calendar-set-time-opened');
8333	}
8334};
8335
8336BX.JCCalendar.prototype.SetDay = function(d)
8337{
8338	this.value.setUTCDate(d);
8339	return this.SetValue(this.value);
8340};
8341
8342BX.JCCalendar.prototype.SetMonth = function(m)
8343{
8344	if (this.popup_month)
8345		this.popup_month.close();
8346
8347	this.value.setUTCMonth(m);
8348
8349	if(m < 0)
8350		m += 12;
8351	else if (m >= 12)
8352		m -= 12;
8353
8354	while(this.value.getUTCMonth() > m)
8355	{
8356		this.value.setUTCDate(this.value.getUTCDate()-1);
8357	}
8358
8359	return this.SetValue(this.value);
8360};
8361
8362BX.JCCalendar.prototype.SetYear = function(y)
8363{
8364	if (this.popup_year)
8365		this.popup_year.close();
8366	this.value.setUTCFullYear(y);
8367	return this.SetValue(this.value);
8368};
8369
8370BX.JCCalendar.prototype.SetDate = function(v, bSet)
8371{
8372	v = this._check_date(v);
8373	v.setUTCHours(this.value.getUTCHours());
8374	v.setUTCMinutes(this.value.getUTCMinutes());
8375	v.setUTCSeconds(this.value.getUTCSeconds());
8376
8377	if (this.params.bTime && !bSet)
8378	{
8379		return this.SetValue(v);
8380	}
8381	else
8382	{
8383		this.SetValue(v);
8384		this.SaveValue();
8385	}
8386};
8387
8388BX.JCCalendar.prototype.SetValue = function(v)
8389{
8390	this.value = (v && v.BXCHECKED) ? v : this._check_date(v);
8391
8392	this.PARTS.MONTH.innerHTML = BX.message('MONTH_' + (this.value.getUTCMonth()+1));
8393	this.PARTS.YEAR.innerHTML = this.value.getUTCFullYear();
8394
8395	if (!!this.params.bTime)
8396	{
8397		var h = this.value.getUTCHours();
8398		if (this.bAmPm)
8399		{
8400			if (h >= 12)
8401			{
8402				this.PARTS.TIME_AMPM.innerHTML = 'PM';
8403
8404				if (h != 12)
8405					h -= 12;
8406			}
8407			else
8408			{
8409				this.PARTS.TIME_AMPM.innerHTML = 'AM';
8410
8411				if (h == 0)
8412					h = 12;
8413			}
8414		}
8415
8416		this.PARTS.TIME_INPUT_H.value = BX.util.str_pad_left(h.toString(), 2, "0");
8417		this.PARTS.TIME_INPUT_M.value = BX.util.str_pad_left(this.value.getUTCMinutes().toString(), 2, "0");
8418	}
8419
8420	this._set_layer();
8421
8422	return this;
8423};
8424
8425BX.JCCalendar.prototype.SaveValue = function()
8426{
8427	if (this.popup_month)
8428		this.popup_month.close();
8429	if (this.popup_year)
8430		this.popup_year.close();
8431
8432	var bSetValue = true;
8433	if (!!this.params.callback)
8434	{
8435		var res = this.params.callback.apply(this, [new Date(this.value.valueOf()+this.value.getTimezoneOffset()*60000)]);
8436		if (res === false)
8437			bSetValue = false;
8438	}
8439
8440	if (bSetValue)
8441	{
8442		var bTime = !!this.params.bTime && BX.hasClass(this.PARTS.TIME, 'bx-calendar-set-time-opened');
8443
8444		if (this.params.field)
8445		{
8446			var format = BX.message(bTime ? 'FORMAT_DATETIME' : 'FORMAT_DATE');
8447
8448			if(bTime && !this.params.bUseSecond)
8449			{
8450				format = format.replace(':SS', '');
8451			}
8452
8453			this.params.field.value = BX.calendar.ValueToStringFormat(this.value, format, true);
8454			BX.fireEvent(this.params.field, 'change');
8455		}
8456
8457		this.popup.close();
8458
8459		if (!!this.params.callback_after)
8460		{
8461			this.params.callback_after.apply(this, [new Date(this.value.valueOf()+this.value.getTimezoneOffset()*60000), bTime]);
8462		}
8463	}
8464
8465	return this;
8466};
8467
8468BX.JCCalendar.prototype.Close = function()
8469{
8470	if (!!this.popup)
8471		this.popup.close();
8472
8473	return this;
8474};
8475
8476BX.JCSpinner = function(params)
8477{
8478	params = params || {};
8479	this.params = {
8480		input: params.input || null,
8481
8482		delta: params.delta || 1,
8483
8484		timeout_start: params.timeout_start || 1000,
8485		timeout_cont: params.timeout_cont || 150,
8486
8487		callback_start: params.callback_start || null,
8488		callback_change: params.callback_change || null,
8489		callback_finish: params.callback_finish || null,
8490
8491		bSaveValue: typeof params.bSaveValue == 'undefined' ? !!params.input : !!params.bSaveValue
8492	};
8493
8494	this.mousedown = false;
8495	this.direction = 1;
8496};
8497
8498BX.JCSpinner.prototype.Show = function()
8499{
8500	this.node = BX.create('span', {
8501		events: {
8502			mousedown: BX.delegateEvent(
8503				{attr: 'data-dir'},
8504				BX.delegate(this.Start, this)
8505			)
8506		},
8507		html: '<a href="javascript:void(0)" class="bx-calendar-form-arrow bx-calendar-form-arrow-top" data-dir="1"><i></i></a><a href="javascript:void(0)" class="bx-calendar-form-arrow bx-calendar-form-arrow-bottom" data-dir="-1"><i></i></a>'
8508	});
8509	return this.node;
8510};
8511
8512BX.JCSpinner.prototype.Start = function()
8513{
8514	this.mousedown = true;
8515	this.direction = BX.proxy_context.getAttribute('data-dir') > 0 ? 1 : -1;
8516	BX.bind(document, "mouseup", BX.proxy(this.MouseUp, this));
8517	this.ChangeValue(true);
8518};
8519
8520BX.JCSpinner.prototype.ChangeValue = function(bFirst)
8521{
8522	if(!this.mousedown)
8523		return;
8524
8525	if (this.params.input)
8526	{
8527		var v = parseInt(this.params.input.value, 10) + this.params.delta * this.direction;
8528
8529		if (this.params.bSaveValue)
8530			this.params.input.value = v;
8531
8532		if (!!bFirst && this.params.callback_start)
8533			this.params.callback_start(this.params, v, this.direction);
8534
8535		if (this.params.callback_change)
8536			this.params.callback_change(this.params, v, this.direction);
8537
8538		setTimeout(
8539			BX.proxy(this.ChangeValue, this),
8540			!!bFirst ? this.params.timeout_start : this.params.timeout_cont
8541		);
8542	}
8543};
8544
8545BX.JCSpinner.prototype.MouseUp = function()
8546{
8547	this.mousedown = false;
8548	BX.unbind(document, "mouseup", BX.proxy(this.MouseUp, this));
8549
8550	if (this.params.callback_finish)
8551		this.params.callback_finish(this.params, this.params.input.value);
8552};
8553
8554/**************** compatibility hacks ***************************/
8555
8556window.jsCalendar = {
8557	Show: function(obj, field, fieldFrom, fieldTo, bTime, serverTime, form_name, bHideTimebar)
8558	{
8559		return BX.calendar({
8560			node: obj, field: field, form: form_name, bTime: !!bTime, currentTime: serverTime, bHideTimebar: !!bHideTimebar
8561		});
8562	},
8563
8564	ValueToString: BX.calendar.ValueToString
8565};
8566
8567
8568/************ clock popup transferred from timeman **************/
8569
8570BX.CClockSelector = function(params)
8571{
8572	this.params = params;
8573
8574	this.params.popup_buttons = this.params.popup_buttons || [
8575		new BX.PopupWindowButton({
8576			text : BX.message('CAL_BUTTON'),
8577			className : "popup-window-button-create",
8578			events : {click : BX.proxy(this.setValue, this)}
8579		})
8580	];
8581
8582	this.isReady = false;
8583
8584	this.WND = new BX.PopupWindow(
8585		this.params.popup_id || 'clock_selector_popup',
8586		this.params.node,
8587		this.params.popup_config || {
8588			titleBar: BX.message('CAL_TIME'),
8589			offsetLeft: -45,
8590			offsetTop: -135,
8591			autoHide: true,
8592			closeIcon: true,
8593			closeByEsc: true
8594		}
8595	);
8596
8597	this.SHOW = false;
8598	BX.addCustomEvent(this.WND, "onPopupClose", BX.delegate(this.onPopupClose, this));
8599
8600	this.obClocks = {};
8601	this.CLOCK_ID = this.params.clock_id || 'clock_selector';
8602};
8603
8604BX.CClockSelector.prototype.Show = function()
8605{
8606	if (!this.isReady)
8607	{
8608		//BX.timeman.showWait(this.parent.DIV);
8609
8610		BX.addCustomEvent('onClockRegister', BX.proxy(this.onClockRegister, this));
8611		return BX.ajax.get('/bitrix/tools/clock_selector.php', {start_time: this.params.start_time, clock_id: this.CLOCK_ID, sessid: BX.bitrix_sessid()}, BX.delegate(this.Ready, this));
8612	}
8613
8614	this.WND.setButtons(this.params.popup_buttons);
8615	this.WND.show();
8616
8617	this.SHOW = true;
8618
8619	if (window['bxClock_' + this.obClocks[this.CLOCK_ID]])
8620	{
8621		setTimeout("window['bxClock_" + this.obClocks[this.CLOCK_ID] + "'].CalculateCoordinates()", 40);
8622	}
8623
8624	return true;
8625};
8626
8627BX.CClockSelector.prototype.onClockRegister = function(obClocks)
8628{
8629	if (obClocks[this.CLOCK_ID])
8630	{
8631		this.obClocks[this.CLOCK_ID] = obClocks[this.CLOCK_ID];
8632		BX.removeCustomEvent('onClockRegister', BX.proxy(this.onClockRegister, this));
8633	}
8634};
8635
8636BX.CClockSelector.prototype.Ready = function(data)
8637{
8638	this.content = this.CreateContent(data);
8639	this.WND.setContent(this.content);
8640
8641	this.isReady = true;
8642	//BX.timeman.closeWait();
8643
8644	setTimeout(BX.proxy(this.Show, this), 30);
8645};
8646
8647BX.CClockSelector.prototype.CreateContent = function(data)
8648{
8649	return BX.create('DIV', {
8650		events: {click: BX.PreventDefault},
8651		html:
8652			'<div class="bx-tm-popup-clock">' + data + '</div>'
8653	});
8654};
8655
8656BX.CClockSelector.prototype.setValue = function(e)
8657{
8658	if (this.params.callback)
8659	{
8660		var input = BX.findChild(this.content, {tagName: 'INPUT'}, true);
8661		this.params.callback.apply(this.params.node, [input.value]);
8662	}
8663
8664	return BX.PreventDefault(e);
8665};
8666
8667BX.CClockSelector.prototype.closeWnd = function(e)
8668{
8669	this.WND.close();
8670	return (e || window.event) ? BX.PreventDefault(e) : true;
8671};
8672
8673BX.CClockSelector.prototype.setNode = function(node)
8674{
8675	this.WND.setBindElement(node);
8676};
8677
8678BX.CClockSelector.prototype.setTime = function(timestamp)
8679{
8680	this.params.start_time = timestamp;
8681	if (window['bxClock_' + this.obClocks[this.CLOCK_ID]])
8682	{
8683		window['bxClock_' +  this.obClocks[this.CLOCK_ID]].SetTime(parseInt(timestamp/3600), parseInt((timestamp%3600)/60));
8684	}
8685};
8686
8687BX.CClockSelector.prototype.setCallback = function(cb)
8688{
8689	this.params.callback = cb;
8690};
8691
8692BX.CClockSelector.prototype.onPopupClose = function()
8693{
8694	this.SHOW = false;
8695};
8696
8697})();
8698
8699/* End */
8700;
8701; /* Start:"a:4:{s:4:"full";s:37:"/bitrix/js/main/dd.js?167415717914809";s:6:"source";s:21:"/bitrix/js/main/dd.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
8702;(function(){
8703
8704if (window.jsDD)
8705	return;
8706
8707jsDD = {
8708	arObjects: [],
8709	arDestinations: [],
8710	arDestinationsPriority: [],
8711
8712	arContainers: [],
8713	arContainersPos: [],
8714
8715	current_dest_index: false,
8716	current_node: null,
8717
8718	wndSize: null,
8719
8720	bStarted: false,
8721	bDisable: false,
8722	bDisableDestRefresh: false,
8723
8724	bEscPressed: false,
8725
8726	bScrollWindow: false,
8727	scrollViewTimer: null,
8728	scrollViewConfig: {
8729		checkerTimeout: 30,
8730		scrollZone: 25,
8731		scrollBy: 25,
8732		scrollContainer: null,
8733		bScrollH: true,
8734		bScrollV: true,
8735		pos: null
8736	},
8737
8738	setScrollWindow: function(val)
8739	{
8740		jsDD.bScrollWindow = !!val;
8741		if (BX.type.isDomNode(val))
8742		{
8743			jsDD.scrollViewConfig.scrollContainer = val;
8744			jsDD.scrollViewConfig.pos = BX.pos(val);
8745
8746			var s = BX.style(val, 'overflow') || 'visible',
8747				s1 = BX.style(val, 'overflow-x') || 'visible',
8748				s2 = BX.style(val, 'overflow-y') || 'visible';
8749
8750			jsDD.scrollViewConfig.bScrollH = s != 'visible' || s1 != 'visible';
8751			jsDD.scrollViewConfig.bScrollV = s != 'visible' || s2 != 'visible';
8752		}
8753	},
8754
8755	Reset: function()
8756	{
8757		jsDD.arObjects = [];
8758		jsDD.arDestinations = [];
8759		jsDD.arDestinationsPriority = [];
8760		jsDD.bStarted = false;
8761		jsDD.current_node = null;
8762		jsDD.current_dest_index = false;
8763		jsDD.bDisableDestRefresh = false;
8764		jsDD.bDisable = false;
8765		jsDD.x = null;
8766		jsDD.y = null;
8767		jsDD.start_x = null;
8768		jsDD.start_y = null;
8769		jsDD.wndSize = null;
8770
8771		jsDD.bEscPressed = false;
8772
8773		clearInterval(jsDD.scrollViewTimer)
8774		jsDD.bScrollWindow = false;
8775		jsDD.scrollViewTimer = null;
8776		jsDD.scrollViewConfig.scrollContainer = null;
8777	},
8778
8779	registerObject: function (obNode)
8780	{
8781		BX.bind(obNode, 'mousedown', jsDD.startDrag);
8782		BX.Event.bind(obNode, 'touchstart', jsDD.startDrag, { passive: true });
8783
8784		obNode.__bxddid = jsDD.arObjects.length;
8785
8786		jsDD.arObjects[obNode.__bxddid] = obNode;
8787	},
8788	unregisterObject: function(obNode)
8789	{
8790		if(typeof(obNode["__bxddid"]) === "undefined")
8791		{
8792			return;
8793		}
8794
8795		delete jsDD.arObjects[obNode.__bxddid];
8796		delete obNode.__bxddid;
8797		BX.unbind(obNode, 'mousedown', jsDD.startDrag);
8798		BX.unbind(obNode, 'touchstart', jsDD.startDrag);
8799	},
8800	registerDest: function (obDest, priority)
8801	{
8802		if (!priority)
8803			priority = 100;
8804
8805		obDest.__bxddeid = jsDD.arDestinations.length;
8806		obDest.__bxddpriority = priority;
8807
8808		jsDD.arDestinations[obDest.__bxddeid] = obDest;
8809		if (!jsDD.arDestinationsPriority[priority])
8810			jsDD.arDestinationsPriority[priority] = [obDest.__bxddeid]
8811		else
8812			jsDD.arDestinationsPriority[priority].push(obDest.__bxddeid);
8813
8814		jsDD.refreshDestArea(obDest.__bxddeid);
8815	},
8816	unregisterDest: function(obDest)
8817	{
8818		if(typeof(obDest["__bxddeid"]) === "undefined")
8819		{
8820			return;
8821		}
8822
8823		delete jsDD.arDestinations[obDest.__bxddeid];
8824		delete obDest.__bxddeid;
8825		delete obDest.__bxddpriority;
8826
8827		jsDD.refreshDestArea();
8828	},
8829	disableDest: function(obDest)
8830	{
8831		if (typeof(obDest.__bxddeid) !== "undefined")
8832		{
8833			obDest.__bxdddisabled = true;
8834		}
8835	},
8836
8837	enableDest: function(obDest)
8838	{
8839		if (typeof(obDest.__bxddeid) !== "undefined")
8840		{
8841			obDest.__bxdddisabled = false;
8842		}
8843	},
8844
8845	registerContainer: function (obCont)
8846	{
8847		jsDD.arContainers[jsDD.arContainers.length] = obCont;
8848	},
8849
8850	getContainersScrollPos: function(x, y)
8851	{
8852		var pos = {'left':0, 'top':0};
8853		for(var i=0, n=jsDD.arContainers.length; i<n; i++)
8854		{
8855			if(jsDD.arContainers[i] && x >= jsDD.arContainersPos[i]["left"] && x <= jsDD.arContainersPos[i]["right"] && y >= jsDD.arContainersPos[i]["top"] && y <= jsDD.arContainersPos[i]["bottom"])
8856			{
8857				pos.left = jsDD.arContainers[i].scrollLeft;
8858				pos.top = jsDD.arContainers[i].scrollTop;
8859			}
8860		}
8861		return pos;
8862	},
8863
8864	setContainersPos: function()
8865	{
8866		for(var i=0, n=jsDD.arContainers.length; i<n; i++)
8867		{
8868			if(jsDD.arContainers[i])
8869				jsDD.arContainersPos[i] = BX.pos(jsDD.arContainers[i]);
8870		}
8871	},
8872
8873	refreshDestArea: function(id)
8874	{
8875		if (id && typeof (id) == "object" && typeof (id.__bxddeid) != 'undefined')
8876		{
8877			id = id.__bxddeid;
8878		}
8879
8880		if (typeof id == 'undefined')
8881		{
8882			for (var i = 0, cnt = jsDD.arDestinations.length; i < cnt; i++)
8883			{
8884				jsDD.refreshDestArea(i);
8885			}
8886		}
8887		else
8888		{
8889			if (null == jsDD.arDestinations[id])
8890				return;
8891
8892			var arPos = BX.pos(jsDD.arDestinations[id]);
8893			jsDD.arDestinations[id].__bxpos = [arPos.left, arPos.top, arPos.right, arPos.bottom];
8894		}
8895	},
8896
8897	_checkEsc: function(e)
8898	{
8899		e = e||window.event;
8900		if (jsDD.bStarted && e.keyCode == 27)
8901		{
8902			jsDD.stopCurrentDrag();
8903		}
8904	},
8905
8906	stopCurrentDrag: function()
8907	{
8908		if (jsDD.bStarted)
8909		{
8910			jsDD.bEscPressed = true;
8911			jsDD.stopDrag();
8912		}
8913	},
8914
8915	/* scroll checkers */
8916
8917	_onscroll: function() {
8918		jsDD.wndSize = BX.GetWindowSize();
8919	},
8920
8921	_checkScroll: function()
8922	{
8923		if (jsDD.bScrollWindow)
8924		{
8925			var pseudo_e = {
8926					clientX: jsDD.x - jsDD.wndSize.scrollLeft,
8927					clientY: jsDD.y - jsDD.wndSize.scrollTop
8928				},
8929				bChange = false,
8930				d = jsDD.scrollViewConfig.scrollZone;
8931
8932			// check whether window scroll needed
8933			if (pseudo_e.clientY < d && jsDD.wndSize.scrollTop > 0)
8934			{
8935				window.scrollBy(0, -jsDD.scrollViewConfig.scrollBy);
8936				bChange = true;
8937			}
8938
8939			if (pseudo_e.clientY > jsDD.wndSize.innerHeight - d && jsDD.wndSize.scrollTop < jsDD.wndSize.scrollHeight - jsDD.wndSize.innerHeight)
8940			{
8941				window.scrollBy(0, jsDD.scrollViewConfig.scrollBy);
8942				bChange = true;
8943			}
8944
8945			if (pseudo_e.clientX < d && jsDD.wndSize.scrollLeft > 0)
8946			{
8947				window.scrollBy(-jsDD.scrollViewConfig.scrollBy, 0);
8948				bChange = true;
8949			}
8950
8951			if (pseudo_e.clientX > jsDD.wndSize.innerWidth - d && jsDD.wndSize.scrollLeft < jsDD.wndSize.scrollWidth - jsDD.wndSize.innerWidth)
8952			{
8953				window.scrollBy(jsDD.scrollViewConfig.scrollBy, 0);
8954				bChange = true;
8955			}
8956
8957			// check whether container scroll needed
8958
8959			if (jsDD.scrollViewConfig.scrollContainer)
8960			{
8961				var c = jsDD.scrollViewConfig.scrollContainer;
8962
8963				if (jsDD.scrollViewConfig.bScrollH)
8964				{
8965					if (pseudo_e.clientX + jsDD.wndSize.scrollLeft < jsDD.scrollViewConfig.pos.left + d && c.scrollLeft > 0)
8966					{
8967						c.scrollLeft -= jsDD.scrollViewConfig.scrollBy;
8968						bChange = true;
8969					}
8970
8971					if (pseudo_e.clientX + jsDD.wndSize.scrollLeft > jsDD.scrollViewConfig.pos.right - d
8972						&& c.scrollLeft < c.scrollWidth - c.offsetWidth)
8973					{
8974						c.scrollLeft += jsDD.scrollViewConfig.scrollBy;
8975						bChange = true;
8976					}
8977				}
8978
8979				if (jsDD.scrollViewConfig.bScrollV)
8980				{
8981					if (pseudo_e.clientY + jsDD.wndSize.scrollTop < jsDD.scrollViewConfig.pos.top + d && c.scrollTop > 0)
8982					{
8983						c.scrollTop -= jsDD.scrollViewConfig.scrollBy;
8984						bChange = true;
8985					}
8986
8987					if (pseudo_e.clientY + jsDD.wndSize.scrollTop > jsDD.scrollViewConfig.pos.bottom - d
8988						&& c.scrollTop < c.scrollHeight - c.offsetHeight)
8989					{
8990						c.scrollTop += jsDD.scrollViewConfig.scrollBy;
8991						bChange = true;
8992					}
8993				}
8994			}
8995
8996			if (bChange)
8997			{
8998				jsDD._onscroll();
8999				jsDD.drag(pseudo_e);
9000			}
9001		}
9002	},
9003
9004	/* DD process */
9005
9006	startDrag: function(e)
9007	{
9008		if (jsDD.bDisable)
9009			return true;
9010
9011		e = e || window.event;
9012
9013		if (!(BX.getEventButton(e)&BX.MSLEFT))
9014			return true;
9015
9016		jsDD.current_node = null;
9017		if (e.currentTarget)
9018		{
9019			jsDD.current_node = e.currentTarget;
9020			if (null == jsDD.current_node || null == jsDD.current_node.__bxddid)
9021			{
9022				jsDD.current_node = null;
9023				return;
9024			}
9025		}
9026		else
9027		{
9028			jsDD.current_node = e.srcElement;
9029			if (null == jsDD.current_node)
9030				return;
9031
9032			while (null == jsDD.current_node.__bxddid)
9033			{
9034				jsDD.current_node = jsDD.current_node.parentNode;
9035				if (jsDD.current_node.tagName == 'BODY')
9036					return;
9037			}
9038		}
9039
9040		jsDD.bStarted = false;
9041		jsDD.bPreStarted = true;
9042
9043		jsDD.wndSize = BX.GetWindowSize();
9044
9045		jsDD.start_x = e.clientX + jsDD.wndSize.scrollLeft;
9046		jsDD.start_y = e.clientY + jsDD.wndSize.scrollTop;
9047
9048		BX.bind(document, "mouseup", jsDD.stopDrag);
9049		BX.bind(document, "touchend", jsDD.stopDrag);
9050		BX.bind(document, "mousemove", jsDD.drag);
9051		BX.bind(document, "touchmove", jsDD.drag);
9052		BX.bind(window, 'scroll', jsDD._onscroll);
9053
9054		if(document.body.setCapture)
9055			document.body.setCapture();
9056
9057		if (!jsDD.bDisableDestRefresh)
9058			jsDD.refreshDestArea();
9059
9060		jsDD.setContainersPos();
9061
9062		if(e.type !== "touchstart")
9063		{
9064			jsDD.denySelection();
9065			return BX.PreventDefault(e);
9066		}
9067		else
9068		{
9069			return true;
9070		}
9071	},
9072
9073	start: function()
9074	{
9075		if (jsDD.bDisable)
9076			return true;
9077
9078		document.body.style.cursor = 'move';
9079
9080		if (jsDD.current_node.onbxdragstart)
9081			jsDD.current_node.onbxdragstart();
9082
9083		for (var i = 0, cnt = jsDD.arDestinations.length; i < cnt; i++)
9084		{
9085			if (jsDD.arDestinations[i] && jsDD.arDestinations[i].onbxdestdragstart)
9086				jsDD.arDestinations[i].onbxdestdragstart(jsDD.current_node);
9087		}
9088
9089		jsDD.bStarted = true;
9090		jsDD.bPreStarted = false;
9091
9092		if (jsDD.bScrollWindow)
9093		{
9094			if (jsDD.scrollViewTimer)
9095				clearInterval(jsDD.scrollViewTimer);
9096
9097			jsDD.scrollViewTimer = setInterval(jsDD._checkScroll, jsDD.scrollViewConfig.checkerTimeout);
9098		}
9099
9100		BX.bind(document, 'keypress', this._checkEsc);
9101	},
9102
9103	drag: function(e)
9104	{
9105		if (jsDD.bDisable)
9106			return true;
9107
9108		e = e || window.event;
9109
9110		jsDD.x = e.clientX + jsDD.wndSize.scrollLeft;
9111		jsDD.y = e.clientY + jsDD.wndSize.scrollTop;
9112
9113		if (!jsDD.bStarted)
9114		{
9115			var delta = 5;
9116			if(jsDD.x >= jsDD.start_x-delta && jsDD.x <= jsDD.start_x+delta && jsDD.y >= jsDD.start_y-delta && jsDD.y <= jsDD.start_y+delta)
9117				return true;
9118
9119			jsDD.start();
9120		}
9121
9122		if (jsDD.current_node.onbxdrag)
9123		{
9124			jsDD.current_node.onbxdrag(jsDD.x, jsDD.y, e);
9125		}
9126
9127		var containersScroll = jsDD.getContainersScrollPos(jsDD.x, jsDD.y);
9128		var current_dest_index = jsDD.searchDest(jsDD.x+containersScroll.left, jsDD.y+containersScroll.top);
9129
9130		if (current_dest_index !== jsDD.current_dest_index)
9131		{
9132			if (jsDD.current_dest_index !== false)
9133			{
9134				if (jsDD.current_node.onbxdraghout)
9135					jsDD.current_node.onbxdraghout(jsDD.arDestinations[jsDD.current_dest_index], jsDD.x, jsDD.y);
9136
9137				if (jsDD.arDestinations[jsDD.current_dest_index].onbxdestdraghout)
9138					jsDD.arDestinations[jsDD.current_dest_index].onbxdestdraghout(jsDD.current_node, jsDD.x, jsDD.y);
9139			}
9140
9141			if (current_dest_index !== false)
9142			{
9143				if (jsDD.current_node.onbxdraghover)
9144					jsDD.current_node.onbxdraghover(jsDD.arDestinations[current_dest_index], jsDD.x, jsDD.y);
9145
9146				if (jsDD.arDestinations[current_dest_index].onbxdestdraghover)
9147					jsDD.arDestinations[current_dest_index].onbxdestdraghover(jsDD.current_node, jsDD.x, jsDD.y);
9148			}
9149		}
9150
9151		jsDD.current_dest_index = current_dest_index;
9152	},
9153
9154	stopDrag: function(e)
9155	{
9156		BX.unbind(document, 'keypress', jsDD._checkEsc);
9157
9158		e = e || window.event;
9159
9160		jsDD.bPreStarted = false;
9161
9162		if (jsDD.bStarted)
9163		{
9164			if (!jsDD.bEscPressed)
9165			{
9166				jsDD.x = e.clientX + jsDD.wndSize.scrollLeft;
9167				jsDD.y = e.clientY + jsDD.wndSize.scrollTop;
9168			}
9169
9170			if (null != jsDD.current_node.onbxdragstop)
9171				jsDD.current_node.onbxdragstop(jsDD.x, jsDD.y, e);
9172
9173			var containersScroll = jsDD.getContainersScrollPos(jsDD.x, jsDD.y);
9174			var dest_index = jsDD.searchDest(jsDD.x+containersScroll.left, jsDD.y+containersScroll.top);
9175
9176			if (false !== dest_index)
9177			{
9178				if (jsDD.bEscPressed)
9179				{
9180					if (null != jsDD.arDestinations[dest_index].onbxdestdraghout)
9181					{
9182						if (!jsDD.arDestinations[dest_index].onbxdestdraghout(jsDD.current_node, jsDD.x, jsDD.y))
9183							dest_index = false;
9184						else
9185						{
9186							if (null != jsDD.current_node.onbxdragfinish)
9187								jsDD.current_node.onbxdragfinish(jsDD.arDestinations[dest_index], jsDD.x, jsDD.y);
9188						}
9189					}
9190
9191				}
9192				else
9193				{
9194					if (null != jsDD.arDestinations[dest_index].onbxdestdragfinish)
9195					{
9196						if (!jsDD.arDestinations[dest_index].onbxdestdragfinish(jsDD.current_node, jsDD.x, jsDD.y, e))
9197							dest_index = false;
9198						else
9199						{
9200							if (null != jsDD.current_node.onbxdragfinish)
9201								jsDD.current_node.onbxdragfinish(jsDD.arDestinations[dest_index], jsDD.x, jsDD.y);
9202						}
9203					}
9204				}
9205			}
9206
9207			if (false === dest_index)
9208			{
9209				if (null != jsDD.current_node.onbxdragrelease)
9210					jsDD.current_node.onbxdragrelease(jsDD.x, jsDD.y);
9211			}
9212			else
9213			{
9214				for (var i = 0, cnt = jsDD.arDestinations.length; i < cnt; i++)
9215				{
9216					if (i != dest_index && jsDD.arDestinations[i] && null != jsDD.arDestinations[i].onbxdestdragrelease)
9217						jsDD.arDestinations[i].onbxdestdragrelease(jsDD.current_node, jsDD.x, jsDD.y);
9218				}
9219			}
9220
9221			for (var i = 0, cnt = jsDD.arDestinations.length; i < cnt; i++)
9222			{
9223				if (jsDD.arDestinations[i] && null != jsDD.arDestinations[i].onbxdestdragstop)
9224					jsDD.arDestinations[i].onbxdestdragstop(jsDD.current_node, jsDD.x, jsDD.y);
9225			}
9226		}
9227
9228		if(document.body.releaseCapture)
9229			document.body.releaseCapture();
9230
9231		BX.unbind(window, 'scroll', jsDD._onscroll);
9232		BX.unbind(document, "mousemove", jsDD.drag);
9233		BX.unbind(document, "touchmove", jsDD.drag);
9234		BX.unbind(document, "keypress", jsDD._checkEsc);
9235		BX.unbind(document, "mouseup", jsDD.stopDrag);
9236		BX.unbind(document, "touchend", jsDD.stopDrag);
9237
9238		jsDD.allowSelection();
9239		document.body.style.cursor = '';
9240
9241		jsDD.current_node = null;
9242		jsDD.current_dest_index = false;
9243
9244		if (jsDD.bScrollWindow)
9245		{
9246			if (jsDD.scrollViewTimer)
9247				clearInterval(jsDD.scrollViewTimer);
9248		}
9249
9250		if (jsDD.bStarted && !jsDD.bDisableDestRefresh)
9251			jsDD.refreshDestArea();
9252
9253		jsDD.bStarted = false;
9254		jsDD.bEscPressed = false;
9255	},
9256
9257	searchDest: function(x, y)
9258	{
9259		var p, len, p1, len1, i;
9260		for (p = 0, len = jsDD.arDestinationsPriority.length; p < len; p++)
9261		{
9262			if (jsDD.arDestinationsPriority[p] && BX.type.isArray(jsDD.arDestinationsPriority[p]))
9263			{
9264				for (p1 = 0, len1 = jsDD.arDestinationsPriority[p].length; p1 < len1; p1++)
9265				{
9266					i = jsDD.arDestinationsPriority[p][p1];
9267					if (jsDD.arDestinations[i] && !jsDD.arDestinations[i].__bxdddisabled)
9268					{
9269						if (
9270							jsDD.arDestinations[i].__bxpos[0] <= x &&
9271							jsDD.arDestinations[i].__bxpos[2] >= x &&
9272
9273							jsDD.arDestinations[i].__bxpos[1] <= y &&
9274							jsDD.arDestinations[i].__bxpos[3] >= y
9275							)
9276						{
9277							return i;
9278						}
9279					}
9280				}
9281			}
9282		}
9283
9284		return false;
9285	},
9286
9287	allowSelection: function()
9288	{
9289		document.onmousedown = document.ontouchstart = null;
9290		var b = document.body;
9291		b.ondrag = null;
9292		b.onselectstart = null;
9293		b.style.MozUserSelect = '';
9294
9295		if (jsDD.current_node)
9296		{
9297			jsDD.current_node.ondrag = null;
9298			jsDD.current_node.onselectstart = null;
9299			jsDD.current_node.style.MozUserSelect = '';
9300		}
9301	},
9302
9303	denySelection: function()
9304	{
9305		document.onmousedown = document.ontouchstart = BX.False;
9306		var b = document.body;
9307		b.ondrag = BX.False;
9308		b.onselectstart = BX.False;
9309		b.style.MozUserSelect = 'none';
9310		if (jsDD.current_node)
9311		{
9312			jsDD.current_node.ondrag = BX.False;
9313			jsDD.current_node.onselectstart = BX.False;
9314			jsDD.current_node.style.MozUserSelect = 'none';
9315		}
9316	},
9317
9318	Disable: function() {jsDD.bDisable = true;},
9319	Enable: function() {jsDD.bDisable = false;}
9320}
9321
9322})();
9323
9324/* End */
9325;
9326; /* Start:"a:4:{s:4:"full";s:47:"/bitrix/js/main/core/core_uf.js?167415717618700";s:6:"source";s:31:"/bitrix/js/main/core/core_uf.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
9327;(function ()
9328{
9329	'use strict';
9330
9331	BX.namespace('BX.Main.UF');
9332
9333	if (typeof BX.Main.UF.Manager !== 'undefined')
9334	{
9335		return;
9336	}
9337
9338	var fieldStack = {};
9339
9340	/**
9341	 * Dynamic form manager. Initilized as singleton below
9342	 *
9343	 * @constructor
9344	 */
9345
9346	BX.Main.UF.Manager = function ()
9347	{
9348		this.mode = this.mode || '';
9349		this.ajaxUrl = '/bitrix/tools/uf.php';
9350	};
9351
9352
9353	BX.Main.UF.Manager.getEdit = function (param, callback)
9354	{
9355		return BX.Main.UF.EditManager.get(param, callback);
9356	};
9357
9358	BX.Main.UF.Manager.getView = function (param, callback)
9359	{
9360		return BX.Main.UF.ViewManager.get(param, callback);
9361	};
9362
9363	BX.Main.UF.Manager.prototype.get = function (param, callback)
9364	{
9365		if (!this.mode)
9366		{
9367			this.displayError([
9368				'No mode set. Use BX.UF.EditManager or BX.UF.ViewManager'
9369			]);
9370
9371			return;
9372		}
9373
9374		return this.query(this.mode, {
9375			FIELDS: param.FIELDS,
9376			FORM: param.FORM || '',
9377			CONTEXT: param.CONTEXT || '',
9378			MEDIA_TYPE: param.MEDIA_TYPE || ''
9379		}, callback);
9380	};
9381
9382	BX.Main.UF.Manager.prototype.add = function (param, callback)
9383	{
9384		if (!this.mode)
9385		{
9386			this.displayError([
9387				'No mode set. Use BX.UF.EditManager or BX.UF.ViewManager'
9388			]);
9389
9390			return;
9391		}
9392
9393		return this.query(this.mode, {
9394			action: 'add',
9395			FIELDS: param.FIELDS,
9396			FORM: param.FORM || ''
9397		}, callback);
9398	};
9399
9400	BX.Main.UF.Manager.prototype.update = function (param, callback)
9401	{
9402		if (!this.mode)
9403		{
9404			this.displayError([
9405				'No mode set. Use BX.UF.EditManager or BX.UF.ViewManager'
9406			]);
9407
9408			return;
9409		}
9410
9411		return this.query(this.mode, {
9412			action: 'update',
9413			FIELDS: param.FIELDS,
9414			FORM: param.FORM || ''
9415		}, callback);
9416	};
9417
9418	BX.Main.UF.Manager.prototype.delete = function (param, callback)
9419	{
9420		if (!this.mode)
9421		{
9422			this.displayError([
9423				'No mode set. Use BX.UF.EditManager or BX.UF.ViewManager'
9424			]);
9425
9426			return;
9427		}
9428
9429		return this.query(this.mode, {
9430			action: 'delete',
9431			FIELDS: param.FIELDS,
9432			FORM: param.FORM || ''
9433		}, callback);
9434	};
9435
9436	BX.Main.UF.Manager.prototype.query = function (mode, param, callback)
9437	{
9438		BX.ajax({
9439			dataType: 'json',
9440			url: this.ajaxUrl,
9441			method: 'POST',
9442			data: this.prepareQuery(mode, param),
9443			onsuccess: this.queryCallback(callback)
9444		});
9445	};
9446
9447	BX.Main.UF.Manager.prototype.prepareQuery = function (mode, param)
9448	{
9449		var p = param || {};
9450
9451		p.mode = mode;
9452		p.lang = BX.message('LANGUAGE_ID') || '';
9453		p.tpl = BX.message('UF_SITE_TPL') || '';
9454		p.tpls = BX.message('UF_SITE_TPL_SIGN') || '';
9455		p.sessid = BX.bitrix_sessid();
9456
9457		return p;
9458	};
9459
9460	BX.Main.UF.Manager.prototype.queryCallback = function (callback)
9461	{
9462		var processResult = BX.proxy(this.processResult, this);
9463		return function (result)
9464		{
9465			processResult(result, callback);
9466		}
9467	};
9468
9469	BX.Main.UF.Manager.prototype.processResult = function (result, callback)
9470	{
9471		var asset = '';
9472		if (BX.type.isArray(result.ASSET))
9473		{
9474			asset += result.ASSET.join('\n');
9475		}
9476
9477		if (!!result.ERROR)
9478		{
9479			this.displayError(result.ERROR);
9480		}
9481
9482		return BX.html(null, asset).then(function ()
9483		{
9484			if (!!callback)
9485			{
9486				callback(result.FIELD);
9487			}
9488		});
9489	};
9490
9491	BX.Main.UF.Manager.prototype.displayError = function (errorList)
9492	{
9493		for (var i in errorList)
9494		{
9495			if (errorList.hasOwnProperty(i))
9496			{
9497				console.error(errorList[i]);
9498			}
9499		}
9500	};
9501
9502	BX.Main.UF.Manager.prototype.registerField = function (field, fieldDescription, node)
9503	{
9504		fieldStack[field] = {
9505			FIELD: fieldDescription,
9506			NODE: node
9507		};
9508	};
9509
9510	BX.Main.UF.Manager.prototype.unRegisterField = function (field)
9511	{
9512		if (!!fieldStack[field])
9513		{
9514			delete fieldStack[field];
9515		}
9516	};
9517
9518
9519	BX.Main.UF.ViewManager = function ()
9520	{
9521		BX.Main.UF.ViewManager.superclass.constructor.apply(this, arguments);
9522
9523		this.mode = 'main.view';
9524	};
9525	BX.extend(BX.Main.UF.ViewManager, BX.Main.UF.Manager);
9526
9527	BX.Main.UF.EditManager = function ()
9528	{
9529		BX.Main.UF.EditManager.superclass.constructor.apply(this, arguments);
9530
9531		this.mode = 'main.edit';
9532	};
9533	BX.extend(BX.Main.UF.EditManager, BX.Main.UF.Manager);
9534
9535	BX.Main.UF.EditManager.prototype.validate = function (fieldList, callback)
9536	{
9537		if (fieldList.length > 0)
9538		{
9539			var request = [];
9540			for (var i = 0; i < fieldList.length; i++)
9541			{
9542				var value = BX.Main.UF.Factory.getValue(fieldList[i]);
9543				if (value !== null)
9544				{
9545					request.push({
9546						'ENTITY_ID': fieldStack[fieldList[i]].FIELD.ENTITY_ID,
9547						'FIELD': fieldStack[fieldList[i]].FIELD.FIELD,
9548						'ENTITY_VALUE_ID': fieldStack[fieldList[i]].FIELD.ENTITY_VALUE_ID,
9549						'VALUE': value
9550					});
9551				}
9552			}
9553
9554			return this.query(this.mode, {
9555				action: 'validate',
9556				FIELDS: request
9557			}, callback);
9558		}
9559		else
9560		{
9561			this.queryCallback(callback)({'FIELD': []});
9562		}
9563	};
9564
9565	/**
9566	 * Base type handler class. Will be initialized in Factory.
9567	 *
9568	 * @constructor
9569	 */
9570
9571	BX.Main.UF.BaseType = function ()
9572	{
9573	};
9574
9575	BX.Main.UF.BaseType.prototype.addRow = function (fieldName, thisButton)
9576	{
9577		var element = thisButton.parentNode.getElementsByTagName('span');
9578		if (element && element.length > 0 && element[0])
9579		{
9580			var parentElement = element[0].parentNode; // parent
9581			var newNode = this.getClone(element[element.length - 1], fieldName);
9582
9583			if (parentElement === thisButton.parentNode)
9584			{
9585				parentElement.insertBefore(newNode, thisButton);
9586			}
9587			else
9588			{
9589				parentElement.appendChild(newNode);
9590			}
9591		}
9592	};
9593
9594	/**
9595	 * @deprecated
9596	 * @param fieldName
9597	 * @param thisButton
9598	 */
9599	BX.Main.UF.BaseType.prototype.addMobileRow = function (fieldName, thisButton)
9600	{
9601		var element = thisButton.parentNode.getElementsByTagName('span');
9602		if (element && element.length && element[0])
9603		{
9604			var parentElement = element[0].parentNode; // parent
9605			var newNode = this.getClone(element[element.length - 1], fieldName);
9606			var firstChildren = newNode.firstElementChild;
9607			var name = firstChildren.getAttribute('name');
9608			var re = /\[(\d)]/;
9609			var newName = name.replace(re, function (match, index)
9610			{
9611				index = parseInt(index) + 1;
9612				return '[' + index + ']';
9613			});
9614			var newItemId = false;
9615			var prevItemName = false;
9616			var userFieldTypeName = null;
9617
9618			firstChildren.setAttribute('name', newName);
9619
9620			if (firstChildren.hasChildNodes())
9621			{
9622				firstChildren.childNodes.forEach(
9623					function (item, index, array)
9624					{
9625						if (!prevItemName && item.attributes !== undefined && item.tagName === 'INPUT')
9626						{
9627							item.setAttribute('name', newName);
9628							prevItemName = item.getAttribute('id');
9629							newItemId = prevItemName + '_1';
9630							userFieldTypeName = item.getAttribute('data-user-field-type-name');
9631						}
9632
9633						if (prevItemName && item.attributes !== undefined && item.id !== undefined)
9634						{
9635							var id = item.getAttribute('id');
9636
9637							if (id !== prevItemName)
9638							{
9639								item.setAttribute('id', id.replace(prevItemName, newItemId));
9640							}
9641							else
9642							{
9643								item.setAttribute('id', newItemId);
9644							}
9645						}
9646					}
9647				);
9648			}
9649
9650			if (parentElement === thisButton.parentNode)
9651			{
9652				parentElement.insertBefore(newNode, thisButton);
9653			}
9654			else
9655			{
9656				parentElement.appendChild(newNode);
9657			}
9658
9659			if (newItemId)
9660			{
9661				BX.onCustomEvent(
9662					'onAddMobileUfField',
9663					[newItemId, userFieldTypeName]
9664				);
9665			}
9666
9667		}
9668	};
9669
9670	BX.Main.UF.BaseType.prototype.getClone = function (node, fieldName)
9671	{
9672		var newNode = node.cloneNode(true);
9673
9674		var inputList = this.findInput(newNode, fieldName);
9675		for (var i = 0; i < inputList.length; i++)
9676		{
9677			inputList[i].value = '';
9678		}
9679
9680		return newNode;
9681	};
9682
9683	BX.Main.UF.BaseType.prototype.findInput = function (node, fieldName)
9684	{
9685		return BX.findChildren(node, {
9686			tagName: /INPUT|TEXTAREA|SELECT/i,
9687			attribute: {
9688				name: fieldName
9689			}
9690		}, true);
9691	};
9692
9693	BX.Main.UF.BaseType.prototype.isEmpty = function (field)
9694	{
9695		var node = this.getNode(field),
9696			fieldName = field + (
9697				fieldStack[field].FIELD.MULTIPLE === 'Y'
9698					? '[]'
9699					: ''
9700			);
9701
9702		if (!BX.isNodeInDom(node))
9703		{
9704			console.error('Node for field ' + field + ' is already removed from DOM');
9705		}
9706
9707		var nodeList = this.findInput(node, fieldName);
9708
9709		if (nodeList.length <= 0)
9710		{
9711			console.error('Unable to find field ' + field + ' in the registered node');
9712		}
9713		else
9714		{
9715			for (var i = 0; i < nodeList.length; i++)
9716			{
9717				if (nodeList[i].value !== '')
9718				{
9719					return false;
9720				}
9721			}
9722		}
9723
9724		return true;
9725	};
9726
9727	BX.Main.UF.BaseType.prototype.getValue = function (field)
9728	{
9729		var node = this.getNode(field),
9730			fieldName = field + (
9731				fieldStack[field].FIELD.MULTIPLE === 'Y'
9732					? '[]'
9733					: ''
9734			),
9735			value = fieldStack[field].FIELD.MULTIPLE === 'Y' ? [] : '';
9736
9737		if (!BX.isNodeInDom(node))
9738		{
9739			console.error('Node for field ' + field + ' is already removed from DOM');
9740		}
9741		var nodeList = this.findInput(node, fieldName);
9742
9743		if (nodeList.length <= 0)
9744		{
9745			var nodeChildren = (node.children.length ? node.children[0] : false);
9746			/**
9747			 * @todo remove !BX.util.in_array(fieldStack[field].FIELD.USER_TYPE_ID, ['crm', 'employee'])
9748			 * after deploy new Crm and Employee types
9749			 */
9750			if (
9751				!BX.util.in_array(fieldStack[field].FIELD.USER_TYPE_ID, ['crm', 'employee'])
9752				&&
9753				(
9754					!nodeChildren
9755					||
9756					nodeChildren.getAttribute('data-has-input') !== 'no'
9757				)
9758			)
9759			{
9760				console.error('Unable to find field ' + field + ' in the registered node');
9761			}
9762		}
9763		else
9764		{
9765			for (var i = 0; i < nodeList.length; i++)
9766			{
9767				if (
9768					nodeList[i].tagName === 'INPUT'
9769					&& (nodeList[i].type === 'radio' || nodeList[i].type === 'checkbox')
9770					&& !nodeList[i].checked
9771				)
9772				{
9773					continue;
9774				}
9775
9776				if (fieldStack[field].FIELD.MULTIPLE === 'Y')
9777				{
9778					value.push(nodeList[i].value);
9779				}
9780				else
9781				{
9782					value = nodeList[i].value;
9783					break;
9784				}
9785			}
9786		}
9787
9788		return value;
9789	};
9790
9791	BX.Main.UF.BaseType.prototype.focus = function (field)
9792	{
9793		var node = this.getNode(field),
9794			fieldName = field + (
9795				fieldStack[field].FIELD.MULTIPLE === 'Y'
9796					? '[]'
9797					: ''
9798			);
9799
9800		if (!BX.isNodeInDom(node))
9801		{
9802			console.error('Node for field ' + field + ' is already removed from DOM');
9803		}
9804		var nodeList = this.findInput(node, fieldName);
9805
9806		if (nodeList.length > 0)
9807		{
9808			BX.focus(nodeList[0]);
9809		}
9810	};
9811
9812	BX.Main.UF.BaseType.prototype.getNode = function (field)
9813	{
9814		return fieldStack[field].NODE;
9815	};
9816
9817	/**
9818	 * Integer type handler class. Will be initialized in Factory.
9819	 *
9820	 * @constructor
9821	 */
9822	BX.Main.UF.TypeBoolean = function ()
9823	{
9824	};
9825	BX.extend(BX.Main.UF.TypeBoolean, BX.Main.UF.BaseType);
9826
9827	BX.Main.UF.TypeBoolean.USER_TYPE_ID = 'boolean';
9828
9829	BX.Main.UF.TypeBoolean.prototype.isEmpty = function (field)
9830	{
9831		return false;
9832	};
9833
9834	/**
9835	 * Integer type handler class. Will be initialized in Factory.
9836	 *
9837	 * @constructor
9838	 */
9839	BX.Main.UF.TypeInteger = function ()
9840	{
9841	};
9842	BX.extend(BX.Main.UF.TypeInteger, BX.Main.UF.BaseType);
9843
9844	BX.Main.UF.TypeInteger.USER_TYPE_ID = 'integer';
9845
9846	/**
9847	 * Double type handler class. Will be initialized in Factory.
9848	 *
9849	 * @constructor
9850	 */
9851	BX.Main.UF.TypeDouble = function ()
9852	{
9853	};
9854	BX.extend(BX.Main.UF.TypeDouble, BX.Main.UF.BaseType);
9855
9856	BX.Main.UF.TypeDouble.USER_TYPE_ID = 'double';
9857
9858	/**
9859	 * String type handler class. Will be initialized in Factory.
9860	 *
9861	 * @constructor
9862	 */
9863	BX.Main.UF.TypeSting = function ()
9864	{
9865	};
9866	BX.extend(BX.Main.UF.TypeSting, BX.Main.UF.BaseType);
9867
9868	BX.Main.UF.TypeSting.USER_TYPE_ID = 'string';
9869
9870	/**
9871	 * URL type handler class. Will be initialized in Factory.
9872	 *
9873	 * @constructor
9874	 */
9875	BX.Main.UF.TypeUrl = function ()
9876	{
9877	};
9878	BX.extend(BX.Main.UF.TypeUrl, BX.Main.UF.BaseType);
9879
9880	BX.Main.UF.TypeUrl.USER_TYPE_ID = 'url';
9881
9882	/**
9883	 * Formatted string type handler class. Will be initialized in Factory.
9884	 *
9885	 * @constructor
9886	 */
9887	BX.Main.UF.TypeStingFormatted = function ()
9888	{
9889	};
9890	BX.extend(BX.Main.UF.TypeStingFormatted, BX.Main.UF.TypeSting);
9891
9892	BX.Main.UF.TypeStingFormatted.USER_TYPE_ID = 'string_formatted';
9893
9894
9895	/**
9896	 * Enumeration type handler class. Will be initialized in Factory.
9897	 *
9898	 * @constructor
9899	 */
9900	BX.Main.UF.TypeEnumeration = function ()
9901	{
9902	};
9903	BX.extend(BX.Main.UF.TypeEnumeration, BX.Main.UF.BaseType);
9904
9905	BX.Main.UF.TypeEnumeration.USER_TYPE_ID = 'enumeration';
9906
9907	BX.Main.UF.TypeEnumeration.prototype.findInput = function (node, fieldName)
9908	{
9909		var inputList = BX.Main.UF.TypeEnumeration.superclass.findInput.apply(this, arguments);
9910
9911		if (inputList.length > 0)
9912		{
9913			for (var i = 0; i < inputList.length; i++)
9914			{
9915				if (inputList[i].tagName === 'INPUT' && inputList[i].type === 'hidden' && inputList.length > 1)
9916				{
9917					delete inputList[i];
9918					break;
9919				}
9920			}
9921		}
9922
9923		return BX.util.array_values(inputList);
9924	};
9925
9926	BX.Main.UF.TypeEnumeration.prototype.focus = function (field)
9927	{
9928		if (fieldStack[field]
9929			&& fieldStack[field].FIELD.SETTINGS.DISPLAY === 'UI'
9930			&& BX.type.isElementNode(fieldStack[field].NODE)
9931		)
9932		{
9933			BX.fireEvent(fieldStack[field].NODE, 'focus');
9934		}
9935		else
9936		{
9937			BX.Main.UF.TypeEnumeration.superclass.focus.apply(this, arguments);
9938		}
9939	};
9940
9941	/**
9942	 * Date type handler class. Will be initialized in Factory.
9943	 *
9944	 * @constructor
9945	 */
9946	BX.Main.UF.TypeDate = function ()
9947	{
9948	};
9949	BX.extend(BX.Main.UF.TypeDate, BX.Main.UF.BaseType);
9950
9951	BX.Main.UF.TypeDate.USER_TYPE_ID = 'date';
9952
9953	BX.Main.UF.TypeDate.prototype.focus = function (field)
9954	{
9955		var fieldName = field + (
9956			fieldStack[field].FIELD.MULTIPLE === 'Y'
9957				? '[]'
9958				: ''
9959		);
9960		var inputList = this.findInput(this.getNode(field), fieldName);
9961
9962		if (inputList.length > 0)
9963		{
9964			BX.fireEvent(inputList[0], 'click');
9965		}
9966
9967		BX.Main.UF.TypeDate.superclass.focus.apply(this, arguments);
9968	};
9969
9970	/**
9971	 * Datetime type handler class. Will be initialized in Factory.
9972	 *
9973	 * @constructor
9974	 */
9975	BX.Main.UF.TypeDateTime = function ()
9976	{
9977	};
9978	BX.extend(BX.Main.UF.TypeDateTime, BX.Main.UF.TypeDate);
9979
9980	BX.Main.UF.TypeDateTime.USER_TYPE_ID = 'datetime';
9981
9982	/**
9983	 * Datetime type handler class. Will be initialized in Factory.
9984	 *
9985	 * @constructor
9986	 */
9987	BX.Main.UF.TypeFile = function ()
9988	{
9989	};
9990	BX.extend(BX.Main.UF.TypeFile, BX.Main.UF.BaseType);
9991
9992	BX.Main.UF.TypeFile.USER_TYPE_ID = 'file';
9993
9994	BX.Main.UF.TypeFile.prototype.findInput = function (node, fieldName)
9995	{
9996		var inputList = BX.Main.UF.TypeFile.superclass.findInput.apply(this, arguments);
9997
9998		if (inputList.length <= 0)
9999		{
10000			inputList = BX.findChildren(node, {
10001				tagName: /INPUT/i,
10002				attribute: {
10003					type: 'file',
10004					name: /^bxu_files/
10005				}
10006			}, true);
10007		}
10008
10009		return inputList;
10010	};
10011
10012	BX.Main.UF.TypeFile.prototype.getValue = function (field)
10013	{
10014		var
10015			baseValue = BX.Main.UF.TypeFile.superclass.getValue.apply(this, arguments),
10016			node = fieldStack[field].NODE,
10017			deletedNodeList = [],
10018			i;
10019
10020		if (fieldStack[field].FIELD.MULTIPLE === 'Y')
10021		{
10022			var deletedFieldName = field + '_del[]';
10023
10024			if (BX.type.isArray(baseValue) && baseValue.length > 0)
10025			{
10026				deletedNodeList = BX.Main.UF.TypeFile.superclass.findInput.apply(this, [node, deletedFieldName]);
10027
10028				for (i = 0; i < deletedNodeList.length; i++)
10029				{
10030					var pos = BX.util.array_search(deletedNodeList[i].value, baseValue);
10031					if (pos >= 0)
10032					{
10033						baseValue[pos] = {'old_id': deletedNodeList[i].value, 'del': 'Y', 'tmp_name': ''};
10034					}
10035				}
10036			}
10037
10038			return BX.util.array_values(baseValue);
10039		}
10040		else if (baseValue > 0)
10041		{
10042			var deletedFieldName = field + '_del';
10043
10044			deletedNodeList = BX.Main.UF.TypeFile.superclass.findInput.apply(this, [node, deletedFieldName]);
10045
10046			for (i = 0; i < deletedNodeList.length; i++)
10047			{
10048				if (baseValue == deletedNodeList[i].value)
10049				{
10050					baseValue = {'old_id': baseValue, 'del': 'Y', 'tmp_name': ''};
10051					break;
10052				}
10053			}
10054
10055			return baseValue;
10056		}
10057	};
10058
10059
10060	/**
10061	 * Type handler Factory singleton. Will be initialized below.
10062	 *
10063	 * @constructor
10064	 */
10065	BX.Main.UF.Factory = function ()
10066	{
10067		this.defaultTypeHandler = BX.Main.UF.BaseType;
10068
10069		this.typeHandlerList = {};
10070		this.objectCollection = {};
10071	};
10072
10073	BX.Main.UF.Factory.prototype.setTypeHandler = function (type, handlerClass)
10074	{
10075		this.typeHandlerList[type] = handlerClass;
10076		if (typeof this.objectCollection[type] !== 'undefined')
10077		{
10078			delete this.objectCollection[type];
10079		}
10080	};
10081
10082	BX.Main.UF.Factory.prototype.get = function (type)
10083	{
10084		if (typeof this.objectCollection[type] === 'undefined')
10085		{
10086			this.objectCollection[type] = this.getObject(type);
10087		}
10088
10089		return this.objectCollection[type];
10090	};
10091
10092	BX.Main.UF.Factory.prototype.getObject = function (type)
10093	{
10094		return new (this.typeHandlerList[type] || this.defaultTypeHandler);
10095	};
10096
10097	BX.Main.UF.Factory.prototype.getFieldObject = function (field)
10098	{
10099		if (typeof fieldStack[field] === 'undefined')
10100		{
10101			console.error('Field ' + field + 'is not registered. Use BX.Main.UF.Factory.registerField to register');
10102
10103			return null;
10104		}
10105
10106		return this.get(fieldStack[field]['FIELD']['USER_TYPE_ID']);
10107	};
10108
10109	BX.Main.UF.Factory.prototype.isEmpty = function (field)
10110	{
10111		if (typeof fieldStack[field] === 'undefined')
10112		{
10113			console.error('Field ' + field + 'is not registered. Use BX.Main.UF.Factory.registerField to register');
10114
10115			return true;
10116		}
10117
10118		return this.get(fieldStack[field]['FIELD']['USER_TYPE_ID']).isEmpty(field);
10119	};
10120
10121	BX.Main.UF.Factory.prototype.getValue = function (field)
10122	{
10123		if (typeof fieldStack[field] === 'undefined')
10124		{
10125			console.error('Field ' + field + 'is not registered. Use BX.Main.UF.Factory.registerField to register');
10126
10127			return null;
10128		}
10129
10130		return this.get(fieldStack[field]['FIELD']['USER_TYPE_ID']).getValue(field);
10131	};
10132
10133	BX.Main.UF.Factory.prototype.focus = function (field)
10134	{
10135		if (typeof fieldStack[field] === 'undefined')
10136		{
10137			console.error('Field ' + field + 'is not registered. Use BX.Main.UF.Factory.registerField to register');
10138		}
10139
10140		return this.get(fieldStack[field]['FIELD']['USER_TYPE_ID']).focus(field);
10141	};
10142
10143	/**
10144	 * Singletons initialization
10145	 */
10146
10147	BX.Main.UF.EditManager = new BX.Main.UF.EditManager();
10148	BX.Main.UF.ViewManager = new BX.Main.UF.ViewManager();
10149	BX.Main.UF.Factory = new BX.Main.UF.Factory();
10150
10151	BX.Main.UF.Factory.setTypeHandler(BX.Main.UF.TypeBoolean.USER_TYPE_ID, BX.Main.UF.TypeBoolean);
10152	BX.Main.UF.Factory.setTypeHandler(BX.Main.UF.TypeInteger.USER_TYPE_ID, BX.Main.UF.TypeInteger);
10153	BX.Main.UF.Factory.setTypeHandler(BX.Main.UF.TypeDouble.USER_TYPE_ID, BX.Main.UF.TypeDouble);
10154	BX.Main.UF.Factory.setTypeHandler(BX.Main.UF.TypeSting.USER_TYPE_ID, BX.Main.UF.TypeSting);
10155	BX.Main.UF.Factory.setTypeHandler(BX.Main.UF.TypeStingFormatted.USER_TYPE_ID, BX.Main.UF.TypeStingFormatted);
10156	BX.Main.UF.Factory.setTypeHandler(BX.Main.UF.TypeEnumeration.USER_TYPE_ID, BX.Main.UF.TypeEnumeration);
10157	BX.Main.UF.Factory.setTypeHandler(BX.Main.UF.TypeFile.USER_TYPE_ID, BX.Main.UF.TypeFile);
10158	BX.Main.UF.Factory.setTypeHandler(BX.Main.UF.TypeDate.USER_TYPE_ID, BX.Main.UF.TypeDate);
10159	BX.Main.UF.Factory.setTypeHandler(BX.Main.UF.TypeDateTime.USER_TYPE_ID, BX.Main.UF.TypeDateTime);
10160})();
10161/* End */
10162;
10163; /* Start:"a:4:{s:4:"full";s:46:"/bitrix/js/main/core/core_dd.js?16741571763613";s:6:"source";s:31:"/bitrix/js/main/core/core_dd.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
10164(function(window){
10165BX.DD = function(params)
10166{
10167	return new BX.DD.dragdrop(params);
10168}
10169
10170BX.DD.allowSelection = function()
10171{
10172	document.onmousedown = null;
10173	var b = document.body;
10174	b.ondrag = null;
10175	b.onselectstart = null;
10176	b.style.MozUserSelect = '';
10177	
10178	// if (jsDD.current_node)
10179	// {
10180		// jsDD.current_node.ondrag = null;
10181		// jsDD.current_node.onselectstart = null;
10182		// jsDD.current_node.style.MozUserSelect = '';
10183	// }
10184}
10185	
10186BX.DD.denySelection = function()
10187{
10188	document.onmousedown = BX.False;
10189	var b = document.body;
10190	b.ondrag = BX.False;
10191	b.onselectstart = BX.False;
10192	b.style.MozUserSelect = 'none';
10193	// if (jsDD.current_node) 
10194	// {
10195		// jsDD.current_node.ondrag = jsUtils.False;
10196		// jsDD.current_node.onselectstart = jsUtils.False;
10197		// jsDD.current_node.style.MozUserSelect = 'none';
10198	// }
10199}
10200
10201BX.DD.dragdrop = function(params)
10202{
10203
10204
10205}
10206
10207/*
10208 * BX.DD.dropFiles - for html5 drag and drop files
10209 *
10210 * example:
10211 *
10212 * BX(function() {
10213 *	  var dropBoxNode = BX('WebDAV23');
10214 *    var dropbox = new BX.DD.dropFiles(dropBoxNode);
10215 *    if (dropbox && dropbox.supported())
10216 *    {
10217 *        BX.addCustomEvent(dropbox, 'dropFiles', function(files) { WDUploadDroppedFiles(files);});
10218 *        BX.addCustomEvent(dropbox, 'dragEnter', function() {BX.addClass( dropBoxNode, 'droptarget');});
10219 *        BX.addCustomEvent(dropbox, 'dragLeave', function() {BX.removeClass( dropBoxNode, 'droptarget');});
10220 *    }
10221 * });
10222 *
10223 * to save files use BX.ajax.FormData
10224 */
10225BX.DD.dropFiles = function(div)
10226{
10227	if (BX.type.isElementNode(div)
10228		&& this.supported())
10229	{
10230		div.setAttribute('dropzone', 'copy f:*/*');
10231		this.DIV = div;
10232		this._timer = null;
10233		this._initEvents();
10234
10235		this._cancelLeave = function()
10236		{
10237			if (this._timer != null)
10238			{
10239				clearTimeout(this._timer);
10240				this._timer = null;
10241			}
10242		}
10243		this._prepareLeave = function()
10244		{
10245			this._cancelLeave();
10246			this._timer = setTimeout( BX.delegate(function() {
10247				BX.onCustomEvent(this, 'dragLeave')
10248			}, this), 100);
10249		}
10250
10251		return this;
10252	}
10253	return false;
10254}
10255
10256BX.DD.dropFiles.prototype._initEvents = function()
10257{
10258	BX.bind(this.DIV, 'dragover', BX.proxy(this._dragOver, this));
10259	BX.bind(this.DIV, 'dragenter', BX.proxy(this._dragEnter, this));
10260	BX.bind(this.DIV, 'dragleave', BX.proxy(this._dragLeave, this));
10261	BX.bind(this.DIV, 'dragexit', BX.proxy(this._dragExit, this));
10262	BX.bind(this.DIV, 'drop', BX.proxy(this._drop, this));
10263}
10264
10265BX.DD.dropFiles.prototype._dragEnter = function(e)
10266{
10267	BX.PreventDefault(e);
10268	this._cancelLeave();
10269	BX.onCustomEvent(this, 'dragEnter', [e]);
10270	return true;
10271}
10272
10273BX.DD.dropFiles.prototype._dragExit = function(e)
10274{
10275	BX.PreventDefault(e);
10276	this._prepareLeave();
10277	return false;
10278}
10279
10280
10281BX.DD.dropFiles.prototype._dragLeave = function(e)
10282{
10283	BX.PreventDefault(e);
10284	this._prepareLeave();
10285	return false;
10286}
10287
10288BX.DD.dropFiles.prototype._dragOver = function(e)
10289{
10290	BX.PreventDefault(e);
10291	this._cancelLeave();
10292	return true;
10293}
10294
10295BX.DD.dropFiles.prototype._drop = function(e)
10296{
10297	BX.PreventDefault(e);
10298	var dt = e.dataTransfer;
10299	var files = dt.files;
10300	BX.onCustomEvent(this, 'dropFiles', [files, e]);
10301	BX.onCustomEvent(this, 'dragLeave')
10302	return false;
10303}
10304
10305BX.DD.dropFiles.prototype.isEventSupported = function(event)
10306{
10307	var div = BX.create('DIV');
10308	var eventName = 'on'+event;
10309	var result = (eventName in div);
10310	
10311	if (!result && div.setAttribute && div.removeAttribute)
10312	{
10313		div.setAttribute(eventName, '');
10314		result = (typeof div[eventName] === 'function');
10315	}
10316
10317	div = null;
10318	return result;
10319}
10320
10321BX.DD.dropFiles.prototype.supported = function()
10322{
10323	return ( (!!window.FileReader) && this.isEventSupported('dragstart') && this.isEventSupported('drop') );
10324}
10325
10326})(window)
10327
10328
10329/* End */
10330;
10331; /* Start:"a:4:{s:4:"full";s:52:"/bitrix/js/main/core/core_tooltip.js?167415717615458";s:6:"source";s:36:"/bitrix/js/main/core/core_tooltip.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
10332(function(window) {
10333if (BX.tooltip) return;
10334
10335var arTooltipIndex = {},
10336	bDisable = false;
10337
10338BX.tooltip = function(user_id, anchor_name, loader, rootClassName, bForceUseLoader, params)
10339{
10340	if (BX.message('TOOLTIP_ENABLED') != "Y")
10341	{
10342		return;
10343	}
10344
10345	if (
10346		BX.browser.IsAndroid()
10347		|| BX.browser.IsIOS()
10348	)
10349	{
10350		return;
10351	}
10352
10353	BX.ready(function() {
10354		var anchor = BX(anchor_name);
10355		if (null == anchor)
10356		{
10357			return;
10358		}
10359
10360		var tooltipId = user_id;
10361		if(bForceUseLoader && BX.type.isNotEmptyString(loader))
10362		{
10363			// prepare tooltip ID from custom loader
10364			var loaderHash = 0;
10365			for(var i = 0, len = loader.length; i < len; i++)
10366			{
10367				loaderHash = (31 * loaderHash + loader.charCodeAt(i)) << 0;
10368			}
10369
10370			tooltipId = loaderHash + user_id;
10371		}
10372
10373		if (null == arTooltipIndex[tooltipId])
10374		{
10375			arTooltipIndex[tooltipId] = new BX.CTooltip(user_id, anchor, loader, rootClassName, bForceUseLoader, params);
10376		}
10377		else
10378		{
10379			arTooltipIndex[tooltipId].ANCHOR = anchor;
10380			arTooltipIndex[tooltipId].rootClassName = rootClassName;
10381			arTooltipIndex[tooltipId].LOADER = (
10382				bForceUseLoader
10383				&& BX.type.isNotEmptyString(loader)
10384					? loader
10385					: '/bitrix/tools/tooltip.php'
10386			);
10387			arTooltipIndex[tooltipId].params = params;
10388			arTooltipIndex[tooltipId].Create();
10389		}
10390	});
10391};
10392
10393BX.tooltip.disable = function(){ bDisable = true; };
10394BX.tooltip.enable = function(){ bDisable = false; };
10395
10396BX.tooltip.hide = function(userId) {
10397	if (BX('user_info_' + userId))
10398	{
10399		BX('user_info_' + userId).style.display = 'none';
10400	}
10401};
10402
10403BX.tooltip.openIM = function(userId) {
10404	if (top.BXIM)
10405	{
10406		top.BXIM.openMessenger(userId);
10407		BX.tooltip.hide(userId);
10408	}
10409	else if (BX('MULSonetMessageChatTemplate'))
10410	{
10411		window.open(BX('MULSonetMessageChatTemplate').replace('#user_id#', userId).replace('#USER_ID#', userId).replace('#ID#', userId), '', 'location=yes,status=no,scrollbars=yes,resizable=yes,width=700,height=550,top='+Math.floor((screen.height - 550)/2-14)+',left='+Math.floor((screen.width - 700)/2-5));
10412		BX.tooltip.hide(userId);
10413	}
10414	return false;
10415};
10416
10417
10418BX.tooltip.openCallTo = function(userId) {
10419	if (top.BXIM)
10420	{
10421		top.BXIM.callTo(userId);
10422		BX.tooltip.hide(userId);
10423	}
10424	return false;
10425};
10426
10427BX.tooltip.checkCallTo = function(nodeId) {
10428	if (
10429		!top.BXIM
10430		|| !top.BXIM.checkCallSupport()
10431	)
10432	{
10433		BX.remove(nodeId);
10434	}
10435};
10436
10437BX.tooltip.openVideoCall = function(userId) {
10438	if (BX('MULVideoCallTemplate'))
10439	{
10440		window.open(BX('MULVideoCallTemplate').replace('#user_id#', userId).replace('#USER_ID#', userId).replace('#ID#', userId), '', 'location=yes,status=no,scrollbars=yes,resizable=yes,width=1000,height=600,top='+Math.floor((screen.height - 600)/2-14)+',left='+Math.floor((screen.width - 1000)/2-5));
10441		BX.tooltip.hide(userId);
10442	}
10443	return false;
10444};
10445
10446BX.CTooltip = function(user_id, anchor, loader, rootClassName, bForceUseLoader, params)
10447{
10448	this.LOADER = (
10449		bForceUseLoader
10450		&& BX.type.isNotEmptyString(loader)
10451			? loader
10452			: '/bitrix/tools/tooltip.php'
10453	);
10454	this.USER_ID = user_id;
10455	this.ANCHOR = anchor;
10456	this.rootClassName = '';
10457	this.params = (typeof params != 'undefined' ? params : {});
10458
10459	if (
10460		rootClassName != 'undefined'
10461		&& rootClassName != null
10462		&& rootClassName.length > 0
10463	)
10464	{
10465		this.rootClassName = rootClassName;
10466	}
10467
10468	var old = document.getElementById('user_info_' + this.USER_ID);
10469	if (null != old)
10470	{
10471		if (null != old.parentNode)
10472			old.parentNode.removeChild(old);
10473
10474		old = null;
10475	}
10476
10477	var _this = this;
10478
10479	this.INFO = null;
10480
10481	this.width = 393;
10482	this.height = 302;
10483
10484	this.RealAnchor = null;
10485	this.CoordsLeft = 0;
10486	this.CoordsTop = 0;
10487	this.AnchorRight = 0;
10488	this.AnchorBottom = 0;
10489
10490	this.DIV = null;
10491	this.ROOT_DIV = null;
10492
10493	if (BX.browser.IsIE())
10494	{
10495		this.IFRAME = null;
10496	}
10497
10498	this.v_delta = 0;
10499	this.classNameAnim = false;
10500	this.classNameFixed = false;
10501
10502	this.left = 0;
10503	this.top = 0;
10504
10505	this.tracking = false;
10506	this.active = false;
10507	this.showed = false;
10508
10509	this.Create = function()
10510	{
10511		_this.ANCHOR.onmouseover = function() {
10512			if (!bDisable)
10513			{
10514				_this.StartTrackMouse(this);
10515			}
10516		};
10517
10518		_this.ANCHOR.onmouseout = function() {
10519			_this.StopTrackMouse(this);
10520		}
10521	};
10522
10523	this.Create();
10524
10525	this.TrackMouse = function(e)
10526	{
10527		if(!_this.tracking)
10528			return;
10529
10530		var current;
10531		if(e && e.pageX)
10532			current = {x: e.pageX, y: e.pageY};
10533		else
10534			current = {x: e.clientX + document.body.scrollLeft, y: e.clientY + document.body.scrollTop};
10535
10536		if(current.x < 0)
10537			current.x = 0;
10538		if(current.y < 0)
10539			current.y = 0;
10540
10541		current.time = _this.tracking;
10542
10543		if(!_this.active)
10544			_this.active = current;
10545		else
10546		{
10547			if(
10548				_this.active.x >= (current.x - 1) && _this.active.x <= (current.x + 1)
10549				&& _this.active.y >= (current.y - 1) && _this.active.y <= (current.y + 1)
10550			)
10551			{
10552				if((_this.active.time + 20/*2sec*/) <= current.time)
10553					_this.ShowTooltip();
10554			}
10555			else
10556				_this.active = current;
10557		}
10558	};
10559
10560	this.ShowTooltip = function()
10561	{
10562		var old = document.getElementById('user_info_' + _this.USER_ID);
10563		if(bDisable || old && old.style.display == 'block')
10564			return;
10565
10566		var bIE = (BX.browser.IsIE() && !BX.browser.IsIE10());
10567
10568		if (!BX.type.isPlainObject(this.params))
10569		{
10570			this.params = {};
10571		}
10572
10573		if (null == _this.DIV && null == _this.ROOT_DIV)
10574		{
10575			_this.ROOT_DIV = document.body.appendChild(document.createElement('DIV'));
10576			_this.ROOT_DIV.style.position = 'absolute';
10577
10578			BX.ZIndexManager.register(_this.ROOT_DIV);
10579
10580			_this.DIV = _this.ROOT_DIV.appendChild(document.createElement('DIV'));
10581			if (bIE)
10582				_this.DIV.className = 'bx-user-info-shadow-ie';
10583			else
10584				_this.DIV.className = 'bx-user-info-shadow';
10585
10586			_this.DIV.style.width = _this.width + 'px';
10587			_this.DIV.style.height = _this.height + 'px';
10588		}
10589
10590		var left = _this.CoordsLeft;
10591		var top = _this.CoordsTop + 30;
10592		var arScroll = BX.GetWindowScrollPos();
10593		var body = document.body;
10594
10595		var h_mirror = false;
10596		var v_mirror = false;
10597
10598		if((body.clientWidth + arScroll.scrollLeft) < (left + _this.width))
10599		{
10600			left = _this.AnchorRight - _this.width;
10601			h_mirror = true;
10602		}
10603
10604		if((top - arScroll.scrollTop) < 0)
10605		{
10606			top = _this.AnchorBottom - 5;
10607			v_mirror = true;
10608			_this.v_delta = 40;
10609		}
10610		else
10611			_this.v_delta = 0;
10612
10613		_this.ROOT_DIV.style.left = parseInt(left) + "px";
10614		_this.ROOT_DIV.style.top = parseInt(top) + "px";
10615
10616		BX.ZIndexManager.bringToFront(_this.ROOT_DIV);
10617
10618		BX.bind(BX(_this.ROOT_DIV), "click", BX.eventCancelBubble);
10619
10620		if (
10621			this.rootClassName != 'undefined'
10622			&& this.rootClassName != null
10623			&& this.rootClassName.length > 0
10624		)
10625			_this.ROOT_DIV.className = this.rootClassName;
10626
10627		if ('' == _this.DIV.innerHTML)
10628		{
10629			var url = _this.LOADER +
10630				(_this.LOADER.indexOf('?') >= 0 ? '&' : '?') +
10631				'MUL_MODE=INFO&USER_ID=' + _this.USER_ID +
10632				'&site=' + (BX.message('SITE_ID') || '') +
10633				(
10634					typeof _this.params != 'undefined'
10635					&& typeof _this.params.entityType != 'undefined'
10636					&& _this.params.entityType.length > 0
10637						? '&entityType=' + _this.params.entityType
10638						: ''
10639				) +
10640				(
10641					typeof _this.params != 'undefined'
10642					&& typeof _this.params.entityId != 'undefined'
10643					&& parseInt(_this.params.entityId) > 0
10644						? '&entityId=' + parseInt(_this.params.entityId)
10645						: ''
10646				);
10647
10648			BX.ajax.get(url, _this.InsertData);
10649			_this.DIV.id = 'user_info_' + _this.USER_ID;
10650
10651			_this.DIV.innerHTML = '<div class="bx-user-info-wrap">'
10652				+ '<div class="bx-user-info-leftcolumn">'
10653					+ '<div class="bx-user-photo" id="user-info-photo-' + _this.USER_ID + '"><div class="bx-user-info-data-loading">' + BX.message('JS_CORE_LOADING') + '</div></div>'
10654					+ '<div class="bx-user-tb-control bx-user-tb-control-left" id="user-info-toolbar-' + _this.USER_ID + '"></div>'
10655				+ '</div>'
10656				+ '<div class="bx-user-info-data">'
10657					+ '<div id="user-info-data-card-' + _this.USER_ID + '"></div>'
10658					+ '<div class="bx-user-info-data-tools">'
10659						+ '<div class="bx-user-tb-control bx-user-tb-control-right" id="user-info-toolbar2-' + _this.USER_ID + '"></div>'
10660						+ '<div class="bx-user-info-data-clear"></div>'
10661					+ '</div>'
10662				+ '</div>'
10663				+ '</div><div class="bx-user-info-bottomarea"></div>';
10664		}
10665
10666		if (bIE)
10667		{
10668			_this.DIV.className = 'bx-user-info-shadow-ie';
10669			_this.classNameAnim = 'bx-user-info-shadow-anim-ie';
10670			_this.classNameFixed = 'bx-user-info-shadow-ie';
10671		}
10672		else
10673		{
10674			_this.DIV.className = 'bx-user-info-shadow';
10675			_this.classNameAnim = 'bx-user-info-shadow-anim';
10676			_this.classNameFixed = 'bx-user-info-shadow';
10677		}
10678
10679		_this.filterFixed = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/bitrix/components/bitrix/main.user.link/templates/.default/images/cloud-left-top.png', sizingMethod = 'crop' );";
10680
10681		if (h_mirror && v_mirror)
10682		{
10683			if (BX.browser.IsIE6())
10684			{
10685				_this.DIV.className = 'bx-user-info-shadow-hv-ie6';
10686				_this.classNameAnim = 'bx-user-info-shadow-hv-anim-ie6';
10687				_this.classNameFixed = 'bx-user-info-shadow-hv-ie6';
10688			}
10689			else if (bIE)
10690			{
10691				_this.DIV.className = 'bx-user-info-shadow-hv-ie';
10692				_this.classNameAnim = 'bx-user-info-shadow-hv-anim-ie';
10693				_this.classNameFixed = 'bx-user-info-shadow-hv-ie';
10694			}
10695			else
10696			{
10697				_this.DIV.className = 'bx-user-info-shadow-hv';
10698				_this.classNameAnim = 'bx-user-info-shadow-hv-anim';
10699				_this.classNameFixed = 'bx-user-info-shadow-hv';
10700			}
10701
10702			_this.filterFixed = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/bitrix/components/bitrix/main.user.link/templates/.default/images/cloud-right-bottom.png', sizingMethod = 'crop' );";
10703		}
10704		else
10705		{
10706			if (h_mirror)
10707			{
10708				if (bIE)
10709				{
10710					_this.DIV.className = 'bx-user-info-shadow-h-ie';
10711					_this.classNameAnim = 'bx-user-info-shadow-h-anim-ie';
10712					_this.classNameFixed = 'bx-user-info-shadow-h-ie';
10713				}
10714				else
10715				{
10716					_this.DIV.className = 'bx-user-info-shadow-h';
10717					_this.classNameAnim = 'bx-user-info-shadow-h-anim';
10718					_this.classNameFixed = 'bx-user-info-shadow-h';
10719				}
10720
10721				_this.filterFixed = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/bitrix/components/bitrix/main.user.link/templates/.default/images/cloud-right-top.png', sizingMethod = 'crop' );";
10722			}
10723
10724			if (v_mirror)
10725			{
10726				if (BX.browser.IsIE6())
10727				{
10728					_this.DIV.className = 'bx-user-info-shadow-v-ie6';
10729					_this.classNameAnim = 'bx-user-info-shadow-v-anim-ie6';
10730					_this.classNameFixed = 'bx-user-info-shadow-v-ie6';
10731				}
10732				else if (bIE)
10733				{
10734					_this.DIV.className = 'bx-user-info-shadow-v-ie';
10735					_this.classNameAnim = 'bx-user-info-shadow-v-anim-ie';
10736					_this.classNameFixed = 'bx-user-info-shadow-v-ie';
10737				}
10738				else
10739				{
10740					_this.DIV.className = 'bx-user-info-shadow-v';
10741					_this.classNameAnim = 'bx-user-info-shadow-v-anim';
10742					_this.classNameFixed = 'bx-user-info-shadow-v';
10743				}
10744
10745				_this.filterFixed = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/bitrix/components/bitrix/main.user.link/templates/.default/images/cloud-left-bottom.png', sizingMethod = 'crop' );";
10746			}
10747		}
10748
10749
10750		if (BX.browser.IsIE() && null == _this.IFRAME)
10751		{
10752			_this.IFRAME = document.body.appendChild(document.createElement('IFRAME'));
10753			_this.IFRAME.id = _this.DIV.id + "_frame";
10754			_this.IFRAME.style.position = 'absolute';
10755			_this.IFRAME.style.width = (_this.width - 60) + 'px';
10756			_this.IFRAME.style.height = (_this.height - 100) + 'px';
10757			_this.IFRAME.style.borderStyle = 'solid';
10758			_this.IFRAME.style.borderWidth = '0px';
10759			_this.IFRAME.style.zIndex = 550;
10760			_this.IFRAME.style.display = 'none';
10761		}
10762		if (BX.browser.IsIE())
10763		{
10764			_this.IFRAME.style.left = (parseInt(left) + 25) + "px";
10765			_this.IFRAME.style.top = (parseInt(top) + 30 + _this.v_delta) + "px";
10766		}
10767
10768		_this.DIV.style.display = 'none';
10769		_this.ShowOpacityEffect({func: _this.SetVisible, obj: _this.DIV, arParams: []}
10769, 0);
10770
10771		document.getElementById('user_info_' + _this.USER_ID).onmouseover = function() {
10772			_this.StartTrackMouse(this);
10773		};
10774
10775		document.getElementById('user_info_' + _this.USER_ID).onmouseout = function() {
10776			_this.StopTrackMouse(this);
10777		};
10778
10779		BX.onCustomEvent('onTooltipShow', [this]);
10780	};
10781
10782	this.InsertData = function(data)
10783	{
10784		if (null != data && data.length > 0)
10785		{
10786			eval('_this.INFO = ' + data);
10787
10788			var cardEl = document.getElementById('user-info-data-card-' + _this.USER_ID);
10789			cardEl.innerHTML = _this.INFO.RESULT.Card;
10790
10791			var photoEl = document.getElementById('user-info-photo-' + _this.USER_ID);
10792			photoEl.innerHTML = _this.INFO.RESULT.Photo;
10793
10794			var toolbarEl = document.getElementById('user-info-toolbar-' + _this.USER_ID);
10795			toolbarEl.innerHTML = _this.INFO.RESULT.Toolbar;
10796
10797			var toolbar2El = document.getElementById('user-info-toolbar2-' + _this.USER_ID);
10798			toolbar2El.innerHTML = _this.INFO.RESULT.Toolbar2;
10799
10800			if(BX.type.isArray(_this.INFO.RESULT.Scripts))
10801			{
10802				for(var i = 0; i < _this.INFO.RESULT.Scripts.length; i++)
10803				{
10804					eval(_this.INFO.RESULT.Scripts[i]);
10805				}
10806			}
10807
10808			BX.onCustomEvent('onTooltipInsertData', [_this]);
10809		}
10810	}
10811
10812};
10813BX.CTooltip.prototype.StartTrackMouse = function(ob)
10814{
10815	var _this = this;
10816
10817	if(!this.tracking)
10818	{
10819		var elCoords = BX.pos(ob);
10820		this.RealAnchor = ob;
10821		this.CoordsLeft = elCoords.left + 0;
10822		this.CoordsTop = elCoords.top - 325;
10823		this.AnchorRight = elCoords.right;
10824		this.AnchorBottom = elCoords.bottom;
10825
10826		this.tracking = 1;
10827		BX.bind(document, "mousemove", _this.TrackMouse);
10828
10829		setTimeout(function() {_this.tickTimer()}, 500);
10830	}
10831};
10832
10833BX.CTooltip.prototype.StopTrackMouse = function()
10834{
10835	var _this = this;
10836	if(this.tracking)
10837	{
10838		BX.unbind(document, "mousemove", _this.TrackMouse);
10839		this.active = false;
10840		setTimeout(function() {_this.HideTooltip()}, 500);
10841		this.tracking = false;
10842	}
10843};
10844
10845BX.CTooltip.prototype.tickTimer = function()
10846{
10847	var _this = this;
10848
10849	if(this.tracking)
10850	{
10851		this.tracking++;
10852		if(this.active)
10853		{
10854			if( (this.active.time + 5/*0.5sec*/)  <= this.tracking)
10855				this.ShowTooltip();
10856		}
10857		setTimeout(function() {_this.tickTimer()}, 100);
10858	}
10859};
10860
10861BX.CTooltip.prototype.HideTooltip = function()
10862{
10863	if(!this.tracking)
10864		this.ShowOpacityEffect({func: this.SetInVisible, obj: this.DIV, arParams: []}, 1);
10865};
10866
10867BX.CTooltip.prototype.ShowOpacityEffect = function(oCallback, bFade)
10868{
10869	var steps = 3;
10870	var period = 1;
10871	var delta = 1 / steps;
10872	var i = 0, op, _this = this;
10873
10874	if(BX.browser.IsIE() && _this.DIV)
10875		_this.DIV.className = _this.classNameAnim;
10876
10877	var show = function()
10878	{
10879		i++;
10880		if (i > steps)
10881		{
10882			clearInterval(intId);
10883			if (!oCallback.arParams)
10884				oCallback.arParams = [];
10885			if (oCallback.func && oCallback.obj)
10886				oCallback.func.apply(oCallback.obj, oCallback.arParams);
10887			return;
10888		}
10889		op = bFade ? 1 - i * delta : i * delta;
10890
10891		if (_this.DIV != null)
10892		{
10893			try{
10894				_this.DIV.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + (op * 100) + ')';
10895				_this.DIV.style.opacity = op;
10896				_this.DIV.style.MozOpacity = op;
10897				_this.DIV.style.KhtmlOpacity = op;
10898			}
10899			catch(e){
10900			}
10901			finally{
10902				if (!bFade && i == 1)
10903					_this.DIV.style.display = 'block';
10904
10905				if (bFade && i == steps && _this.DIV)
10906					_this.DIV.style.display = 'none';
10907
10908
10909				if (BX.browser.IsIE() && i == 1 && bFade && _this.IFRAME)
10910					_this.IFRAME.style.display = 'none';
10911
10912
10913				if (BX.browser.IsIE() && i == steps && _this.DIV)
10914				{
10915					if (!bFade)
10916						_this.IFRAME.style.display = 'block';
10917
10918					_this.DIV.style.filter = _this.filterFixed;
10919					_this.DIV.className = _this.classNameFixed;
10920					_this.DIV.innerHTML = ''+_this.DIV.innerHTML;
10921				}
10922
10923				if(bFade)
10924				{
10925					BX.onCustomEvent('onTooltipHide', [_this]);
10926				}
10927			}
10928		}
10929
10930	};
10931	var intId = setInterval(show, period);
10932
10933}
10934
10935})(window);
10936
10937/* End */
10938;
10939; /* Start:"a:4:{s:4:"full";s:51:"/bitrix/js/main/core/core_webrtc.js?167415717624229";s:6:"source";s:35:"/bitrix/js/main/core/core_webrtc.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
10940/**
10941 * Class for unification and work with WebRTC commands
10942 * @param params
10943 * @constructor
10944 */
10945
10946;(function (window)
10947{
10948	if (window.BX.webrtc) return;
10949
10950	var BX = window.BX;
10951
10952	// this is constructor, you must inherit
10953	BX.webrtc = function ()
10954	{
10955		this.debug = false;
10956		this.audioMuted = false;
10957		this.videoMuted = false;
10958		this.enabled = false;
10959		this.detectedBrowser = 'none';
10960		this.pcConfig = {};
10961		this.oneway = false;
10962		this.lastUserMediaParams = {};
10963		this.pcConstraints = {};
10964		this.sdpConstraints = {'mandatory': { 'OfferToReceiveAudio':true, 'OfferToReceiveVideo':true }};
10965		this.defaultMicrophone = null;
10966		this.defaultCamera = null;
10967		this.defaultSpeaker = null;
10968		this.enableMicAutoParameters = true;
10969		this.useFallbackConstraints = false;
10970
10971		this.configVideo = {
10972			aspectRatio: 1.7777777778
10973		};
10974		this.configVideoGroup = this.configVideo;
10975		this.configVideoMobile = this.configVideo;
10976		this.configVideoAfterError = { };
10977
10978		this.callStreamSelf = null;
10979		this.callStreamMain = null;
10980		this.callStreamUsers = {};
10981
10982		this.pc = {};
10983		this.pcStart = {};
10984		this.connected = {};
10985
10986		this.iceCandidates = {};
10987
10988		this.initiator = false;
10989		this.callUserId = 0;
10990		this.callChatId = 0;
10991		this.callToGroup = false;
10992		this.callGroupUsers = [];
10993		this.callInit = false;
10994		this.callInitUserId = 0;
10995		this.callActive = false;
10996		this.callVideo = false;
10997		this.callRequestUserMedia = {};
10998		this.needPeerConnection = true;
10999
11000		this.createAnswerTimeout = {};
11001		this.initPeerConnectionTimeout = {};
11002		this.iceCandidateTimeout = {};
11003		this.pcConnectTimeout = {};
11004
11005		this.init();
11006		this.setTurnServer();
11007	};
11008
11009	// this function needed to execute, after constructor
11010	BX.inheritWebrtc = function(child)
11011	{
11012		child.prototype = Object.create(BX.webrtc.prototype);
11013		child.prototype.constructor = child;
11014		child.prototype.parent = BX.webrtc.prototype;
11015	};
11016
11017	BX.webrtc.prototype.init = function()
11018	{
11019		if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia)
11020			this.enabled = true;
11021		else
11022			return;
11023
11024		if (navigator.userAgent.substr(navigator.userAgent.indexOf('Firefox/')+8, 2) >= 27)
11025			this.detectedBrowser = 'firefox';
11026		else if (navigator.appVersion.substr(navigator.appVersion.indexOf('Chrome/')+7, 2) >= 29)
11027			this.detectedBrowser = 'chrome';
11028	};
11029
11030	BX.webrtc.prototype.attachMediaStream = function(element, stream)
11031	{
11032		element.srcObject = stream;
11033		if(BX.type.isNotEmptyString(this.defaultSpeaker) && element.setSinkId)
11034		{
11035			this.log('Trying to set output device: ' + this.defaultSpeaker);
11036			element.setSinkId(this.defaultSpeaker);
11037		}
11038	};
11039
11040	// this is public function, don't overwrite
11041	BX.webrtc.prototype.ready = function ()
11042	{
11043		return this.enabled;
11044	};
11045
11046	// this is public function, don't overwrite
11047	BX.webrtc.prototype.setTurnServer = function (params)
11048	{
11049		if (!this.ready()) return false;
11050
11051		params = params || {};
11052
11053		this.turnServer = params.turnServer || 'turn.calls.bitrix24.com';
11054		this.turnServerFirefox = params.turnServerFirefox || '54.217.240.163';
11055		this.turnServerLogin = params.turnServerLogin || 'bitrix';
11056		this.turnServerPassword = params.turnServerPassword || 'bitrix';
11057
11058		if (this.detectedBrowser == 'firefox')
11059		{
11060			this.pcConfig = { "iceServers": [ { url:"stun:"+this.turnServerFirefox}, { url:"turn:"+this.turnServerFirefox, credential:this.turnServerPassword, username: this.turnServerLogin} ] };
11061			this.pcConstraints = {"optional": [{"DtlsSrtpKeyAgreement": true}]};
11062		}
11063		else if (this.detectedBrowser == 'chrome')
11064		{
11065			this.pcConfig = { "iceServers": [ { url:"stun:"+this.turnServer}, { url:"turn:"+this.turnServerLogin+"@"+this.turnServer, username: this.turnServerLogin, credential:this.turnServerPassword} ] };
11066			this.pcConstraints = {"optional": [{"DtlsSrtpKeyAgreement": true}]};
11067		}
11068
11069		return true;
11070	};
11071
11072	// this is public function, don't overwrite
11073	BX.webrtc.prototype.toggleAudio = function(changeVariable)
11074	{
11075		if (!this.ready()) return false;
11076
11077		changeVariable = typeof(changeVariable) != 'undefined'? changeVariable: true;
11078		if (changeVariable)
11079			this.audioMuted = this.audioMuted? false: true;
11080
11081		if (this.callStreamSelf && this.callStreamSelf.getAudioTracks() && this.callStreamSelf.getAudioTracks().length>0)
11082		{
11083			for (var i = 0; i < this.callStreamSelf.getAudioTracks().length; i++)
11084			{
11085				this.callStreamSelf.getAudioTracks()[i].enabled = !this.audioMuted;
11086			}
11087		}
11088
11089		return true;
11090	};
11091
11092	// this is public function, don't overwrite
11093	BX.webrtc.prototype.toggleVideo = function(changeVariable)
11094	{
11095		if (!this.ready()) return false;
11096
11097		changeVariable = typeof(changeVariable) != 'undefined'? changeVariable: true;
11098		if (changeVariable)
11099			this.videoMuted = this.videoMuted? false: true;
11100
11101		if (this.callStreamSelf && this.callStreamSelf.getVideoTracks() && this.callStreamSelf.getVideoTracks().length>0)
11102		{
11103			for (var i = 0; i < this.callStreamSelf.getVideoTracks().length; i++)
11104			{
11105				this.callStreamSelf.getVideoTracks()[i].enabled = !this.videoMuted;
11106			}
11107		}
11108
11109		return true;
11110	};
11111
11112	// this is public function, don't overwrite
11113	BX.webrtc.prototype.signalingReady = function()
11114	{
11115		return (this.ready() && BX.PULL && BX.PULL.getPullServerStatus());
11116	};
11117
11118	// this is public function, don't overwrite
11119	BX.webrtc.prototype.log = function()
11120	{
11121		var text = '';
11122		if (BX.desktop && BX.desktop.ready())
11123		{
11124			for (var i = 0; i < arguments.length; i++)
11125			{
11126				try
11127				{
11128					text = text+' | '+(typeof(arguments[i]) == 'object'? JSON.stringify(arguments[i]): arguments[i]);
11129				}
11130				catch (e)
11131				{
11132					text = text+' | (circular structure)';
11133				}
11134
11135			}
11136			BX.desktop.log(BX.message('USER_ID')+'.video.log', text.substr(3));
11137		}
11138		if (this.debug)
11139		{
11140			if (console) console.log('WebRTC Log', arguments);
11141		}
11142	};
11143
11144	/* UserMedia API */
11145
11146	// this is public function, you can inherit
11147	BX.webrtc.prototype.startGetUserMedia = function(video, audio)
11148	{
11149		if (this.oneway && !this.initiator)
11150		{
11151			this.onUserMediaSuccess();
11152			return true;
11153		}
11154
11155		this.lastUserMediaParams = {video: video, audio: audio};
11156
11157		if (this.callRequestUserMedia[this.callVideo? 'video': 'audio'])
11158			return false;
11159
11160		if(typeof(video) != 'undefined' && video !== true)
11161		{
11162			//nop
11163		}
11164		else
11165		{
11166			if(this.useFallbackConstraints)
11167				video = this.configVideoAfterError;
11168			else if(this.callToGroup)
11169				video = this.configVideoGroup;
11170			else
11171				video = this.configVideo;
11172		}
11173
11174		if(video && this.defaultCamera)
11175		{
11176			video.deviceId = {ideal: this.defaultCamera};
11177		}
11178
11179		audio = typeof(audio) != 'undefined' && audio !== true? audio: {};
11180		if(audio && this.defaultMicrophone)
11181		{
11182			audio.deviceId = {ideal: this.defaultMicrophone};
11183		}
11184
11185		/* for unknown reason, these constraints do not work in chrome, when paired with video resolution constraints */
11186		if(false && this.enableMicAutoParameters === false)
11187		{
11188			audio.optional = [
11189				{echoCancellation:false},
11190				{googEchoCancellation:false},
11191				{googEchoCancellation2:false},
11192				{googDAEchoCancellation:false},
11193				{googAutoGainControl: false},
11194				{googAutoGainControl2: false},
11195				{mozAutoGainControl: false},
11196				{googNoiseSuppression: false},
11197				{googNoiseSuppression2: false},
11198				{googHighpassFilter: false},
11199				{googTypingNoiseDetection: false},
11200				{googAudioMirroring: false}
11201			];
11202		}
11203
11204		var constraints = {
11205			"audio": audio,
11206			"video": video
11207		};
11208
11209		this.log("Requested access to local media with constraints:  \"" + JSON.stringify(constraints) + "\"");
11210
11211		try {
11212			this.callRequestUserMedia[this.callVideo? 'video': 'audio'] = true;
11213			navigator.mediaDevices.getUserMedia(constraints).then(BX.delegate(this.onUserMediaSuccess, this), BX.delegate(this.onUserMediaError, this));
11214		} catch (e) {
11215			this.debug = true;
11216			this.log("Method getUserMedia failed with exception: " + e.message);
11217		}
11218
11219		return true;
11220	}
11221
11222	// this is protected function, you must inherit
11223	BX.webrtc.prototype.onUserMediaSuccess = function(stream)
11224	{
11225		this.log('Media stream received');
11226		if(stream && stream.getTracks)
11227		{
11228			stream.getTracks().forEach(function(track)
11229			{
11230				this.log(BX.webrtc.mediaStreamTrackToString(track));
11231			}.bind(this));
11232		}
11233
11234		if (!this.oneway || this.initiator)
11235		{
11236			this.callRequestUserMedia[this.callVideo? 'video': 'audio'] = false;
11237			if (this.callStreamSelf)
11238				return false;
11239
11240			if (!this.callActive && stream)
11241			{
11242				BX.webrtc.stopMediaStream(stream);
11243				return false;
11244			}
11245
11246			this.log("User has granted access to local media.");
11247
11248			this.callStreamSelf = stream;
11249			this.toggleAudio(false);
11250		}
11251
11252		if (!this.needPeerConnection)
11253			return true;
11254
11255		if (this.initiator)
11256		{
11257			if (this.callToGroup)
11258			{
11259				for (var i = 0; i < this.callGroupUsers.length; i++)
11260				{
11261					var userId = this.callGroupUsers[i];
11262					if (userId != BX.message('USER_ID'))
11263					{
11264						clearTimeout(this.initPeerConnectionTimeout[userId]);
11265						this.initPeerConnection(userId);
11266					}
11267				}
11268			}
11269			else
11270			{
11271				clearTimeout(this.initPeerConnectionTimeout[this.callUserId]);
11272				this.initPeerConnection(this.callUserId);
11273			}
11274		}
11275		else
11276		{
11277			if (this.callToGroup)
11278			{
11279				for (var i = 0; i < this.callGroupUsers.length; i++)
11280				{
11281					var userId = this.callGroupUsers[i];
11282					if (userId != BX.message('USER_ID') && userId != this.callInitUserId && !this.callStreamUsers[userId])
11283					{
11284						clearTimeout(this.initPeerConnectionTimeout[userId]);
11285						this.initPeerConnection(userId, true);
11286					}
11287				}
11288			}
11289		}
11290		return true;
11291	}
11292
11293	// this is protected function, you can inherit
11294	BX.webrtc.prototype.onUserMediaError = function(error)
11295	{
11296		this.debug = true;
11297		this.callRequestUserMedia[this.callVideo? 'video': 'audio'] = false;
11298		if (!this.callActive)
11299			return false;
11300
11301		this.log("Failed to get access to local media. Error code was " + JSON.stringify(error));
11302
11303		return true;
11304	}
11305
11306	/* PeerConnection API */
11307
11308	// this is public function, don't overwrite or inherit
11309	BX.webrtc.prototype.initPeerConnection = function(userId, initiator)
11310	{
11311		if (!this.callActive)
11312			return false;
11313
11314		initiator = initiator === true;
11315		if (this.debug) console.log(userId, 'wait initPeerConnection')
11316		if (!this.pcStart[userId] && (!this.oneway && this.callStreamSelf || this.oneway && this.initiator && this.callStreamSelf || this.oneway && !this.initiator))
11317		{
11318			if (this.connected[userId])
11319			{
11320				this.log("Creating PeerConnection.", userId);
11321				this.createPeerConnection(userId);
11322				if (!this.pc[userId])
11323				{
11324					clearTimeout(this.initPeerConnectionTimeout[userId]);
11325					this.initPeerConnectionTimeout[userId] = setTimeout(BX.delegate(function(){
11326						this.initPeerConnection(userId, initiator);
11327					}, this), 2000);
11328					return false;
11329				}
11330
11331				this.log("Adding local stream.", userId, this.pc[userId]);
11332
11333				this.pcStart[userId] = true;
11334
11335				if (this.initiator || initiator)
11336					this.sendOfferToPeer(userId);
11337			}
11338			else
11339			{
11340				clearTimeout(this.initPeerConnectionTimeout[userId]);
11341				this.initPeerConnectionTimeout[userId] = setTimeout(BX.delegate(function(){
11342					this.initPeerConnection(userId, initiator);
11343				}, this), 2000);
11344			}
11345		}
11346		else if (!this.connected[userId])
11347		{
11348			clearTimeout(this.initPeerConnectionTimeout[userId]);
11349			this.initPeerConnectionTimeout[userId] = setTimeout(BX.delegate(function(){
11350				this.initPeerConnection(userId, initiator);
11351			}, this), 2000);
11352		}
11353
11354		return true;
11355	}
11356
11357	// this protected function, you must inherit
11358	BX.webrtc.prototype.setLocalAndSend = function(userId, desc)
11359	{
11360		if (this.pc[userId] == null || !this.callActive)
11361			return false;
11362
11363		this.log('set local description and send', userId, JSON.stringify(desc));
11364		this.pc[userId].setLocalDescription(desc, BX.delegate(function(a){this.log('setLocalDescription', a)}, this), BX.delegate(function(a){this.log('setLocalDescription', a)}, this));
11365
11366		// need to send local description to "userId" peer
11367
11368		return true;
11369	}
11370
11371	// this is blank function, you must overwrite
11372	BX.webrtc.prototype.onRemoteStreamAdded = function(userId, event, setMainVideo)
11373	{
11374	}
11375
11376	// this is blank function, you can overwrite
11377	BX.webrtc.prototype.onRemoteStreamRemoved = function(userId, event)
11378	{
11379	}
11380
11381	// this is blank function, you must overwrite
11382	BX.webrtc.prototype.onIceCandidate = function (userId, candidates)
11383	{
11384		// need to send IceCandidate to "userId" peer
11385	}
11386
11387	// this is blank function, you can overwrite
11388	BX.webrtc.prototype.onIceConnectionStateChange = function(userId, event)
11389	{
11390	}
11391
11392	// this is blank function, you can overwrite
11393	BX.webrtc.prototype.onSignalingStateChange = function(userId, event)
11394	{
11395	}
11396
11397	// this is blank function, you can overwrite
11398	BX.webrtc.prototype.peerConnectionError = function (userId, event)
11399	{
11400	}
11401
11402	// this is public function, you must inherit
11403	BX.webrtc.prototype.peerConnectionReconnect = function (userId)
11404	{
11405		if (!this.pc[userId])
11406			return false;
11407
11408		if ((this.pc[userId].iceConnectionState == 'connected' || this.pc[userId].iceConnectionState == 'completed') && this.pc[userId].signalingState == 'stable')
11409			return false;
11410
11411		this.log('peerConnectionReconnect', this.pc[userId].iceConnectionState, this.pc[userId].signalingState)
11412		this.pc[userId].close();
11413
11414		delete this.pc[userId];
11415		delete this.pcStart[userId];
11416
11417		if (this.callStreamMain == this.callStreamUsers[userId])
11418			this.callStreamMain = null;
11419		this.callStreamUsers[userId] = null;
11420
11421		clearTimeout(this.initPeerConnectionTimeout[userId]);
11422
11423		// need to send reconnect command to "userId" peer in your class
11424		return true;
11425	}
11426
11427	// this is public function, you can inherit
11428	BX.webrtc.prototype.deleteEvents = function()
11429	{
11430		this.initiator = false;
11431		this.callUserId = 0;
11432		this.callChatId = 0;
11433		this.callToGroup = false;
11434		this.callGroupUsers = [];
11435		this.callInit = false;
11436		this.callInitUserId = 0;
11437		this.callActive = false;
11438		this.callVideo = false;
11439		this.callRequestUserMedia = {};
11440
11441		this.audioMuted = false;
11442		this.videoMuted = false;
11443		this.needPeerConnection = true;
11444
11445		var i = 0;
11446		for (i in this.pc)
11447		{
11448			if(this.pc.hasOwnProperty(i))
11449			{
11450				this.pc[i].close();
11451				delete this.pc[i];
11452			}
11453		}
11454
11455		this.pc = {};
11456		this.pcStart = {};
11457		this.connected = {};
11458		this.iceCandidates = {};
11459
11460		for (i in this.iceCandidateTimeout)
11461		{
11462			if (this.iceCandidateTimeout.hasOwnProperty(i))
11463			{
11464				clearTimeout(this.iceCandidateTimeout[i]);
11465			}
11466		}
11467		this.iceCandidateTimeout = {};
11468
11469		for (i in this.pcConnectTimeout)
11470		{
11471			if (this.pcConnectTimeout.hasOwnProperty(i))
11472			{
11473				clearTimeout(this.pcConnectTimeout[i]);
11474			}
11475		}
11476		this.pcConnectTimeout = {};
11477
11478		for (i in this.createAnswerTimeout)
11479		{
11480			if (this.createAnswerTimeout.hasOwnProperty(i))
11481			{
11482				clearTimeout(this.createAnswerTimeout[i]);
11483			}
11484		}
11485		this.createAnswerTimeout = {};
11486
11487		for (i in this.initPeerConnectionTimeout)
11488		{
11489			if (this.initPeerConnectionTimeout.hasOwnProperty(i))
11490			{
11491				clearTimeout(this.initPeerConnectionTimeout[i]);
11492			}
11493		}
11494		this.initPeerConnectionTimeout = {};
11495
11496		if (this.callStreamSelf)
11497		{
11498			BX.webrtc.stopMediaStream(this.callStreamSelf);
11499			this.callStreamSelf = null;
11500		}
11501		if (this.callStreamMain)
11502		{
11503			BX.webrtc.stopMediaStream(this.callStreamMain);
11504			this.callStreamMain = null;
11505		}
11506		for (i in this.callStreamUsers)
11507		{
11508			if (this.callStreamUsers.hasOwnProperty(i))
11509			{
11510				if (this.callStreamUsers[i])
11511					BX.webrtc.stopMediaStream(this.callStreamUsers[i]);
11512				delete this.callStreamUsers[i];
11513			}
11514		}
11515	}
11516
11517	/* Private function */
11518
11519	// this is private function, don't use or overwrite or inherit
11520	BX.webrtc.prototype.mergeConstraints = function (cons1, cons2)
11521	{
11522		if (!this.ready()) return false;
11523
11524		var merged = cons1;
11525		for (var name in cons2.mandatory)
11526		{
11527			if (cons2.mandatory.hasOwnProperty(name))
11528			{
11529				merged.mandatory[name] = cons2.mandatory[name];
11530			}
11531		}
11532		merged.optional.concat(cons2.optional);
11533		return merged;
11534	};
11535
11536	// this is private function, don't use or overwrite or inherit
11537	BX.webrtc.prototype.sendOfferToPeer = function(userId)
11538	{
11539		if (!this.pc[userId])
11540			return false;
11541
11542		var constraints = {"optional": [], "mandatory": {"MozDontOfferDataChannel": true}};
11543
11544		if (this.detectedBrowser === "chrome")
11545		{
11546			for (var prop in constraints.mandatory)
11547			{
11548				if (constraints.mandatory.hasOwnProperty(prop))
11549				{
11550					if (prop.indexOf("Moz") != -1)
11551						delete constraints.mandatory[prop];
11552				}
11553			}
11554		}
11555		this.log('Constraints', constraints);
11556		constraints = this.mergeConstraints(constraints, this.sdpConstraints);
11557
11558		this.log("Sending offer to peer, with constraints:", userId,  "\"" + JSON.stringify(constraints) + "\".");
11559		this.pc[userId].createOffer(BX.delegate(function(desc){this.setLocalAndSend(userId, desc)}, this), BX.delegate(function(a){this.log('createOffer failure', a)}, this), constraints);
11560
11561		return true;
11562	}
11563
11564	// this is private function, don't use or overwrite or inherit
11565	BX.webrtc.prototype.createPeerConnection = function(userId)
11566	{
11567		try
11568		{
11569			this.pc[userId] = new RTCPeerConnection(this.pcConfig, this.pcConstraints);
11570			this.pc[userId].onicecandidate = BX.delegate(function(event) { this.onIceCandidateEvent(userId, event) }, this);
11571			this.pc[userId].onaddstream = BX.delegate(function(event) { this.onRemoteStreamAddedEvent(userId, event) }, this);
11572			this.pc[userId].onremovestream = BX.delegate(function(event) { this.onRemoteStreamRemovedEvent(userId, event)}, this);
11573			this.pc[userId].oniceconnectionstatechange = BX.delegate(function(event) { this.onIceConnectionStateChangeEvent(userId, event)}, this);
11574			this.pc[userId].onsignalingstatechange = BX.delegate(function(event) { this.onSignalingStateChangeEvent(userId, event)}, this);
11575			if (!this.oneway || this.initiator)
11576			{
11577				this.pc[userId].addStream(this.callStreamSelf);
11578			}
11579
11580			this.log("Created RTCPeerConnnection for "+userId+" with:\n" +
11581			"  config: \"" + JSON.stringify(this.pcConfig) + "\";\n" +
11582			"  constraints: \"" + JSON.stringify(this.pcConstraints) + "\".");
11583		}
11584		catch (e)
11585		{
11586			if (this.callToGroup && this.callStreamUsers[userId])
11587				return false;
11588
11589			this.log('PeerConnection: ', JSON.stringify(this.pcConfig), JSON.stringify(this.pcConstraints));
11590			this.log("Failed to create PeerConnection, exception: " + e.message);
11591
11592			this.peerConnectionError(userId, e);
11593		}
11594		return true;
11595	}
11596
11597	// this is private function, don't use or overwrite or inherit
11598	BX.webrtc.prototype.signalingPeerData = function(userId, peerData)
11599	{
11600		var signal = JSON.parse(peerData);
11601		if (signal.type === 'offer')
11602		{
11603			if (!this.pcStart[userId])
11604				this.initPeerConnection(userId);
11605
11606			this.createAnswer(userId, signal);
11607		}
11608		else if (signal.type === 'answer' && this.pcStart[userId])
11609		{
11610			if (this.pc[userId] == null)
11611				return false;
11612
11613			this.pc[userId].setRemoteDescription(new RTCSessionDescription(signal), function(){}, function(){});
11614		}
11615		else if (signal.type === 'candidate' && this.pcStart[userId])
11616		{
11617			if (!this.pc[userId] || this.pc[userId] == null)
11618				return false;
11619
11620			for (var i = 0; i < signal.candidates.length; i++)
11621			{
11622				var candidate = new RTCIceCandidate({sdpMLineIndex:signal.candidates[i].label, candidate:signal.candidates[i].candidate});
11623				try{
11624					this.pc[userId].addIceCandidate(candidate);
11625				}
11626				catch(e)
11627				{
11628					this.log('Error addIceCandidate', JSON.stringify(e));
11629					this.peerConnectionReconnect(userId);
11630					return false;
11631				}
11632			}
11633		}
11634		else
11635		{
11636			this.log('Signaling command "'+(signal && signal.type? signal.type: 'undefined')+'" from user "'+userId+'" skip');
11637		}
11638
11639		return true;
11640	}
11641
11642	// this is private function, don't use or overwrite or inherit
11643	BX.webrtc.prototype.onRemoteStreamAddedEvent = function (userId, event)
11644	{
11645		if (!this.pc[userId]) return false;
11646
11647		this.log('Remote stream added', userId, JSON.stringify(event));
11648
11649		var setMainVideo = false;
11650		if (!this.callStreamMain)
11651		{
11652			this.callStreamMain = event.stream;
11653			setMainVideo = true;
11654		}
11655		this.callStreamUsers[userId] = event.stream;
11656		this.onRemoteStreamAdded(userId, event, setMainVideo)
11657	}
11658
11659	// this is private function, don't use or overwrite or inherit
11660	BX.webrtc.prototype.onRemoteStreamRemovedEvent = function(userId, event)
11661	{
11662		if (!this.pc[userId]) return false;
11663
11664		this.callStreamUsers[userId] = null;
11665		this.onRemoteStreamRemoved(userId, event);
11666	}
11667
11668	// this is private function, don't use or overwrite or inherit
11669	BX.webrtc.prototype.onIceCandidateEvent = function (userId, event)
11670	{
11671		if (!this.pc[userId]) return false;
11672
11673		if (!this.iceCandidates[userId])
11674			this.iceCandidates[userId] = [];
11675
11676		if (event.candidate)
11677		{
11678			this.log("New ICE candidate: ", event.candidate);
11679			this.iceCandidates[userId].push({type: 'candidate', label: event.candidate.sdpMLineIndex, id: event.candidate.sdpMid, candidate: event.candidate.candidate});
11680
11681			clearTimeout(this.iceCandidateTimeout[userId]);
11682			this.iceCandidateTimeout[userId] = setTimeout(BX.delegate(function(){
11683				if (this.iceCandidates[userId].length === 0)
11684					return false;
11685
11686				this.onIceCandidate(userId, {'type': 'candidate', 'candidates': this.iceCandidates[userId]});
11687				this.iceCandidates[userId] = [];
11688			}, this), 250);
11689		}
11690		else
11691		{
11692			this.log("End of candidates of "+userId);
11693		}
11694	}
11695
11696	// this is private function, don't use or overwrite or inherit
11697	BX.webrtc.prototype.onIceConnectionStateChangeEvent = function(userId, event)
11698	{
11699		clearTimeout(this.pcConnectTimeout[userId]);
11700		if (!this.pc[userId] || this.pc[userId].iceConnectionState == "close")
11701			return false;
11702
11703		this.log('iceConnectionStateChange', userId, this.pc[userId].iceConnectionState, this.pc[userId].signalingState);
11704		this.pcConnectTimeout[userId] = setTimeout(BX.delegate(function(){
11705			this.peerConnectionReconnect(userId);
11706		}, this), 15000);
11707
11708		this.onIceConnectionStateChange(userId, event);
11709
11710		return true;
11711	}
11712
11713	// this is private function, don't use or overwrite or inherit
11714	BX.webrtc.prototype.onSignalingStateChangeEvent = function(userId, event)
11715	{
11716		clearTimeout(this.pcConnectTimeout[userId]);
11717		if (!this.pc[userId] || this.pc[userId].signalingState == "close")
11718			return false;
11719
11720		this.log('signalingStateChange', userId, this.pc[userId].iceConnectionState, this.pc[userId].signalingState);
11721		this.pcConnectTimeout[userId] = setTimeout(BX.delegate(function(){
11722			this.peerConnectionReconnect(userId);
11723		}, this), 15000);
11724
11725		this.onSignalingStateChange(userId, event)
11726	}
11727
11728	// this is private function, don't use or overwrite or inherit
11729	BX.webrtc.prototype.createAnswer = function(userId, signal)
11730	{
11731		if (!this.callActive)
11732			return false;
11733
11734		if (!this.pcStart[userId])
11735		{
11736			clearTimeout(this.createAnswerTimeout[userId]);
11737			this.createAnswerTimeout[userId] = setTimeout(BX.delegate(function(){
11738				this.createAnswer(userId, signal);
11739			}, this), 2000);
11740
11741			return false;
11742		}
11743		this.pc[userId].setRemoteDescription(new RTCSessionDescription(signal), BX.delegate(function()
11744		{
11745			if (!this.pc[userId]) return false;
11746			this.pc[userId].createAnswer(BX.delegate(function(desc){this.setLocalAndSend(userId, desc)}, this), BX.delegate(function(a){this.log('createAnswer failure', a)}, this), this.sdpConstraints);
11747		}, this), function(){});
11748
11749		return true;
11750	}
11751
11752	BX.webrtc.prototype.setDefaultCamera = function(defaultCamera)
11753	{
11754		this.defaultCamera = defaultCamera;
11755	};
11756
11757	BX.webrtc.prototype.setDefaultMicrophone = function(defaultMicrophone)
11758	{
11759		this.defaultMicrophone = defaultMicrophone;
11760	};
11761
11762	BX.webrtc.prototype.logDevices = function()
11763	{
11764		var self = this;
11765		if(navigator.mediaDevices && navigator.mediaDevices.enumerateDevices)
11766		{
11767			self.log('Enumerating media devices');
11768			navigator.mediaDevices.enumerateDevices().then(function(devices)
11769			{
11770				devices.forEach(function(device)
11771				{
11772					try
11773					{
11774						self.log(JSON.stringify(device));
11775					}
11776					catch (e)
11777					{
11778						self.log(device);
11779					}
11780				});
11781			})
11782		}
11783		else
11784		{
11785			self.log('Could not enumerate devices, api is not supported');
11786		}
11787	};
11788
11789	BX.webrtc.mediaStreamTrackToString = function(track)
11790	{
11791		var result = '';
11792		for(key in track)
11793		{
11794			if(!BX.type.isFunction(track[key]))
11795			{
11796				result = result + ' ' + key + ': ' + track[key] + ';';
11797			}
11798		}
11799		return result;
11800	};
11801
11802	BX.webrtc.stopMediaStream = function(mediaStream)
11803	{
11804		if(!(mediaStream instanceof MediaStream))
11805			return;
11806
11807		if (typeof mediaStream.getTracks === 'undefined')
11808		{
11809			// Support for legacy browsers
11810			mediaStream.stop();
11811		}
11812		else
11813		{
11814			mediaStream.getTracks().forEach(function(track)
11815			{
11816				track.stop();
11817			});
11818		}
11819	};
11820
11821})(window);
11822
11823/* End */
11824;
11825; /* Start:"a:4:{s:4:"full";s:49:"/bitrix/js/main/core/core_timer.js?16741571766316";s:6:"source";s:34:"/bitrix/js/main/core/core_timer.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
11826(function(window){
11827if (window.BX.timer) return;
11828
11829var timers = [],
11830	timeout = 200,
11831	obTimer = null,
11832	last_index = 0;
11833
11834BX.timer = function(container, params)
11835{
11836	params = params || {};
11837	if (BX.type.isString(container) || BX.type.isElementNode(container))
11838		params.container = container;
11839	else if (typeof (container) == "object")
11840		params = container;
11841
11842	if (!params.container)
11843		return false;
11844
11845	var ob = new BX.CTimer(params);
11846	BX.timer.start(ob);
11847
11848	if (null == obTimer)
11849	{
11850		obTimer = setInterval(_RunTimer, timeout);
11851		BX.garbage(BX.timer.clear);
11852	}
11853
11854	return ob;
11855}
11856
11857BX.timer.stop = function(timer)
11858{
11859	timers[timer.TIMER_INDEX] = null;
11860}
11861
11862BX.timer.start = function(timer)
11863{
11864	timer.TIMER_INDEX = last_index;
11865	timers[last_index++] = timer;
11866}
11867
11868BX.timer.clock = function(cont, dt)
11869{
11870	return BX.timer({container: cont, dt: dt});
11871}
11872
11873BX.timer.clear = function()
11874{
11875	clearInterval(obTimer);
11876	timers = null;
11877}
11878
11879BX.timer.registerFormat = function(format_name, format_handler)
11880{
11881	BX.CTimer.prototype.formatValueHandlers[format_name] = format_handler
11882}
11883
11884BX.timer.getHandler = function(format_name)
11885{
11886	return BX.CTimer.prototype.formatValueHandlers[format_name];
11887}
11888
11889BX.CTimer = function(params, index)
11890{
11891	this.container = params.container;
11892	this.from = params.from ? parseInt(params.from.valueOf()) : null;
11893	this.to = params.to ? parseInt(params.to.valueOf()) : null;
11894	this.index = index;
11895
11896	this.dt = parseInt(params.dt);
11897	if (isNaN(this.dt))
11898		this.dt = 0;
11899
11900	this.display = params.display || (BX.isAmPmMode() ? 'clock_am_pm' : 'clock'); // other variants - 'simple', 'worktime'
11901
11902	this.accuracy = params.accuracy || 60; // default timing acccuracy is 1 minute
11903
11904	// if (this.from)
11905		// this.from = new Date(parseInt(this.from.valueOf() / this.accuracy) * this.accuracy);
11906	// if (this.to)
11907		// this.to = new Date(parseInt(this.to.valueOf() / this.accuracy) * this.accuracy);
11908
11909	this.callback = this.from ? this._callback_from : (this.to ? this._callback_to : this._callback);
11910	this.callback_finish = params.callback_finish;
11911
11912	this.formatValue = this.formatValueHandlers.clock;
11913
11914	this.bInited = false;
11915	BX.ready(BX.delegate(this.Init, this));
11916}
11917
11918BX.CTimer.prototype.Init = function()
11919{
11920	if (this.bInited)
11921		return;
11922
11923	this.container = BX(this.container);
11924	this.container_value_fld = this.container.tagName.toUpperCase() == 'INPUT' ? 'value' : 'innerHTML';
11925	if (this.container_value_fld == 'value' && (this.display == 'clock' || this.display == 'clock_am_pm'))
11926	{
11927		if (this.display == 'clock')
11928		{
11929			this.display = 'simple';
11930		}
11931		else if (this.display == 'clock_am_pm')
11932		{
11933			this.display = 'simple_am_pm';
11934		}
11935	}
11936
11937	this.formatValue = this.formatValueHandlers[this.display] ? this.formatValueHandlers[this.display] : this.formatValueHandlers.clock;
11938
11939	this.bInited = true;
11940}
11941
11942BX.CTimer.prototype.setFrom = function(from)
11943{
11944	if (!this.from) return;
11945	this.from = from;
11946}
11947
11948BX.CTimer.prototype.setTo = function(to)
11949{
11950	if (!this.to) return;
11951	this.to = to;
11952}
11953
11954BX.CTimer.prototype._callback = function(date)
11955{
11956	if (this.dt !== 0)
11957		var date = new Date(date.valueOf() + this.dt);
11958
11959	this.setValue(this.formatValue(date.getHours(), date.getMinutes(), date.getSeconds()));
11960}
11961
11962BX.CTimer.prototype._callback_from = function(date)
11963{
11964	var diff = (date.valueOf() - this.from.valueOf() + this.dt)/1000;
11965	this.setValue(
11966		this.formatValue(
11967			parseInt(diff / 3600),
11968			parseInt((diff % 3600) / 60),
11969			parseInt(diff % 60)
11970		)
11971	);
11972}
11973
11974BX.CTimer.prototype._callback_to = function(date)
11975{
11976	var diff = (this.to.valueOf() - date.valueOf())/1000;
11977	if (diff > 0)
11978	{
11979		this.setValue(
11980			this.formatValue(
11981				parseInt(diff / 3600),
11982				parseInt((diff % 3600) / 60),
11983				parseInt(diff % 60)
11984			)
11985		);
11986	}
11987	else
11988	{
11989		this.Finish();
11990	}
11991}
11992
11993BX.CTimer.prototype.formatValueHandlers = {
11994	clock: function(h, m, s)
11995	{
11996		var d = '<span class="bx-timer-semicolon">:</span>';
11997
11998		return BX.util.str_pad(h, 2, '0', 'left')
11999			+ d
12000			+ (this.accuracy >= 3600
12001				? '00'
12002				: BX.util.str_pad(m, 2, '0', 'left'))
12003			+ (this.accuracy >= 60
12004				? ''
12005				:
12006				(d + BX.util.str_pad(s, 2, '0', 'left'))
12007			);
12008	},
12009	clock_am_pm: function(h, m, s)
12010	{
12011		var mt = 'am';
12012		var d = '<span class="bx-timer-semicolon">:</span>';
12013
12014		if (h > 12)
12015		{
12016			h = h - 12;
12017			mt = 'pm';
12018		}
12019		else if (h == 0)
12020		{
12021			h = 12;
12022			mt = 'am';
12023		}
12024		else if (h == 12)
12025		{
12026			mt = 'pm';
12027		}
12028
12029		return h
12030			+ d
12031			+ (this.accuracy >= 3600
12032				? '00'
12033				: BX.util.str_pad(m, 2, '0', 'left'))
12034			+ (this.accuracy >= 60
12035				? ''
12036				:
12037				(d + BX.util.str_pad(s, 2, '0', 'left'))
12038			)
12039			+ ' ' + mt;
12040	},
12041	simple: function(h, m, s)
12042	{
12043		return BX.util.str_pad(h, 2, '0', 'left')
12044			+ ':'
12045			+ (this.accuracy >= 3600
12046				? '00'
12047				: BX.util.str_pad(m, 2, '0', 'left'))
12048
12049			+ (this.accuracy >= 60
12050				? ''
12051				:
12052				(':' + BX.util.str_pad(s, 2, '0', 'left'))
12053			);
12054	},
12055	simple_am_pm: function(h, m, s)
12056	{
12057		var mt = 'am';
12058
12059		if (h > 12)
12060		{
12061			h = h - 12;
12062			mt = 'pm';
12063		}
12064		else if (h == 0)
12065		{
12066			h = 12;
12067			mt = 'am';
12068		}
12069		else if (h == 12)
12070		{
12071			mt = 'pm';
12072		}
12073		return h
12074			+ ':'
12075			+ (this.accuracy >= 3600
12076				? '00'
12077				: BX.util.str_pad(m, 2, '0', 'left'))
12078
12079			+ (this.accuracy >= 60
12080				? ''
12081				:
12082				(':' + BX.util.str_pad(s, 2, '0', 'left'))
12083			) + ' ' + mt;
12084	},
12085	worktime: function(h, m, s)
12086	{
12087		return h + BX.message('JS_CORE_H') + ' '
12088			+ (this.accuracy >= 3600
12089				? ''
12090				: m + BX.message('JS_CORE_M')
12091					+ (this.accuracy >= 60
12092						? ''
12093						: ' ' + s + BX.message('JS_CORE_S')
12094					)
12095				);
12096	},
12097	worktime_short: function(h, m, s)
12098	{
12099		return BX.util.rtrim((h > 0 ? h + BX.message('JS_CORE_H') + ' ' : '')
12100			+ (m > 0 && this.accuracy < 3600 ? m + BX.message('JS_CORE_M') + ' ' : '')
12101			+ (this.accuracy >= 60
12102				? ''
12103				: (s > 0 ? s + BX.message('JS_CORE_S') : '')
12104			));
12105	}
12106}
12107
12108BX.CTimer.prototype.setValue = function(value)
12109{
12110	if (this.bInited)
12111	{
12112		if (value != this._last_value)
12113			this.container[this.container_value_fld] = value;
12114
12115		this._last_value = value;
12116	}
12117}
12118
12119BX.CTimer.prototype.Finish = function()
12120{
12121	BX.timer.stop(this);
12122
12123	if (this.callback_finish)
12124		this.callback_finish.apply(this);
12125
12126	BX.cleanNode(this.container.parentNode);
12127}
12128
12129function _RunTimer()
12130{
12131	var current_moment = new Date();
12132
12133	for (var i=0,len=last_index;i<len;i++)
12134	{
12135		if (timers[i] && timers[i].callback)
12136			timers[i].callback.apply(timers[i], [current_moment]);
12137	}
12138
12139	current_moment = null;
12140}
12141})(window)
12142
12143/* End */
12144;

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.