PageSourceSearch

https://muzopt.ru/bitrix/js/main/core/core_popup.js?162764464559673

js muzopt.ru collected 2026-10-04 00:12:59 UTC 59,673 bytes, 2,649 lines download raw bytes

1;(function(window) {
2
3"use strict";
4
5if (BX.PopupWindowManager)
6{
7	return;
8}
9
10BX.PopupWindowManager =
11{
12	_popups : [],
13	_currentPopup : null,
14
15	create : function(uniquePopupId, bindElement, params)
16	{
17		var index = -1;
18		if ((index = this._getPopupIndex(uniquePopupId)) !== -1)
19		{
20			return this._popups[index];
21		}
22
23		var popupWindow = new BX.PopupWindow(uniquePopupId, bindElement, params);
24		BX.addCustomEvent(popupWindow, "onPopupShow", BX.delegate(this.onPopupShow, this));
25		BX.addCustomEvent(popupWindow, "onPopupClose", BX.delegate(this.onPopupClose, this));
26
27		return popupWindow;
28	},
29
30	onPopupWindowIsInitialized : function(uniquePopupId, popupWindow)
31	{
32		BX.addCustomEvent(popupWindow, "onPopupDestroy", BX.delegate(this.onPopupDestroy, this));
33		this._popups.push(popupWindow);
34	},
35
36	onPopupShow : function(popupWindow)
37	{
38		if (this._currentPopup !== null)
39		{
40			this._currentPopup.close();
41		}
42
43		this._currentPopup = popupWindow;
44	},
45
46	onPopupClose : function(popupWindow)
47	{
48		this._currentPopup = null;
49	},
50
51	onPopupDestroy : function(popupWindow)
52	{
53		var index;
54		if ((index = this._getPopupIndex(popupWindow.uniquePopupId)) !== -1)
55		{
56			this._popups = BX.util.deleteFromArray(this._popups, index);
57		}
58	},
59
60	getCurrentPopup : function()
61	{
62		return this._currentPopup;
63	},
64
65	isPopupExists : function(uniquePopupId)
66	{
67		return this._getPopupIndex(uniquePopupId) !== -1
68	},
69
70	_getPopupIndex : function(uniquePopupId)
71	{
72		var index = -1;
73
74		for (var i = 0; i < this._popups.length; i++)
75		{
76			if (this._popups[i].uniquePopupId === uniquePopupId)
77			{
78				return i;
79			}
80		}
81
82		return index;
83	},
84
85	getMaxZIndex : function()
86	{
87		var zIndex = 0, ii;
88		for (ii = 0; ii < this._popups.length; ii++)
89		{
90			zIndex = Math.max(zIndex, this._popups[ii].params.zIndex);
91		}
92		return zIndex;
93	}
94};
95BX.addCustomEvent("onPopupWindowIsInitialized", BX.proxy(BX.PopupWindowManager.onPopupWindowIsInitialized, BX.PopupWindowManager));
96/**
97 *
98 * @param {string} uniquePopupId
99 * @param {Element|object|null} bindElement
100 * @param params
101 * @constructor
102 */
103BX.PopupWindow = function(uniquePopupId, bindElement, params)
104{
105	params = params || {};
106	this.params = params;
107
108	BX.onCustomEvent("onPopupWindowInit", [uniquePopupId, bindElement, params]);
109
110	this.uniquePopupId = uniquePopupId;
111
112	this.params.zIndex = parseInt(params.zIndex);
113	this.params.zIndex = isNaN(params.zIndex) ? 0 : params.zIndex;
114	this.buttons = params.buttons && BX.type.isArray(params.buttons) ? params.buttons : [];
115	this.offsetTop = BX.PopupWindow.getOption("offsetTop");
116	this.offsetLeft = BX.PopupWindow.getOption("offsetLeft");
117	this.firstShow = false;
118	this.bordersWidth = 20;
119	this.bindElementPos = null;
120	this.closeIcon = null;
121	this.resizeIcon = null;
122	this.angle = null;
123	this.overlay = null;
124	this.titleBar = null;
125	this.bindOptions = typeof(params.bindOptions) === "object" ? params.bindOptions : {};
126	this.autoHide = params.autoHide === true;
127	this.isAutoHideBinded = false;
128	this.closeByEsc = params.closeByEsc === true;
129	this.isCloseByEscBinded = false;
130
131	this.width = null;
132	this.height = null;
133	this.minWidth = 0;
134	this.minHeight = 0;
135
136	if (params.parentPopup instanceof BX.PopupWindow)
137	{
138		this.parentPopup = params.parentPopup;
139		this.appendContainer = params.parentPopup.contentContainer;
140
141		params.offsetTop = (params.offsetTop? params.offsetTop: 0) - (BX.PopupWindow.fullscreenStatus? 0: this.parentPopup.popupContainer.offsetTop);
142		params.offsetLeft = (params.offsetLeft? params.offsetLeft: 0) - (BX.PopupWindow.fullscreenStatus? 0: this.parentPopup.popupContainer.offsetLeft);
143	}
144	else
145	{
146		this.parentPopup = null;
147		this.appendContainer = document.body;
148	}
149
150	this.dragOptions = {
151		cursor: "",
152		callback: BX.DoNothing,
153		eventName: ""
154	};
155	this.dragged = false;
156	this.dragPageX = 0;
157	this.dragPageY = 0;
158
159	if (params.events)
160	{
161		for (var eventName in params.events)
162		{
163			BX.addCustomEvent(this, eventName, params.events[eventName]);
164		}
165	}
166
167	var popupClassName = "popup-window";
168
169	/*if (params.lightShadow)
170		popupClassName += " popup-window-light";*/
171
172	if (params.contentColor && BX.type.isNotEmptyString(params.contentColor))
173	{
174		popupClassName += " popup-window-content-" + params.contentColor;
175	}
176
177	if (params.contentNoPaddings)
178	{
179		popupClassName += " popup-window-content-no-paddings";
180	}
181
182	if (params.noAllPaddings)
183	{
184		popupClassName += " popup-window-no-paddings";
185	}
186
187	if (params.titleBar)
188	{
189		popupClassName += " popup-window-with-titlebar";
190	}
191
192	if (params.className && BX.type.isNotEmptyString(params.className))
193	{
194		popupClassName += " " + params.className;
195	}
196
197	if (params.darkMode)
198	{
199		popupClassName += ' popup-window-dark';
200	}
201
202	this.popupContainer = document.createElement("div");
203	var titleBarID = "popup-window-titlebar-" + uniquePopupId;
204
205	if(params.titleBar)
206	{
207		this.titleBar = BX.create("div", {
208			props : {
209				className: "popup-window-titlebar",
210				id: titleBarID
211			}
212		});
213	}
214
215	if (params.closeIcon)
216	{
217		this.closeIcon = BX.create("span", {
218			props : { className: "popup-window-close-icon" + (params.titleBar ? " popup-window-titlebar-close-icon" : "") },
219			style : (typeof(params.closeIcon) === "object" ? params.closeIcon : {} ),
220			events : { click : BX.proxy(this._onCloseIconClick, this) }
221		});
222
223		if (BX.browser.IsIE())
224		{
225			BX.adjust(this.closeIcon, { attrs: { hidefocus: "true" } });
226		}
227	}
228
229	this.contentContainer = BX.create("div",{
230		props:{
231			id: "popup-window-content-" +  uniquePopupId,
232			className: "popup-window-content"
233		}
234	});
235
236	BX.adjust(this.popupContainer, {
237		props : {
238			id : uniquePopupId,
239			className : popupClassName
240		},
241		style : {
242			zIndex: this.getZindex(),
243			position: "absolute",
244			display: "none",
245			top: "0px",
246			left: "0px"
247		},
248		children : [this.titleBar, this.contentContainer, this.closeIcon]
249	});
250
251	this.appendContainer.appendChild(this.popupContainer);
252
253	this.buttonsContainer = null;
254
255	if (params.angle)
256	{
257		this.setAngle(params.angle);
258	}
259
260	if (params.overlay)
261	{
262		this.setOverlay(params.overlay);
263	}
264
265	this.setOffset(params);
266	this.setBindElement(bindElement);
267	this.setTitleBar(params.titleBar);
268	this.setContent(params.content);
269	this.setButtons(params.buttons);
270	this.setWidth(params.width);
271	this.setHeight(params.height);
272	this.setResizeMode(params.resizable);
273
274	if (params.bindOnResize !== false)
275	{
276		BX.bind(window, "resize", BX.proxy(this._onResizeWindow, this));
277	}
278	BX.onCustomEvent("onPopupWindowIsInitialized", [uniquePopupId, this]);
279};
280
281/**
282 *
283 * @param {Element|string} content
284 */
285BX.PopupWindow.prototype.setContent = function(content)
286{
287	if (!this.contentContainer || !content)
288	{
289		return;
290	}
291
292	if (BX.type.isElementNode(content))
293	{
294		BX.cleanNode(this.contentContainer);
295		this.contentContainer.appendChild(content.parentNode ? content.parentNode.removeChild(content) : content );
296		content.style.display = "block";
297	}
298	else if (BX.type.isString(content))
299	{
300		this.contentContainer.innerHTML = content;
301	}
302	else
303	{
304		this.contentContainer.innerHTML = "&nbsp;";
305	}
306};
307
308/**
309 *
310 * @param {BX.PopupWindowButton[]} buttons
311 */
312BX.PopupWindow.prototype.setButtons = function(buttons)
313{
314	this.buttons = buttons && BX.type.isArray(buttons) ? buttons : [];
315
316	if (this.buttonsContainer)
317	{
318		BX.remove(this.buttonsContainer);
319	}
320
321	if (this.buttons.length > 0 && this.contentContainer)
322	{
323		var newButtons = [];
324		for (var i = 0; i < this.buttons.length; i++)
325		{
326			var button = this.buttons[i];
327			if (button === null || !BX.is_subclass_of(button, BX.PopupWindowButton))
328			{
329				continue;
330			}
331
332			button.popupWindow = this;
333			newButtons.push(button.render());
334		}
335
336		this.buttonsContainer = this.contentContainer.parentNode.appendChild(
337			BX.create("div",{
338				props : { className : "popup-window-buttons" },
339				children : newButtons
340			})
341		);
342	}
343};
344
345/**
346 *
347 * @returns {BX.PopupWindowButton[]}
348 */
349BX.PopupWindow.prototype.getButtons = function()
350{
351	return this.buttons;
352};
353
354/**
355 *
356 * @param {string} id
357 * @returns {BX.PopupWindowButton}
358 */
359BX.PopupWindow.prototype.getButton = function(id)
360{
361	for (var i = 0; i < this.buttons.length; i++)
362	{
363		var button = this.buttons[i];
364		if (button.getId() === id)
365		{
366			return button;
367		}
368	}
369
370	return null;
371};
372
373/**
374 *
375 * @param {Element|Event|object} bindElement
376 */
377BX.PopupWindow.prototype.setBindElement = function(bindElement)
378{
379	if (!bindElement || typeof(bindElement) !== "object")
380	{
381		return;
382	}
383
384	if (BX.type.isDomNode(bindElement) || (BX.type.isNumber(bindElement.top) && BX.type.isNumber(bindElement.left)))
385	{
386		this.bindElement = bindElement;
387	}
388	else if (BX.type.isNumber(bindElement.clientX) && BX.type.isNumber(bindElement.clientY))
389	{
390		BX.fixEventPageXY(bindElement);
391		this.bindElement = { left : bindElement.pageX, top : bindElement.pageY, bottom : bindElement.pageY };
392	}
393};
394
395/**
396 *
397 * @param bindElement
398 * @returns {object} position
399 */
400BX.PopupWindow.prototype.getBindElementPos = function(bindElement)
401{
402	if (BX.type.isDomNode(bindElement))
403	{
404		return BX.pos(bindElement, false);
405	}
406	else if (bindElement && typeof(bindElement) === "object")
407	{
408		if (!BX.type.isNumber(bindElement.bottom))
409		{
410			bindElement.bottom = bindElement.top;
411		}
412
413		return bindElement;
414	}
415	else
416	{
417		var windowSize =  BX.GetWindowInnerSize();
418		var windowScroll = BX.GetWindowScrollPos();
419		var popupWidth = this.popupContainer.offsetWidth;
420		var popupHeight = this.popupContainer.offsetHeight;
421
422		this.bindOptions.forceTop = true;
423
424		return {
425			left : windowSize.innerWidth/2 - popupWidth/2 + windowScroll.scrollLeft,
426			top : windowSize.innerHeight/2 - popupHeight/2 + windowScroll.scrollTop,
427			bottom : windowSize.innerHeight/2 - popupHeight/2 + windowScroll.scrollTop,
428
429			//for optimisation purposes
430			windowSize : windowSize,
431			windowScroll : windowScroll,
432			popupWidth : popupWidth,
433			popupHeight : popupHeight
434		};
435	}
436};
437
438/**
439 *
440 * @param {Object|bool} params
441 * @param {number} [params.offset = 0]
442 * @param {string} [params.position = "top"]
443 */
444BX.PopupWindow.prototype.setAngle = function(params)
445{
446	if (params === false && this.angle !== null)
447	{
448		BX.remove(this.angle.element);
449		this.angle = null;
450		return;
451	}
452
453	var className = "popup-window-angly";
454	if (this.angle === null)
455	{
456		var position = this.bindOptions.position && this.bindOptions.position === "top" ? "bottom" : "top";
457		var angleMinLeft = BX.PopupWindow.getOption(position === "top" ? "angleMinTop" : "angleMinBottom");
458		var defaultOffset = BX.type.isNumber(params.offset) ? params.offset : 0;
459
460		var angleLeftOffset = BX.PopupWindow.getOption("angleLeftOffset", null);
461		if (defaultOffset > 0 && BX.type.isNumber(angleLeftOffset))
462		{
463			defaultOffset += angleLeftOffset - BX.PopupWindow.defaultOptions.angleLeftOffset;
464		}
465
466		this.angle = {
467			element : BX.create("div", { props : { className: className + " " + className +"-" + position }}),
468			position : position,
469			offset : 0,
470			defaultOffset : Math.max(defaultOffset, angleMinLeft)
471			//Math.max(BX.type.isNumber(params.offset) ? params.offset : 0, angleMinLeft)
472		};
473
474		this.popupContainer.appendChild(this.angle.element);
475	}
476
477	if (typeof(params) === "object" && params.position && BX.util.in_array(params.position, ["top", "right", "bottom", "left", "hide"]))
478	{
479		BX.removeClass(this.angle.element, className + "-" +  this.angle.position);
480		BX.addClass(this.angle.element, className + "-" +  params.position);
481		this.angle.position = params.position;
482	}
483
484	if (typeof(params) === "object" && BX.type.isNumber(params.offset))
485	{
486		var offset = params.offset;
487		var minOffset, maxOffset;
488		if (this.angle.position === "top")
489		{
490			minOffset = BX.PopupWindow.getOption("angleMinTop");
491			maxOffset = this.popupContainer.offsetWidth - BX.PopupWindow.getOption("angleMaxTop");
492			maxOffset = maxOffset < minOffset ? Math.max(minOffset, offset) : maxOffset;
493
494			this.angle.offset = Math.min(Math.max(minOffset, offset), maxOffset);
495			this.angle.element.style.left = this.angle.offset + "px";
496			this.angle.element.style.marginLeft = 0;
497		}
498		else if (this.angle.position === "bottom")
499		{
500			minOffset = BX.PopupWindow.getOption("angleMinBottom");
501			maxOffset = this.popupContainer.offsetWidth - BX.PopupWindow.getOption("angleMaxBottom");
502			maxOffset = maxOffset < minOffset ? Math.max(minOffset, offset) : maxOffset;
503
504			this.angle.offset = Math.min(Math.max(minOffset, offset), maxOffset);
505			this.angle.element.style.marginLeft = this.angle.offset + "px";
506			this.angle.element.style.left = 0;
507		}
508		else if (this.angle.position === "right")
509		{
510			minOffset = BX.PopupWindow.getOption("angleMinRight");
511			maxOffset = this.popupContainer.offsetHeight - BX.PopupWindow.getOption("angleMaxRight");
512			maxOffset = maxOffset < minOffset ? Math.max(minOffset, offset) : maxOffset;
513
514			this.angle.offset = Math.min(Math.max(minOffset, offset), maxOffset);
515			this.angle.element.style.top = this.angle.offset + "px";
516		}
517		else if (this.angle.position === "left")
518		{
519			minOffset = BX.PopupWindow.getOption("angleMinLeft");
520			maxOffset = this.popupContainer.offsetHeight - BX.PopupWindow.getOption("angleMaxLeft");
521			maxOffset = maxOffset < minOffset ? Math.max(minOffset, offset) : maxOffset;
522
523			this.angle.offset = Math.min(Math.max(minOffset, offset), maxOffset);
524			this.angle.element.style.top = this.angle.offset + "px";
525		}
526	}
527};
528
529/**
530 *
531 * @param {number} width
532 */
533BX.PopupWindow.prototype.setWidth = function(width)
534{
535	if (BX.type.isNumber(width) && width >= 0)
536	{
537		this.width = width;
538		this.contentContainer.style.width = width + "px";
539		this.contentContainer.style.overflowX = "auto";
540		if (this.titleBar)
541		{
542			this.titleBar.style.width = width + "px";
543		}
544	}
545	else if (width === false)
546	{
547		this.width = null;
548		this.contentContainer.style.removeProperty("width");
549		this.contentContainer.style.removeProperty("overflowX");
550		if (this.titleBar)
551		{
552			this.titleBar.style.removeProperty("width");
553		}
554	}
555};
556
557/**
558 *
559 * @param {number} height
560 */
561BX.PopupWindow.prototype.setHeight = function(height)
562{
563	if (BX.type.isNumber(height) && height >= 0)
564	{
565		this.height = height;
566		this.contentContainer.style.height = height + "px";
567		this.contentContainer.style.overflowY = "auto";
568	}
569	else if (height === false)
570	{
571		this.height = null;
572		this.contentContainer.style.removeProperty("height");
573		this.contentContainer.style.removeProperty("overflowY");
574	}
575};
576
577/**
578 *
579 * @param {object} options
580 * @param {number} [options.minWidth = 0]
581 * @param {number} [options.minHeight = 0]
582 * @param {bool} [options.restrict = true]
583 *
584 */
585BX.PopupWindow.prototype.setResizeMode = function(options)
586{
587	if (options === true || BX.type.isPlainObject(options))
588	{
589		if (!this.resizeIcon)
590		{
591			this.resizeIcon = BX.create("div", {
592				props: {
593					className: "popup-window-resize"
594				},
595				events: {
596					mousedown: BX.proxy(this.onResizeMouseDown, this)
597				}
598			});
599
600			this.popupContainer.appendChild(this.resizeIcon);
601		}
602
603		if (BX.type.isNumber(options.minWidth) && options.minWidth > 0)
604		{
605			this.minWidth = options.minWidth;
606		}
607
608		if (BX.type.isNumber(options.minHeight) && options.minHeight > 0)
609		{
610			this.minHeight = options.minHeight;
611		}
612	}
613	else if (options === false && this.resizeIcon)
614	{
615		BX.remove(this.resizeIcon);
616		this.resizeIcon = null;
617	}
618};
619
620/**
621 *
622 * @returns {number|null}
623 */
624BX.PopupWindow.prototype.getWidth = function()
625{
626	return this.width;
627};
628
629/**
630 *
631 * @returns {number|null}
632 */
633BX.PopupWindow.prototype.getHeight = function()
634{
635	return this.height;
636};
637
638BX.PopupWindow.prototype.onTitleMouseDown = function(event)
639{
640	this._startDrag(
641		event,
642		{
643			cursor: "move",
644			callback: BX.proxy(this.move, this),
645			eventName: "Drag"
646		}
647	);
648};
649
650BX.PopupWindow.prototype.onResizeMouseDown = function(event)
651{
652	this._startDrag(
653		event,
654		{
655			cursor: "nwse-resize",
656			eventName: "Resize",
657			callback: BX.proxy(this._resize, this)
658		}
659	);
660
661	this.resizeContentPos = BX.pos(this.contentContainer);
662	this.resizeContentOffset = this.resizeContentPos.left - BX.pos(this.popupContainer).left;
663};
664
665BX.PopupWindow.prototype._resize = function(offsetX, offsetY, pageX, pageY)
666{
667	var width = pageX - this.resizeContentPos.left;
668	var height = pageY - this.resizeContentPos.top;
669
670	var scrollWidth = BX.GetWindowScrollSize().scrollWidth;
671	if (this.resizeContentPos.left + width + this.resizeContentOffset >= scrollWidth)
672	{
673		width = scrollWidth - this.resizeContentPos.left - this.resizeContentOffset;
674	}
675
676	this.setWidth(Math.max(width, this.minWidth));
677	this.setHeight(Math.max(height, this.minHeight));
678};
679
680BX.PopupWindow.prototype.isTopAngle = function()
681{
682	return this.angle !== null && this.angle.position === "top";
683};
684
685BX.PopupWindow.prototype.isBottomAngle = function()
686{
687	return this.angle !== null && this.angle.position === "bottom";
688};
689
690BX.PopupWindow.prototype.isTopOrBottomAngle = function()
691{
692	return this.angle !== null && BX.util.in_array(this.angle.position, ["to
692p", "bottom"]);
693};
694
695BX.PopupWindow.prototype.getAngleHeight = function()
696{
697	return (this.isTopOrBottomAngle() ? BX.PopupWindow.getOption("angleTopOffset") : 0);
698};
699
700/**
701 *
702 * @param {object} params
703 * @param {number} [params.offsetLeft]
704 * @param {number} [params.offsetTop]
705 */
706BX.PopupWindow.prototype.setOffset = function(params)
707{
708	if (!BX.type.isPlainObject(params))
709	{
710		return;
711	}
712
713	if (params.offsetLeft && BX.type.isNumber(params.offsetLeft))
714	{
715		this.offsetLeft = params.offsetLeft + BX.PopupWindow.getOption("offsetLeft");
716	}
717
718	if (params.offsetTop && BX.type.isNumber(params.offsetTop))
719	{
720		this.offsetTop = params.offsetTop + BX.PopupWindow.getOption("offsetTop");
721	}
722};
723
724/**
725 *
726 * @param {object|string} params
727 * @param {Element} [params.content]
728 */
729BX.PopupWindow.prototype.setTitleBar = function(params)
730{
731	if (!this.titleBar)
732	{
733		return;
734	}
735
736	if (typeof(params) === "object" && BX.type.isDomNode(params.content))
737	{
738		this.titleBar.innerHTML = "";
739		this.titleBar.appendChild(params.content);
740	}
741	else if (typeof(params) === "string")
742	{
743		this.titleBar.innerHTML = "";
744		this.titleBar.appendChild(
745			BX.create("span", {
746				props : {
747					className: "popup-window-titlebar-text"
748				},
749				text : params
750			})
751		);
752	}
753
754	if (this.params.draggable)
755	{
756		this.titleBar.style.cursor = "move";
757		BX.bind(this.titleBar, "mousedown", BX.proxy(this.onTitleMouseDown, this));
758	}
759};
760
761/**
762 *
763 * @param {bool} enable
764 */
765BX.PopupWindow.prototype.setClosingByEsc = function(enable)
766{
767	enable = BX.type.isBoolean(enable) ? enable : true;
768	if (enable)
769	{
770		this.closeByEsc = true;
771		if (!this.isCloseByEscBinded)
772		{
773			BX.bind(document, "keyup", BX.proxy(this._onKeyUp, this));
774			this.isCloseByEscBinded = true;
775		}
776	}
777	else
778	{
779		this.closeByEsc = false;
780		if (this.isCloseByEscBinded)
781		{
782			BX.unbind(document, "keyup", BX.proxy(this._onKeyUp, this));
783			this.isCloseByEscBinded = false;
784		}
785	}
786};
787
788/**
789 *
790 * @param {bool} enable
791 */
792BX.PopupWindow.prototype.setAutoHide = function(enable)
793{
794	enable = BX.type.isBoolean(enable) ? enable : true;
795	if (enable)
796	{
797		this.autoHide = true;
798		if (this.isShown())
799		{
800			this.bindAutoHide();
801		}
802	}
803	else
804	{
805		this.autoHide = false;
806		this.unbindAutoHide();
807	}
808};
809
810BX.PopupWindow.prototype.bindAutoHide = function()
811{
812	if (!this.isAutoHideBinded)
813	{
814		this.isAutoHideBinded = true;
815		BX.bind(this.popupContainer, "click", this.cancelBubble);
816		if(this.overlay && this.overlay.element)
817			BX.bind(this.overlay.element, "click", BX.proxy(this.close, this));
818		else
819			BX.bind(document, "click", BX.proxy(this.close, this));
820	}
821};
822
823BX.PopupWindow.prototype.unbindAutoHide = function()
824{
825	if (this.isAutoHideBinded)
826	{
827		this.isAutoHideBinded = false;
828		BX.unbind(this.popupContainer, "click", this.cancelBubble);
829		if(this.overlay && this.overlay.element)
830			BX.unbind(this.overlay.element, "click", BX.proxy(this.close, this));
831		else
832			BX.unbind(document, "click", BX.proxy(this.close, this));
833	}
834};
835
836/**
837 *
838 * @param {object} params
839 * @param {number} [params.opacity]
840 * @param {string} [params.backgroundColor]
841 */
842BX.PopupWindow.prototype.setOverlay = function(params)
843{
844	if (this.overlay === null)
845	{
846		this.overlay = {
847			element : BX.create("div", {
848				props : {
849					className: "popup-window-overlay", id : "popup-window-overlay-" + this.uniquePopupId
850				}
851			})
852		};
853
854		this.adjustOverlayZindex();
855		this.resizeOverlay();
856
857		this.appendContainer.appendChild(this.overlay.element);
858	}
859
860	if (params && params.hasOwnProperty('opacity') && BX.type.isNumber(params.opacity) && params.opacity >= 0 && params.opacity <= 100)
861	{
862		if (BX.browser.IsIE() && !BX.browser.IsIE9())
863		{
864			this.overlay.element.style.filter =  "alpha(opacity=" + params.opacity +")";
865		}
866		else
867		{
868			this.overlay.element.style.filter = "none";
869			this.overlay.element.style.opacity = parseFloat(params.opacity/100).toPrecision(3);
870		}
871	}
872
873	if (params && params.backgroundColor)
874	{
875		this.overlay.element.style.backgroundColor = params.backgroundColor;
876	}
877};
878
879BX.PopupWindow.prototype.removeOverlay = function()
880{
881	if (this.overlay !== null && this.overlay.element !== null)
882	{
883		BX.remove(this.overlay.element);
884	}
885
886	if (this.overlayTimeout)
887	{
888		clearInterval(this.overlayTimeout);
889		this.overlayTimeout = null;
890	}
891
892	this.overlay = null;
893};
894
895BX.PopupWindow.prototype.hideOverlay = function()
896{
897	if (this.overlay !== null && this.overlay.element !== null)
898	{
899		if (this.overlayTimeout)
900		{
901			clearInterval(this.overlayTimeout);
902			this.overlayTimeout = null;
903		}
904
905		this.overlay.element.style.display = "none";
906	}
907};
908
909BX.PopupWindow.prototype.showOverlay = function()
910{
911	if (this.overlay !== null && this.overlay.element !== null)
912	{
913		this.overlay.element.style.display = "block";
914
915		var popupHeight = this.popupContainer.offsetHeight;
916		this.overlayTimeout = setInterval(function() {
917			if (popupHeight !== this.popupContainer.offsetHeight)
918			{
919				this.resizeOverlay();
920				popupHeight = this.popupContainer.offsetHeight;
921			}
922
923		}.bind(this), 1000);
924	}
925};
926
927BX.PopupWindow.prototype.resizeOverlay = function()
928{
929	if (this.overlay !== null && this.overlay.element !== null)
930	{
931		if (this.parentPopup)
932		{
933			this.overlay.element.style.width = this.parentPopup.popupContainer.offsetWidth + "px";
934			this.overlay.element.style.height = this.parentPopup.popupContainer.offsetHeight + "px";
935		}
936		else
937		{
938			var windowSize = BX.GetWindowScrollSize();
939			var scrollHeight = Math.max(
940				document.body.scrollHeight, document.documentElement.scrollHeight,
941				document.body.offsetHeight, document.documentElement.offsetHeight,
942				document.body.clientHeight, document.documentElement.clientHeight
943			);
944
945			this.overlay.element.style.width = windowSize.scrollWidth + "px";
946			this.overlay.element.style.height = scrollHeight + "px";
947		}
948	}
949};
950
951BX.PopupWindow.prototype.getZindex = function()
952{
953	if (this.overlay !== null)
954	{
955		return BX.PopupWindow.getOption("popupOverlayZindex") + this.params.zIndex;
956	}
957	else
958	{
959		return BX.PopupWindow.getOption("popupZindex") + this.params.zIndex;
960	}
961};
962
963BX.PopupWindow.prototype.adjustOverlayZindex = function()
964{
965	if (this.overlay !== null && this.overlay.element !== null)
966	{
967		this.overlay.element.style.zIndex = parseInt(this.popupContainer.style.zIndex) - 1;
968	}
969};
970
971BX.PopupWindow.prototype.show = function()
972{
973	if (!this.firstShow)
974	{
975		BX.onCustomEvent(this, "onPopupFirstShow", [this]);
976		this.firstShow = true;
977	}
978	BX.onCustomEvent(this, "onPopupShow", [this]);
979
980	this.showOverlay();
981	this.popupContainer.style.display = "block";
982
983	this.adjustPosition();
984
985	BX.onCustomEvent(this, "onAfterPopupShow", [this]);
986
987	if (this.closeByEsc && !this.isCloseByEscBinded)
988	{
989		BX.bind(document, "keyup", BX.proxy(this._onKeyUp, this));
990		this.isCloseByEscBinded = true;
991	}
992
993	if (this.autoHide && !this.isAutoHideBinded)
994	{
995		setTimeout(
996			BX.proxy(function() {
997				if (this.isShown())
998				{
999					this.bindAutoHide();
1000				}
1001			}, this), 100
1002		);
1003	}
1004};
1005
1006BX.PopupWindow.prototype.isShown = function()
1007{
1008   return this.popupContainer.style.display === "block";
1009};
1010
1011BX.PopupWindow.prototype.cancelBubble = function(event)
1012{
1013	event = event || window.event;
1014
1015	if (event.stopPropagation)
1016	{
1017		event.stopPropagation();
1018	}
1019	else
1020	{
1021		event.cancelBubble = true;
1022	}
1023};
1024
1025BX.PopupWindow.prototype.close = function(event)
1026{
1027	if (!this.isShown())
1028	{
1029		return;
1030	}
1031
1032	if (event && !(BX.getEventButton(event) & BX.MSLEFT))
1033	{
1034		return true;
1035	}
1036
1037	BX.onCustomEvent(this, "onPopupClose", [this, event]);
1038
1039	this.hideOverlay();
1040	this.popupContainer.style.display = "none";
1041
1042	if (this.isCloseByEscBinded)
1043	{
1044		BX.unbind(document, "keyup", BX.proxy(this._onKeyUp, this));
1045		this.isCloseByEscBinded = false;
1046	}
1047
1048	setTimeout(BX.proxy(this._close, this), 0);
1049};
1050
1051BX.PopupWindow.prototype._close = function()
1052{
1053	if (this.autoHide)
1054	{
1055		this.unbindAutoHide();
1056	}
1057};
1058
1059BX.PopupWindow.prototype._onCloseIconClick = function(event)
1060{
1061	event = event || window.event;
1062	this.close(event);
1063	BX.PreventDefault(event);
1064};
1065
1066BX.PopupWindow.prototype._onKeyUp = function(event)
1067{
1068	event = event || window.event;
1069	if (event.keyCode === 27)
1070	{
1071		_checkEscPressed(this.getZindex(), BX.proxy(this.close, this));
1072	}
1073};
1074
1075BX.PopupWindow.prototype.destroy = function()
1076{
1077	BX.onCustomEvent(this, "onPopupDestroy", [this]);
1078	BX.unbindAll(this);
1079	BX.unbind(document, "keyup", BX.proxy(this._onKeyUp, this));
1080	BX.unbind(document, "click", BX.proxy(this.close, this));
1081	BX.unbind(document, "mousemove", BX.proxy(this._moveDrag, this));
1082	BX.unbind(document, "mouseup", BX.proxy(this._stopDrag, this));
1083	BX.unbind(window, "resize", BX.proxy(this._onResizeWindow, this));
1084	BX.remove(this.popupContainer);
1085	this.removeOverlay();
1086};
1087
1088BX.PopupWindow.prototype.enterFullScreen = function()
1089{
1090	if (BX.PopupWindow.fullscreenStatus)
1091	{
1092		if (document.cancelFullScreen)
1093		{
1094			document.cancelFullScreen();
1095		}
1096		else if (document.mozCancelFullScreen)
1097		{
1098			document.mozCancelFullScreen();
1099		}
1100		else if (document.webkitCancelFullScreen)
1101		{
1102			document.webkitCancelFullScreen();
1103		}
1104	}
1105	else
1106	{
1107		if (BX.browser.IsChrome() || BX.browser.IsSafari())
1108		{
1109			this.contentContainer.webkitRequestFullScreen(this.contentContainer.ALLOW_KEYBOARD_INPUT);
1110			BX.bind(window, "webkitfullscreenchange", this.fullscreenBind = BX.proxy(this.eventFullScreen, this));
1111		}
1112		else if (BX.browser.IsFirefox())
1113		{
1114			this.contentContainer.mozRequestFullScreen(this.contentContainer.ALLOW_KEYBOARD_INPUT);
1115			BX.bind(window, "mozfullscreenchange", this.fullscreenBind = BX.proxy(this.eventFullScreen, this));
1116		}
1117	}
1118};
1119
1120BX.PopupWindow.prototype.eventFullScreen = function(event)
1121{
1122	if (BX.PopupWindow.fullscreenStatus)
1123	{
1124		if (BX.browser.IsChrome() || BX.browser.IsSafari())
1125		{
1126			BX.unbind(window, "webkitfullscreenchange", this.fullscreenBind);
1127		}
1128		else if (BX.browser.IsFirefox())
1129		{
1130			BX.unbind(window, "mozfullscreenchange", this.fullscreenBind);
1131		}
1132
1133		BX.removeClass(this.contentContainer, "popup-window-fullscreen", [this.contentContainer]);
1134
1135		BX.PopupWindow.fullscreenStatus = false;
1136		BX.onCustomEvent(this, "onPopupFullscreenLeave");
1137		this.adjustPosition();
1138	}
1139	else
1140	{
1141		BX.addClass(this.contentContainer, "popup-window-fullscreen");
1142		BX.PopupWindow.fullscreenStatus = true;
1143		BX.onCustomEvent(this, "onPopupFullscreenEnter", [this.contentContainer]);
1144		this.adjustPosition();
1145	}
1146};
1147
1148/**
1149 *
1150 * @param {object} bindOptions
1151 * @param {bool} [bindOptions.forceBindPosition]
1152 * @param {bool} [bindOptions.forceLeft]
1153 * @param {bool} [bindOptions.forceTop]
1154 * @param {string} [bindOptions.position = "bottom"]
1155 */
1156BX.PopupWindow.prototype.adjustPosition = function(bindOptions)
1157{
1158	if (bindOptions && typeof(bindOptions) === "object")
1159	{
1160		this.bindOptions = bindOptions;
1161	}
1162
1163	var bindElementPos = this.getBindElementPos(this.bindElement);
1164
1165	if (
1166		!this.bindOptions.forceBindPosition &&
1167		this.bindElementPos !== null &&
1168		bindElementPos.top === this.bindElementPos.top &&
1169		bindElementPos.left === this.bindElementPos.left
1170	)
1171	{
1172		return;
1173	}
1174
1175	this.bindElementPos = bindElementPos;
1176
1177	var windowSize = bindElementPos.windowSize ? bindElementPos.windowSize : BX.GetWindowInnerSize();
1178	var windowScroll = bindElementPos.windowScroll ? bindElementPos.windowScroll : BX.GetWindowScrollPos();
1179	var popupWidth = bindElementPos.popupWidth ? bindElementPos.popupWidth : this.popupContainer.offsetWidth;
1180	var popupHeight = bindElementPos.popupHeight ? bindElementPos.popupHeight : this.popupContainer.offsetHeight;
1181
1182	var angleTopOffset = BX.PopupWindow.getOption("angleTopOffset");
1183
1184	var left = this.bindElementPos.left + this.offsetLeft -
1185				(this.isTopOrBottomAngle() ? BX.PopupWindow.getOption("angleLeftOffset") : 0);
1186
1187	if (
1188		!this.bindOptions.forceLeft &&
1189		(left + popupWidth + this.bordersWidth) >= (windowSize.innerWidth + windowScroll.scrollLeft) &&
1190		(windowSize.innerWidth + windowScroll.scrollLeft - popupWidth - this.bordersWidth) > 0)
1191	{
1192		var bindLeft = left;
1193		left = windowSize.innerWidth + windowScroll.scrollLeft - popupWidth - this.bordersWidth;
1194		if (this.isTopOrBottomAngle())
1195		{
1196			this.setAngle({ offset : bindLeft - left + this.angle.defaultOffset});
1197		}
1198	}
1199	else if (this.isTopOrBottomAngle())
1200	{
1201		this.setAngle({ offset : this.angle.defaultOffset + (left < 0 ? left : 0) });
1202	}
1203
1204	if (left < 0)
1205	{
1206		left = 0;
1207	}
1208
1209	var top = 0;
1210
1211	if (this.bindOptions.position && this.bindOptions.position === "top")
1212	{
1213
1214		top = this.bindElementPos.top - popupHeight - this.offsetTop - (this.isBottomAngle() ? angleTopOffset : 0);
1215		if (top < 0 || (!this.bindOptions.forceTop && top < windowScroll.scrollTop))
1216		{
1217			top = this.bindElementPos.bottom + this.offsetTop;
1218			if (this.angle !== null)
1219			{
1220				top += angleTopOffset;
1221				this.setAngle({ position: "top"});
1222			}
1223		}
1224		else if (this.isTopAngle())
1225		{
1226			top = top - angleTopOffset + BX.PopupWindow.getOption("positionTopXOffset");
1227			this.setAngle({ position: "bottom"});
1228		}
1229		else
1230		{
1231			top += BX.PopupWindow.getOption("positionTopXOffset");
1232		}
1233	}
1234	else
1235	{
1236
1237		top = this.bindElementPos.bottom + this.offsetTop + this.getAngleHeight();
1238
1239		if (
1240			!this.bindOptions.forceTop &&
1241			(top + popupHeight) >
1241 (windowSize.innerHeight + windowScroll.scrollTop) &&
1242			(this.bindElementPos.top - popupHeight - this.getAngleHeight()) >= 0) //Can we place the PopupWindow above the bindElement?
1243		{
1244			//The PopupWindow doesn't place below the bindElement. We should place it above.
1245			top = this.bindElementPos.top - popupHeight;
1246
1247			if (this.isTopOrBottomAngle())
1248			{
1249				top -= angleTopOffset;
1250				this.setAngle({ position: "bottom"});
1251			}
1252
1253			top += BX.PopupWindow.getOption("positionTopXOffset");
1254
1255		}
1256		else if (this.isBottomAngle())
1257		{
1258			top += angleTopOffset;
1259			this.setAngle({ position: "top"});
1260		}
1261	}
1262
1263	if (!this.parentPopup && top < 0)
1264	{
1265		top = 0;
1266	}
1267
1268	BX.adjust(this.popupContainer, { style: {
1269		top: top + "px",
1270		left: left + "px",
1271		zIndex: this.getZindex()
1272	}});
1273
1274	this.adjustOverlayZindex();
1275};
1276
1277BX.PopupWindow.prototype._onResizeWindow = function(event)
1278{
1279	if (this.isShown())
1280	{
1281		this.adjustPosition();
1282		if (this.overlay !== null)
1283		{
1284			this.resizeOverlay();
1285		}
1286	}
1287};
1288
1289BX.PopupWindow.prototype.move = function(offsetX, offsetY, pageX, pageY)
1290{
1291	var left = parseInt(this.popupContainer.style.left) + offsetX;
1292	var top = parseInt(this.popupContainer.style.top) + offsetY;
1293
1294	if (typeof(this.params.draggable) === "object" && this.params.draggable.restrict)
1295	{
1296		//Left side
1297		if (!this.parentPopup && left < 0)
1298		{
1299			left = 0;
1300		}
1301
1302		//Right side
1303		var scrollSize = BX.GetWindowScrollSize();
1304		var floatWidth = this.popupContainer.offsetWidth;
1305		var floatHeight = this.popupContainer.offsetHeight;
1306
1307		if (left > (scrollSize.scrollWidth - floatWidth))
1308		{
1309			left = scrollSize.scrollWidth - floatWidth;
1310		}
1311
1312		if (top > (scrollSize.scrollHeight - floatHeight))
1313		{
1314			top = scrollSize.scrollHeight - floatHeight;
1315		}
1316
1317		//Top side
1318		if (!this.parentPopup && top < 0)
1319		{
1320			top = 0;
1321		}
1322	}
1323
1324	this.popupContainer.style.left = left + "px";
1325	this.popupContainer.style.top = top + "px";
1326};
1327
1328BX.PopupWindow.prototype._startDrag = function(event, options)
1329{
1330	event = event || window.event;
1331	BX.fixEventPageXY(event);
1332
1333	options = options || {};
1334	if (BX.type.isNotEmptyString(options.cursor))
1335	{
1336		this.dragOptions.cursor = options.cursor;
1337	}
1338
1339	if (BX.type.isNotEmptyString(options.eventName))
1340	{
1341		this.dragOptions.eventName = options.eventName;
1342	}
1343
1344	if (BX.type.isFunction(options.callback))
1345	{
1346		this.dragOptions.callback = options.callback;
1347	}
1348
1349	this.dragPageX = event.pageX;
1350	this.dragPageY = event.pageY;
1351	this.dragged = false;
1352
1353	BX.bind(document, "mousemove", BX.proxy(this._moveDrag, this));
1354	BX.bind(document, "mouseup", BX.proxy(this._stopDrag, this));
1355
1356	if (document.body.setCapture)
1357	{
1358		document.body.setCapture();
1359	}
1360
1361	document.body.ondrag = BX.False;
1362	document.body.onselectstart = BX.False;
1363	document.body.style.cursor = this.dragOptions.cursor;
1364	document.body.style.MozUserSelect = "none";
1365	this.popupContainer.style.MozUserSelect = "none";
1366
1367	return BX.PreventDefault(event);
1368};
1369
1370BX.PopupWindow.prototype._moveDrag = function(event)
1371{
1372	event = event || window.event;
1373	BX.fixEventPageXY(event);
1374
1375	if (this.dragPageX === event.pageX && this.dragPageY === event.pageY)
1376	{
1377		return;
1378	}
1379
1380	this.dragOptions.callback(
1381		event.pageX - this.dragPageX,
1382		event.pageY - this.dragPageY,
1383		event.pageX,
1384		event.pageY
1385	);
1386
1387	this.dragPageX = event.pageX;
1388	this.dragPageY = event.pageY;
1389
1390	if (!this.dragged)
1391	{
1392		BX.onCustomEvent(this, "onPopup" + this.dragOptions.eventName + "Start", [this]);
1393		this.dragged = true;
1394	}
1395
1396	BX.onCustomEvent(this, "onPopup" + this.dragOptions.eventName, [this]);
1397};
1398
1399BX.PopupWindow.prototype._stopDrag = function(event)
1400{
1401	if(document.body.releaseCapture)
1402	{
1403		document.body.releaseCapture();
1404	}
1405
1406	BX.unbind(document, "mousemove", BX.proxy(this._moveDrag, this));
1407	BX.unbind(document, "mouseup", BX.proxy(this._stopDrag, this));
1408
1409	//document.onmousedown = null;
1410	document.body.ondrag = null;
1411	document.body.onselectstart = null;
1412	document.body.style.cursor = "";
1413	document.body.style.MozUserSelect = "";
1414	this.popupContainer.style.MozUserSelect = "";
1415
1416	BX.onCustomEvent(this, "onPopup" + this.dragOptions.eventName + "End", [this]);
1417	this.dragged = false;
1418
1419	return BX.PreventDefault(event);
1420};
1421
1422BX.PopupWindow.options = {};
1423BX.PopupWindow.defaultOptions = {
1424
1425	angleLeftOffset : 40, /*left offset for popup about target */
1426
1427	positionTopXOffset : -11, /* when popup position is 'top' offset distance between popup body and target node */
1428
1429	angleTopOffset : 10,    /* offset distance between popup body and target node if use angle, sum with positionTopXOffset  */
1430
1431	popupZindex : 1000,
1432	popupOverlayZindex : 1100,
1433
1434	angleMinLeft : 10,
1435	angleMaxLeft : 10,
1436
1437	angleMinRight : 10,
1438	angleMaxRight : 10,
1439
1440	angleMinBottom : 23, /**/
1441	angleMaxBottom : 25,
1442
1443	angleMinTop : 23,
1444	angleMaxTop : 25,
1445
1446	offsetLeft : 0,
1447	offsetTop: 0
1448};
1449
1450BX.PopupWindow.setOptions = function(options)
1451{
1452	if (!options || typeof(options) !== "object")
1453	{
1454		return;
1455	}
1456
1457	for (var option in options)
1458	{
1459		BX.PopupWindow.options[option] = options[option];
1460	}
1461};
1462
1463BX.PopupWindow.getOption = function(option, defaultValue)
1464{
1465	if (typeof(BX.PopupWindow.options[option]) !== "undefined")
1466	{
1467		return BX.PopupWindow.options[option];
1468	}
1469	else if (typeof(defaultValue) !== "undefined")
1470	{
1471		return defaultValue;
1472	}
1473	else
1474	{
1475		return BX.PopupWindow.defaultOptions[option];
1476	}
1477};
1478
1479/**
1480 *
1481 * @param {object} params
1482 * @param {string} [params.text]
1483 * @param {string} [params.id]
1484 * @param {string} [params.className]
1485 * @param {object} [params.events]
1486 * @constructor
1487 */
1488BX.PopupWindowButton = function(params)
1489{
1490	this.popupWindow = null;
1491
1492	this.params = params || {};
1493
1494	this.text = this.params.text || "";
1495	this.id = this.params.id || "";
1496	this.className = this.params.className || "";
1497	this.events = this.params.events || {};
1498
1499	this.contextEvents = {};
1500	for (var eventName in this.events)
1501	{
1502		this.contextEvents[eventName] = BX.proxy(this.events[eventName], this);
1503	}
1504
1505	this.buttonNode = BX.create(
1506		"span",
1507		{
1508			props : { className : "popup-window-button" + (this.className.length > 0 ? " " + this.className : ""), id : this.id },
1509			events : this.contextEvents,
1510			text : this.text
1511		}
1512	);
1513};
1514
1515BX.PopupWindowButton.prototype.render = function()
1516{
1517	return this.buttonNode;
1518};
1519
1520BX.PopupWindowButton.prototype.getId = function()
1521{
1522	return this.id;
1523};
1524
1525BX.PopupWindowButton.prototype.getName = function()
1526{
1527	return this.name;
1528};
1529
1530/**
1531 *
1532 * @returns {Element}
1533 */
1534BX.PopupWindowButton.prototype.getContainer = function()
1535{
1536	return this.buttonNode;
1537};
1538
1539BX.PopupWindowButton.prototype.setName = function(name)
1540{
1541	this.text = name || "";
1542	if (this.buttonNode)
1543	{
1544		BX.cleanNode(this.buttonNode);
1545		BX.adjust(this.buttonNode, { text : this.text} );
1546	}
1547};
1548
1549BX.PopupWindowButton.prototype.setClassName = function(className)
1550{
1551	if (this.buttonNode)
1552	{
1553		if (BX.type.isString(this.className) && (this.className !== ""))
1554		{
1555			BX.removeClass(this.buttonNode, this.className);
1556		}
1557
1558		BX.addClass(this.buttonNode, className)
1559	}
1560
1561	this.className = className;
1562};
1563
1564BX.PopupWindowButton.prototype.addClassName = function(className)
1565{
1566	if (this.buttonNode)
1567	{
1568		BX.addClass(this.buttonNode, className);
1569		this.className = this.buttonNode.className;
1570	}
1571};
1572
1573BX.PopupWindowButton.prototype.removeClassName = function(className)
1574{
1575	if (this.buttonNode)
1576	{
1577		BX.removeClass(this.buttonNode, className);
1578		this.className = this.buttonNode.className;
1579	}
1580};
1581
1582BX.PopupWindowButtonLink = function(params)
1583{
1584	BX.PopupWindowButtonLink.superclass.constructor.apply(this, arguments);
1585
1586	this.buttonNode = BX.create(
1587		"span",
1588		{
1589			props : { className : "popup-window-button popup-window-button-link" + (this.className.length > 0 ? " " + this.className : ""), id : this.id },
1590			text : this.text,
1591			events : this.contextEvents
1592		}
1593	);
1594
1595};
1596
1597BX.extend(BX.PopupWindowButtonLink, BX.PopupWindowButton);
1598
1599BX.PopupWindowCustomButton = function(params)
1600{
1601	BX.PopupWindowCustomButton.superclass.constructor.apply(this, arguments);
1602
1603	this.buttonNode = BX.create(
1604		"span",
1605		{
1606			props : { className :  (this.className.length > 0 ? " " + this.className : ""), id : this.id },
1607			events : this.contextEvents,
1608			text : this.text
1609		}
1610	);
1611};
1612
1613BX.extend(BX.PopupWindowCustomButton, BX.PopupWindowButton);
1614
1615BX.PopupMenu = {
1616
1617	Data : {},
1618	currentItem : null,
1619
1620	show : function(id, bindElement, menuItems, params)
1621	{
1622		if (this.currentItem !== null)
1623		{
1624			this.currentItem.popupWindow.close();
1625		}
1626
1627		this.currentItem = this.create(id, bindElement, menuItems, params);
1628		this.currentItem.popupWindow.show();
1629	},
1630
1631	create : function(id, bindElement, menuItems, params)
1632	{
1633		if (!this.Data[id])
1634		{
1635			this.Data[id] = new BX.PopupMenuWindow(id, bindElement, menuItems, params);
1636			BX.addCustomEvent(this.Data[id], 'onPopupMenuDestroy', this.onPopupDestroy.bind(this));
1637		}
1638		return this.Data[id];
1639	},
1640
1641	getCurrentMenu : function()
1642	{
1643		return this.currentItem;
1644	},
1645
1646	getMenuById : function(id)
1647	{
1648		return this.Data[id] ? this.Data[id] : null;
1649	},
1650
1651	onPopupDestroy: function(popupMenuWindow)
1652	{
1653		this.destroy(popupMenuWindow.id);
1654	},
1655
1656	destroy : function(id)
1657	{
1658		var menu = this.getMenuById(id);
1659		if (menu)
1660		{
1661			if (this.currentItem === menu)
1662			{
1663				this.currentItem = null;
1664			}
1665			menu.popupWindow.destroy();
1666			delete this.Data[id];
1667		}
1668	}
1669};
1670
1671BX.PopupMenuWindow = function(id, bindElement, menuItems, params)
1672{
1673	this.id = id;
1674	this.bindElement = bindElement;
1675
1676	/**
1677	 *
1678	 * @type {BX.PopupMenuItem[]}
1679	 */
1680	this.menuItems = [];
1681	this.itemsContainer = null;
1682	this.params = params && typeof(params) === "object" ? params : {};
1683	this.parentMenuWindow = null;
1684	this.parentMenuItem = null;
1685
1686	if (menuItems && BX.type.isArray(menuItems))
1687	{
1688		for (var i = 0; i < menuItems.length; i++)
1689		{
1690			this.addMenuItemInternal(menuItems[i], null);
1691		}
1692	}
1693
1694	this.layout = {
1695		menuContainer: null,
1696		itemsContainer: null
1697	};
1698
1699	this.popupWindow = this.__createPopup();
1700};
1701
1702BX.PopupMenuWindow.prototype.__createPopup = function()
1703{
1704	var domItems = [];
1705	for (var i = 0; i < this.menuItems.length; i++)
1706	{
1707		var item = this.menuItems[i];
1708		var itemLayout = item.getLayout();
1709		domItems.push(itemLayout.item);
1710	}
1711
1712	var popupWindow = new BX.PopupWindow("menu-popup-" + this.id, this.bindElement, {
1713		closeByEsc: typeof(this.params.closeByEsc) !== "undefined" ? this.params.closeByEsc: false,
1714		bindOptions: typeof(this.params.bindOptions) === "object" ? this.params.bindOptions : {},
1715		angle: typeof(this.params.angle) !== "undefined" ? this.params.angle : false,
1716		zIndex: this.params.zIndex ? this.params.zIndex : 0,
1717		overlay: typeof(this.params.overlay) === "object" ? this.params.overlay : null,
1718		autoHide: typeof(this.params.autoHide) !== "undefined" ? this.params.autoHide : true,
1719		offsetTop: this.params.offsetTop ? this.params.offsetTop : 1,
1720		offsetLeft: this.params.offsetLeft ? this.params.offsetLeft : 0,
1721		className: BX.type.isNotEmptyString(this.params.className) ? this.params.className : "",
1722		noAllPaddings: true,
1723		content : (this.layout.menuContainer = BX.create("div", {
1724			props : {
1725				className : "menu-popup"
1726			},
1727			children: [
1728				(this.layout.itemsContainer = this.itemsContainer = BX.create("div", {
1729					props : {
1730						className : "menu-popup-items"
1731					},
1732					children: domItems
1733				}))
1734			]
1735		})),
1736		events: {
1737			onPopupClose: this.onMenuWindowClose.bind(this),
1738			onPopupDestroy: this.onMenuWindowDestroy.bind(this)
1739		}
1740	});
1741
1742	if (this.params && this.params.events)
1743	{
1744		for (var eventName in this.params.events)
1745		{
1746			if (this.params.events.hasOwnProperty(eventName))
1747			{
1748				BX.addCustomEvent(popupWindow, eventName, this.params.events[eventName]);
1749			}
1750		}
1751	}
1752
1753	return popupWindow;
1754};
1755
1756/**
1757 *
1758 * @returns {BX.PopupWindow}
1759 */
1760BX.PopupMenuWindow.prototype.getPopupWindow = function()
1761{
1762	return this.popupWindow;
1763};
1764
1765BX.PopupMenuWindow.prototype.show = function()
1766{
1767	this.popupWindow.show();
1768};
1769
1770BX.PopupMenuWindow.prototype.close = function()
1771{
1772	this.popupWindow.close();
1773};
1774
1775BX.PopupMenuWindow.prototype.destroy = function()
1776{
1777	BX.onCustomEvent(this, "onPopupMenuDestroy", [this]);
1778	this.popupWindow.destroy();
1779};
1780
1781BX.PopupMenuWindow.prototype.onMenuWindowClose = function()
1782{
1783	for (var i = 0; i < this.menuItems.length; i++)
1784	{
1785		var item = this.menuItems[i];
1786		item.closeSubMenu();
1787	}
1788};
1789
1790BX.PopupMenuWindow.prototype.onMenuWindowDestroy = function()
1791{
1792	for (var i = 0; i < this.menuItems.length; i++)
1793	{
1794		var item = this.menuItems[i];
1795		item.destroySubMenu();
1796	}
1797};
1798
1799/**
1800 *
1801 * @param {BX.PopupMenuWindow} parentMenuWindow
1802 */
1803BX.PopupMenuWindow.prototype.setParentMenuWindow = function(parentMenuWindow)
1804{
1805	if (parentMenuWindow instanceof BX.PopupMenuWindow)
1806	{
1807		this.parentMenuWindow = parentMenuWindow;
1808	}
1809};
1810
1811/**
1812 *
1813 * @returns {BX.PopupMenuWindow|null}
1814 */
1815BX.PopupMenuWindow.prototype.getParentMenuWindow = function()
1816{
1817	return this.parentMenuWindow;
1818};
1819
1820/**
1821 *
1822 * @param {BX.PopupMenuItem} parentMenuItem
1823 */
1824BX.PopupMenuWindow.prototype.setParentMenuItem = function(parentMenuItem)
1825{
1826	if (parentMenuItem instanceof BX.PopupMenuItem)
1827	{
1828		this.parentMenuItem = parentMenuItem;
1829	}
1830};
1831
1832/**
1833 *
1834 * @returns {BX.PopupMenuItem}
1835 */
1836BX.PopupMenuWindow.prototype.getParentMenuItem = function()
1837{
1838	return this.parentMenuItem;
1839};
1840
1841/**
1842 *
1843 * @param menuItemJson
1844 * @param targetItemId
1845 * @returns {BX.PopupMenuItem}
1846 */
1847BX.PopupMenuWindow.prototype.addMenuItem = function(menuItemJson, targetItemId)
1848{
1849	var menuItem = this.addMenuItemInternal(menuItemJson, targetItemId);
1850	if (!menuItem)
1851	{
1852		return null;
1853	}
1854
1855	var itemLayout = menuItem.getLayout();
1856	var targetItem = this.getMenuItem(targetItemId);
1857	if (targetItem !== null)
1858	{
1859		var targetLayout = targetItem.getLayout();
1860		this.itemsContainer.insertBefore(itemLayout.item, targetLayout.item);
1861	}
1862	else
1863	{
1864		this.itemsContainer.appendChild(itemLayout.item);
1865	}
1866
1867	return menuItem;
1868};
1869
1870/**
1871 *
1872 * @param menuItemJson
1873 * @param targetItemId
1874 * @returns {BX.PopupMenuItem}
1875 */
1876BX.PopupMenuWindow.prototype.addMenuItemInternal = function(menuItemJson, targetItemId)
1877{
1878	if (
1879		!menuItemJson ||
1880		(!menuItemJson.delimiter && !BX.type.isNotEmptyString(menuItemJson.text)) ||
1881		(menuItemJson.id && this.getMenuItem(menuItemJson.id) !== null)
1882	)
1883	{
1884		return null;
1885	}
1886
1887	if (BX.type.isNumber(this.params.menuShowDelay))
1888	{
1889		menuItemJson.menuShowDelay = this.params.menuShowDelay;
1890	}
1891
1892	var menuItem = new BX.PopupMenuItem(menuItemJson);
1893	menuItem.setMenuWindow(this);
1894
1895	var position = this.getMenuItemPosition(targetItemId);
1896	if (position >= 0)
1897	{
1898		this.menuItems = BX.util.insertIntoArray(this.menuItems, position, menuItem);
1899	}
1900	else
1901	{
1902		this.menuItems.push(menuItem);
1903	}
1904
1905	return menuItem;
1906};
1907
1908BX.PopupMenuWindow.prototype.removeMenuItem = function(itemId)
1909{
1910	var item = this.getMenuItem(itemId);
1911	if (!item)
1912	{
1913		return;
1914	}
1915
1916	for (var position = 0; position < this.menuItems.length; position++)
1917	{
1918		if (this.menuItems[position] === item)
1919		{
1920			item.destroySubMenu();
1921			this.menuItems = BX.util.deleteFromArray(this.menuItems, position);
1922			break;
1923		}
1924	}
1925
1926	if (!this.menuItems.length)
1927	{
1928		var menuWindow = item.getMenuWindow();
1929		if (menuWindow)
1930		{
1931			var parentMenuItem = menuWindow.getParentMenuItem();
1932			if (parentMenuItem)
1933			{
1934				parentMenuItem.destroySubMenu();
1935			}
1936			else
1937			{
1938				menuWindow.destroy();
1939			}
1940		}
1941	}
1942
1943	item.layout.item.parentNode.removeChild(item.layout.item);
1944	item.layout = {
1945		item: null,
1946		text: null
1947	};
1948};
1949
1950/**
1951 *
1952 * @param itemId
1953 * @returns {BX.PopupMenuItem}
1954 */
1955BX.PopupMenuWindow.prototype.getMenuItem = function(itemId)
1956{
1957	for (var i = 0; i < this.menuItems.length; i++)
1958	{
1959		if (this.menuItems[i].id && this.menuItems[i].id === itemId)
1960		{
1961			return this.menuItems[i];
1962		}
1963	}
1964
1965	return null;
1966};
1967
1968/**
1969 *
1970 * @returns {BX.PopupMenuItem[]}
1971 */
1972BX.PopupMenuWindow.prototype.getMenuItems = function()
1973{
1974	return this.menuItems;
1975};
1976
1977/**
1978 *
1979 * @param itemId
1980 * @returns {number}
1981 */
1982BX.PopupMenuWindow.prototype.getMenuItemPosition = function(itemId)
1983{
1984	if (itemId)
1985	{
1986		for (var i = 0; i < this.menuItems.length; i++)
1987		{
1988			if (this.menuItems[i].id && this.menuItems[i].id === itemId)
1989			{
1990				return i;
1991			}
1992		}
1993	}
1994
1995	return -1;
1996};
1997
1998/**
1999 *
2000 * @param {Object} options
2001 * @param {string} [options.id]
2002 * @param {string} [options.text]
2003 * @param {string} [options.title = ""]
2004 * @param {string} [options.href = null]
2005 * @param {string} [options.target = null]
2006 * @param {string} [options.className = null]
2007 * @param {boolean} [options.delimiter = false]
2008 * @param {number} [options.menuShowDelay = 300]
2009 * @param {number} [options.subMenuOffsetX = 4]
2010 * @param {object} [options.events]
2011 * @param {object} [options.dataset]
2012 * @param {function|string} [options.onclick = null]
2013 * @param {array[]} [options.items = []]
2014 * @constructor
2015 */
2016BX.PopupMenuItem = function(options)
2017{
2018	options = options || {};
2019	this.options = options;
2020
2021	this.id = options.id || BX.util.getRandomString().toLowerCase();
2022	this.text = BX.type.isNotEmptyString(options.text) ? options.text : "";
2023	this.title = BX.type.isNotEmptyString(options.title) ? options.title : "";
2024	this.delimiter = options.delimiter === true;
2025	this.href = BX.type.isNotEmptyString(options.href) ? options.href : null;
2026	this.target = BX.type.isNotEmptyString(options.target) ? options.target : null;
2027	this.dataset = BX.type.isPlainObject(options.dataset) ? options.dataset : null;
2028	this.className = BX.type.isNotEmptyString(options.className) ? options.className : null;
2029	this.menuShowDelay = BX.type.isNumber(options.menuShowDelay) ? options.menuShowDelay : 300;
2030	this.subMenuOffsetX = BX.type.isNumber(options.subMenuOffsetX) ? options.subMenuOffsetX : 4;
2031	this._items = BX.type.isArray(options.items) ? options.items : [];
2032
2033	/**
2034	 *
2035	 * @type {function|string}
2036	 */
2037	this.onclick =
2038		BX.type.isNotEmptyString(options.onclick) || BX.type.isFunction(options.onclick)
2039			? options.onclick
2040			: null
2041	;
2042
2043	if (BX.type.isPlainObject(options.events))
2044	{
2045		for (var eventName in options.events)
2046		{
2047			BX.addCustomEvent(this, eventName, options.events[eventName]);
2048		}
2049	}
2050
2051	/**
2052	 *
2053	 * @type {BX.PopupMenuWindow}
2054	 */
2055	this.menuWindow = null;
2056
2057	/**
2058	 *
2059	 * @type {BX.PopupMenuWindow}
2060	 */
2061	this.subMenuWindow = null;
2062
2063	this.layout = {
2064		item: null,
2065		text: null
2066	};
2067
2068	this.getLayout(); //compatibility
2069
2070	//compatibility
2071	//now use this.options
2072	this.events = {};
2073	this.items = [];
2074	for (var property in options)
2075	{
2076		if (options.hasOwnProperty(property) && typeof(this[property]) === "undefined")
2077		{
2078			this[property] = options[property];
2079		}
2080	}
2081};
2082
2083BX.PopupMenuItem.prototype = {
2084
2085	getLayout: function()
2086	{
2087		if (this.layout.item)
2088		{
2089			return this.layout;
2090		}
2091
2092		if (this.delimiter)
2093		{
2094			this.layout.item = BX.create("span", {
2095				props: {
2096					className: "popup-window-delimiter"
2097				}
2098			});
2099		}
2100		else
2101		{
2102			this.layout.item = BX.create(this.href ? "a" : "span", {
2103				props : {
2104					className: [
2105						"menu-popup-item",
2106						(this.className ? this.className : "menu-popup-no-icon"),
2107						(this.hasSubMenu() ? "menu-popup-item-submenu" : "")
2108					].join(" ")
2109				},
2110
2111				attrs : {
2112					title : this.title,
2113					onclick: BX.type.isString(this.onclick) ? this.onclick : "", // compatibility
2114					target : this.target ? this.target : ""
2115				},
2116
2117				dataset: this.dataset,
2118
2119				events :
2120					BX.type.isFunction(this.onclick)
2121						? { click : BX.delegate(this.onItemClick, this) }
2122						: null
2123				,
2124
2125				children : [
2126					BX.create("span", { props : { className: "menu-popup-item-icon"} }),
2127					(this.layout.text = BX.create("span", {
2128						props : {
2129							className: "menu-popup-item-text"
2130						},
2131						html : this.text
2132					}))
2133				]
2134			});
2135
2136			if (this.href)
2137			{
2138				this.layout.item.href = this.href;
2139			}
2140
2141			BX.bind(this.layout.item, "mouseenter", this.onItemMouseEnter.bind(this));
2142			BX.bind(this.layout.item, "mouseleave", this.onItemMouseLeave.bind(this));
2143		}
2144
2145		return this.layout;
2146	},
2147
2148	onItemClick: function(event)
2149	{
2150		this.onclick.call(this.menuWindow, event, this); //compatibility
2151	},
2152
2153	onItemMouseEnter: function(event)
2154	{
2155		BX.onCustomEvent(this, "onMouseEnter");
2156
2157		if (this.subMenuTimeout)
2158		{
2159			clearTimeout(this.subMenuTimeout);
2160		}
2161
2162		if (this.hasSubMenu())
2163		{
2164			this.subMenuTimeout = setTimeout(function() {
2165				this.showSubMenu();
2166			}.bind(this), this.menuShowDelay);
2167		}
2168		else
2169		{
2170			this.subMenuTimeout = setTimeout(function() {
2171				this.closeSiblings();
2172			}.bind(this), this.menuShowDelay);
2173		}
2174	},
2175
2176	onItemMouseLeave: function(event)
2177	{
2178		BX.onCustomEvent(this, "onMouseLeave");
2179
2180		if (this.subMenuTimeout)
2181		{
2182			clearTimeout(this.subMenuTimeout);
2183		}
2184	},
2185
2186	hasSubMenu: function()
2187	{
2188		return this.subMenuWindow !== null || this._items.length;
2189	},
2190
2191	showSubMenu: function()
2192	{
2193		this.addSubMenu(this._items);
2194
2195		if (this.subMenuWindow)
2196		{
2197			BX.addClass(this.layout.item, "menu-popup-item-open");
2198
2199			this.closeSiblings();
2200			this.closeChildren();
2201
2202			var popupWindow = this.subMenuWindow.getPopupWindow();
2203			if (!popupWindow.isShown())
2204			{
2205				BX.onCustomEvent(this, "onSubMenuShow");
2206				popupWindow.show();
2207			}
2208
2209
2210			this.adjustSubMenu();
2211		}
2212	},
2213
2214	addSubMenu: function(items)
2215	{
2216		if (this.subMenuWindow !== null || !BX.type.isArray(items) || !items.length)
2217		{
2218			return;
2219		}
2220
2221		this.subMenuWindow = new BX.PopupMenuWindow(
2222			"popup-submenu-" + this.id,
2223			null,
2224			items,
2225			{
2226				autoHide: false,
2227				menuShowDelay: this.menuShowDelay,
2228				bindOptions: {
2229					forceTop: true,
2230					forceLeft: true,
2231					forceBindPosition: true
2232				}
2233			}
2234		);
2235
2236		this.subMenuWindow.setParentMenuWindow(this.menuWindow);
2237		this.subMenuWindow.setParentMenuItem(this);
2238
2239		BX.addClass(this.layout.item, "menu-popup-item-submenu");
2240	},
2241
2242	closeSubMenu: function()
2243	{
2244		if (this.subMenuWindow)
2245		{
2246
2247			BX.removeClass(this.layout.item, "menu-popup-item-open");
2248
2249			this.closeChildren();
2250
2251			var popupWindow = this.subMenuWindow.getPopupWindow();
2252			if (popupWindow.isShown())
2253			{
2254				BX.onCustomEvent(this, "onSubMenuClose");
2255				popupWindow.close();
2256			}
2257
2258			this.subMenuWindow.close();
2259		}
2260	},
2261
2262	closeSiblings: function()
2263	{
2264		var siblings = this.menuWindow.getMenuItems();
2265		for (var i = 0; i < siblings.length; i++)
2266		{
2267			if (siblings[i] !== this)
2268			{
2269				siblings[i].closeSubMenu();
2270			}
2271		}
2272	},
2273
2274	closeChildren: function()
2275	{
2276		if (this.subMenuWindow)
2277		{
2278			var children = this.subMenuWindow.getMenuItems();
2279			for (var i = 0; i < children.length; i++)
2280			{
2281				children[i].closeSubMenu();
2282			}
2283		}
2284	},
2285
2286	destroySubMenu: function()
2287	{
2288		if (this.subMenuWindow)
2289		{
2290			BX.removeClass(this.layout.item, "menu-popup-item-open menu-popup-item-submenu");
2291			this.destroyChildren();
2292			this.subMenuWindow.destroy();
2293
2294			this.subMenuWindow = null;
2295			this._items = [];
2296		}
2297	},
2298
2299	destroyChildren: function()
2300	{
2301		if (this.subMenuWindow)
2302		{
2303			var children = this.subMenuWindow.getMenuItems();
2304			for (var i = 0; i < children.length; i++)
2305			{
2306				children[i].destroySubMenu();
2307			}
2308		}
2309	},
2310
2311	adjustSubMenu: function()
2312	{
2313		if (!this.subMenuWindow || !this.layout.item)
2314		{
2315			return;
2316		}
2317
2318		var popupWindow = this.subMenuWindow.getPopupWindow();
2319		var itemRect = BX.pos(this.layout.item);
2320
2321		var offsetLeft = itemRect.width + this.subMenuOffsetX;
2322		var anglePosition = "left";
2323
2324		var popupWidth = popupWindow.popupContainer.offsetWidth;
2325		var clientWidth = document.documentElement.clientWidth;
2326		if ((itemRect.left + offsetLeft + popupWidth) > clientWidth)
2327		{
2328			var left = itemRect.left - popupWidth - this.subMenuOffsetX;
2329			if (left > 0)
2330			{
2331				offsetLeft = -popupWidth - this.subMenuOffsetX;
2332				anglePosition = "right";
2333			}
2334		}
2335
2336		popupWindow.setBindElement(this.layout.item);
2337
2338		popupWindow.setOffset({
2339			offsetLeft: offsetLeft,
2340			offsetTop: -(itemRect.height + this.getPopupPadding())
2341		});
2342
2343		popupWindow.setAngle({
2344			"position": anglePosition,
2345			"offset": ((itemRect.height / 2) - this.getPopupPadding())
2346		});
2347
2348		popupWindow.adjustPosition();
2349	},
2350
2351	/**
2352	 *
2353	 * @returns {number}
2354	 */
2355	getPopupPadding: function() {
2356		if (!BX.type.isNumber(this.popupPadding))
2357		{
2358			if (this.subMenuWindow)
2359			{
2360				var menuContainer = this.subMenuWindow.layout.menuContainer;
2361				this.popupPadding = parseInt(BX.style(menuContainer, "paddingTop"), 10);
2362			}
2363			else
2364			{
2365				this.popupPadding = 0;
2366			}
2367		}
2368
2369		return this.popupPadding;
2370	},
2371
2372	/**
2373	 *
2374	 * @returns {BX.PopupMenuWindow|null}
2375	 */
2376	getSubMenu: function()
2377	{
2378		return this.subMenuWindow;
2379	},
2380
2381	getId: function()
2382	{
2383		return this.id;
2384	},
2385
2386	/**
2387	 *
2388	 * @param {BX.PopupMenuWindow} menuWindow
2389	 */
2390	setMenuWindow: function(menuWindow)
2391	{
2392		this.menuWindow = menuWindow;
2393	},
2394
2395	/**
2396	 *
2397	 * @returns {BX.PopupMenuWindow}
2398	 */
2399	getMenuWindow: function()
2400	{
2401		return this.menuWindow;
2402	},
2403
2404	getMenuShowDelay: function()
2405	{
2406		return this.menuShowDelay;
2407	}
2408};
2409
2410// TODO: copypaste/update/enhance CSS and images from calendar to MAIN CORE
2411// this.values = [{ID: 1, NAME : '111', DESCRIPTION: '111', URL: 'href://...'}]
2412
2413window.BXInputPopup = function(params)
2414{
2415	this.id = params.id || 'bx-inp-popup-' + Math.round(Math.random() * 1000000);
2416	this.handler = params.handler || false;
2417	this.values = params.values || false;
2418	this.pInput = params.input;
2419	this.bValues = !!this.values;
2420	this.defaultValue = params.defaultValue || '';
2421	this.openTitle = params.openTitle || '';
2422	this.className = params.className || '';
2423	this.noMRclassName = params.noMRclassName || 'ec-no-rm';
2424	this.emptyClassName = params.noMRclassName || 'ec-label';
2425
2426	var _this = this;
2427	this.curInd = false;
2428
2429	if (this.bValues)
2430	{
2431		this.pInput.onfocus = this.pInput.onclick = function(e)
2432		{
2433			if (this.value == _this.defaultValue)
2434			{
2435				this.value = '';
2436				this.className = _this.className;
2437			}
2438			_this.ShowPopup();
2439			return BX.PreventDefault(e);
2440		};
2441		this.pInput.onblur = function()
2442		{
2443			if (_this.bShowed)
2444				setTimeout(function(){_this.ClosePopup(true);}, 200);
2445			_this.OnChange();
2446		};
2447	}
2448	else
2449	{
2450		this.pInput.className = this.noMRclassName;
2451		this.pInput.onblur = BX.proxy(this.OnChange, this);
2452	}
2453}
2454
2455BXInputPopup.prototype = {
2456ShowPopup: function()
2457{
2458	if (this.bShowed)
2459		return;
2460
2461	var _this = this;
2462	if (!this.oPopup)
2463	{
2464		var
2465			pRow,
2466			pWnd = BX.create("DIV", {props:{className: "bxecpl-loc-popup " + this.className}});
2467
2468		for (var i = 0, l = this.values.length; i < l; i++)
2469		{
2470			pRow = pWnd.appendChild(BX.create("DIV", {
2471				props: {id: 'bxecmr_' + i},
2472				text: this.values[i].NAME,
2473				events: {
2474					mouseover: function(){BX.addClass(this, 'bxecplloc-over');},
2475					mouseout: function(){BX.removeClass(this, 'bxecplloc-over');},
2476					click: function()
2477					{
2478						var ind = this.id.substr('bxecmr_'.length);
2479						_this.pInput.value = _this.values[ind].NAME;
2480						_this.curInd = ind;
2481						_this.OnChange();
2482						_this.ClosePopup(true);
2483					}
2484				}
2485			}));
2486
2487			if (this.values[i].DESCRIPTION)
2488				pRow.title = this.values[i].DESCRIPTION;
2489			if (this.values[i].CLASS_NAME)
2490				BX.addClass(pRow, this.values[i].CLASS_NAME);
2491
2492			if (this.values[i].URL)
2493				pRow.appendChild(BX.create('A', {props: {href: this.values[i].URL, className: 'bxecplloc-view', target: '_blank', title: this.openTitle}}));
2494		}
2495
2496		this.oPopup = new BX.PopupWindow(this.id, this.pInput, {
2497			autoHide : true,
2498			offsetTop : 1,
2499			offsetLeft : 0,
2500			lightShadow : true,
2501			closeByEsc : true,
2502			content : pWnd
2503		});
2504
2505		BX.addCustomEvent(this.oPopup, 'onPopupClose', BX.proxy(this.ClosePopup, this));
2506	}
2507
2508	this.oPopup.show();
2509	this.pInput.select();
2510
2511	this.bShowed = true;
2512	BX.onCustomEvent(this, 'onInputPopupShow', [this]);
2513},
2514
2515ClosePopup: function(bClosePopup)
2516{
2517	this.bShowed = false;
2518
2519	if (this.pInput.value == '')
2520		this.OnChange();
2521
2522	BX.onCustomEvent(this, 'onInputPopupClose', [this]);
2523
2524	if (bClosePopup === true)
2525		this.oPopup.close();
2526},
2527
2528OnChange: function()
2529{
2530	var val = this.pInput.value;
2531	if (this.bValues)
2532	{
2533		if (this.pInput.value == '' || this.pInput.value == this.defaultValue)
2534		{
2535			this.pInput.value = this.defaultValue;
2536			this.pInput.className = this.emptyClassName;
2537			val = '';
2538		}
2539		else
2540		{
2541			this.pInput.className = '';
2542		}
2543	}
2544
2545	if (isNaN(parseInt(this.curInd)) || this.curInd !==false && val != this.values[this.curInd].NAME)
2546		this.curInd = false;
2547	else
2548		this.curInd = parseInt(this.curInd);
2549
2550	BX.onCustomEvent(this, 'onInputPopupChanged', [this, this.curInd, val]);
2551	if (this.handler && typeof this.handler == 'function')
2552		this.handler({ind: this.curInd, value: val});
2553},
2554
2555Set: function(ind, val, bOnChange)
2556{
2557	this.curInd = ind;
2558	if (this.curInd !== false)
2559		this.pInput.value = this.values[this.curInd].NAME;
2560	else
2561		this.pInput.value = val;
2562
2563	if (bOnChange !== false)
2564		this.OnChange();
2565},
2566
2567Get: function(ind)
2568{
2569	var
2570		id = false;
2571	if (typeof ind == 'undefined')
2572		ind = this.curInd;
2573
2574	if (ind !== false && this.values[ind])
2575		id = this.values[ind].ID;
2576	return id;
2577},
2578
2579GetIndex: function(id)
2580{
2581	for (var i = 0, l = this.values.length; i < l; i++)
2582		if (this.values[i].ID == id)
2583			return i;
2584	return false;
2585},
2586
2587Deactivate: function(bDeactivate)
2588{
2589	if (this.pInput.value == '' || this.pInput.value == this.defaultValue)
2590	{
2591		if (bDeactivate)
2592		{
2593			this.pInput.value = '';
2594			this.pInput.className = this.noMRclassName;
2595		}
2596		else if (this.oEC.bUseMR)
2597		{
2598			this.pInput.value = this.defaultValue;
2599			this.pInput.className = this.emptyClassName;
2600		}
2601	}
2602	this.pInput.disabled = bDeactivate;
2603}
2604};
2605
2606/************** utility *************/
2607
2608var _escCallbackIndex = -1,
2609	_escCallback = null;
2610
2611function _checkEscPressed(zIndex, callback)
2612{
2613	if(zIndex === false)
2614	{
2615		if(_escCallback && _escCallback.length > 0)
2616		{
2617			for(var i=0;i<_escCallback.length; i++)
2618			{
2619				_escCallback[i]();
2620			}
2621
2622			_escCallback = null;
2623			_escCallbackIndex = -1;
2624		}
2625	}
2626	else
2627	{
2628		if(_escCallback === null)
2629		{
2630			_escCallback = [];
2631			_escCallbackIndex = -1;
2632			BX.defer(_checkEscPressed)(false);
2633		}
2634
2635		if(zIndex > _escCallbackIndex)
2636		{
2637			_escCallbackIndex = zIndex;
2638			_escCallback = [callback];
2639		}
2640		else if(zIndex == _escCallbackIndex)
2641		{
2642			_escCallback.push(callback)
2643		}
2644	}
2645}
2646
2647
2648})(window);
2649

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.