text: /**
   * Bitrix HTML Editor 3.0
   * Date: 24.04.13
   * Time: 4:23
   *
   * Taskbarmanager
   * Taskbar
   * Context Menu
   * Search/Replace
   */
  ;(function() {
  	function TaskbarManager(editor, init)
  	{
  		this.editor = editor;
  		this.bShown = false;
  		this.closedWidth = 20;
  		this.MIN_CLOSED_WIDTH = 120;
  		this.width = this.editor.config.taskbarWidth || 250;
  		this.taskbars = {};
  		this.freezeOnclickHandler = false;
  
  		if (init)
  		{
  			this.Init();
  		}
  	}
  
  	TaskbarManager.prototype = {
  		Init: function()
  		{
  			this.pCont = this.editor.dom.taskbarCont;
  			this.pCont.setAttribute('data-bx-type', 'taskbarmanager');
  
  			this.pResizer = BX('bx-html-editor-tskbr-res-' + this.editor.id);
  			this.pResizer.setAttribute('data-bx-type', 'taskbarflip');
  			this.pTopCont = BX('bx-html-editor-tskbr-top-' + this.editor.id);
  
  			BX.bind(this.pResizer, 'mousedown', BX.proxy(this.StartResize, this));
  			BX.bind(this.pCont, 'click', BX.proxy(this.OnClick, this));
  
  			// Search
  			this.pSearchCont = BX('bxhed-tskbr-search-cnt-' + this.editor.id);
  			this.pSearchAli = BX('bxhed-tskbr-search-ali-' + this.editor.id);
  			this.pSearchInput = BX('bxhed-tskbr-search-inp-' + this.editor.id);
  			this.pSearchNothingNotice = BX('bxhed-tskbr-search-nothing-' + this.editor.id);
  			BX.bind(this.pSearchInput, 'keyup', BX.proxy(this.TaskbarSearch, this));
  		},
  
  		OnClick: function(e)
  		{
  			if (!e)
  				e = window.event;
  
  			if (this.freezeOnclickHandler)
  				return;
  
  			var
  				_this = this,
  				target = e.target || e.srcElement,
  				type = (target && target.getAttribute) ? target.getAttribute('data-bx-type') : null;
  
  			if (!type)
  			{
  				target = BX.findParent(target, function(node)
  				{
  					return node == _this.pCont || (node.getAttribute && node.getAttribute('data-bx-type'));
  				}, this.pCont);
  				type = (target && target.getAttribute) ? target.getAttribute('data-bx-type') : null;
  			}
  
  			if (type == 'taskbarflip' || (!this.bShown && (type == 'taskbarmanager' || !type)))
  			{
  				if (this.bShown)
  				{
  					this.Hide();
  				}
  				else
  				{
  					this.Show();
  				}
  			}
  			else if(type == 'taskbargroup_title')
  			{
  				BX.onCustomEvent(this, 'taskbargroupTitleClick', [target]);
  			}
  			else if(type == 'taskbarelement')
  			{
  				BX.onCustomEvent(this, 'taskbarelementClick', [target]);
  			}
  			else if(type == 'taskbar_title_but')
  			{
  				BX.onCustomEvent(this, 'taskbarTitleClick', [target]);
  			}
  			else if(type == 'taskbar_top_menu')
  			{
  				BX.onCustomEvent(this, 'taskbarMenuClick', [target]);
  			}
  			else if(type == 'taskbar_search_cancel')
  			{
  				this.pSearchInput.value = '';
  				this.TaskbarSearch();
  			}
  		},
  
  		Show: function(saveValue)
  		{
  			if (!this.bShown)
  			{
  				this.bShown = true;
  				this.pCont.className = 'bxhtmled-taskbar-cnt bxhtmled-taskbar-shown';
  			}
  			this.pCont.style.width = this.GetWidth(true) + 'px';
  			this.editor.ResizeSceleton();
  
  			if (saveValue !== false)
  			{
  				this.editor.SaveOption('taskbar_shown', 1);
  			}
  		},
  
  		Hide: function(saveValue)
  		{
  			if (this.bShown)
  			{
  				this.bShown = false;
  				this.pCont.className = 'bxhtmled-taskbar-cnt bxhtmled-taskbar-hidden';
  			}
  			this.pCont.style.width = this.GetWidth() + 'px';
  			this.editor.ResizeSceleton();
  
  			if (saveValue !== false)
  			{
  				this.editor.SaveOption('taskbar_shown', 0);
  			}
  		},
  
  		GetWidth: function(bCheck, maxWidth)
  		{
  			var width;
  			if (this.bShown)
  			{
  				width = bCheck ? Math.max(this.width, this.closedWidth + this.MIN_CLOSED_WIDTH) : this.width;
  				if(maxWidth && width > maxWidth)
  				{
  					width = this.width = Math.round(maxWidth);
  				}
  			}
  			else
  			{
  				width = this.closedWidth;
  			}
  
  			return width;
  		},
  
  		AddTaskbar: function(oTaskbar)
  		{
  			this.taskbars[oTaskbar.id] = oTaskbar;
  			this.pCont.appendChild(oTaskbar.GetCont());
  			this.pTopCont.appendChild(oTaskbar.GetTitleCont());
  		},
  
  		ShowTaskbar: function(taskbarId)
  		{
  			this.pSearchInput.value = '';
  			for(var id in this.taskbars)
  			{
  				if (this.taskbars.hasOwnProperty(id))
  				{
  					if (id == taskbarId)
  					{
  						this.taskbars[id].Activate();
  						this.pSearchInput.placeholder = this.taskbars[id].searchPlaceholder;
  					}
  					else
  					{
  						this.taskbars[id].Deactivate();
  					}
  
  					this.activeTaskbarId = taskbarId;
  					this.taskbars[id].ClearSearchResult();
  				}
  			}
  		},
  
  		GetActiveTaskbar: function()
  		{
  			return this.taskbars[this.activeTaskbarId];
  		},
  
  		StartResize: function(e)
  		{
  			if(!e)
  				e = window.event;
  
  			var target = e.target || e.srcElement;
  			if (target.getAttribute('data-bx-tsk-split-but') == 'Y')
  				return true;
  
  			this.freezeOnclickHandler = true;
  
  			var
  				width = this.GetWidth(),
  				overlay = this.editor.dom.resizerOverlay,
  				dX = 0, newWidth,
  				windowScroll = BX.GetWindowScrollPos(),
  				startX = e.clientX + windowScroll.scrollLeft,
  				_this = this;
  
  			overlay.style.display = 'block';
  
  			function moveResizer(e, bFinish)
  			{
  				if(!e)
  					e = window.event;
  
  				var x = e.clientX + windowScroll.scrollLeft;
  
  				if(startX == x)
  					return;
  
  				dX = startX - x;
  				newWidth = width + dX;
  
  				if (bFinish)
  				{
  					_this.width = Math.max(newWidth, _this.closedWidth + _this.MIN_CLOSED_WIDTH);
  					if (isNaN(_this.width))
  					{
  						_this.width = _this.closedWidth + _this.MIN_CLOSED_WIDTH;
  					}
  				}
  				else
  				{
  					_this.width = newWidth;
  				}
  
  				if (newWidth > _this.closedWidth + (bFinish ? 20 : 0))
  				{
  					_this.Show();
  				}
  				else
  				{
  					_this.Hide();
  				}
  			}
  
  			function finishResizing(e)
  			{
  				moveResizer(e, true);
  				BX.unbind(document, 'mousemove', moveResizer);
  				BX.unbind(document, 'mouseup', finishResizing);
  				overlay.style.display = 'none';
  				setTimeout(function(){_this.freezeOnclickHandler = false;}, 10);
  				BX.PreventDefault(e);
  
  				_this.editor.SaveOption('taskbar_width', _this.GetWidth(true));
  			}
  
  			BX.bind(document, 'mousemove', moveResizer);
  			BX.bind(document, 'mouseup', finishResizing);
  		},
  
  		Resize: function(w, h)
  		{
  			var topHeight = parseInt(this.pTopCont.offsetHeight, 10);
  			for(var id in this.taskbars)
  			{
  				if (this.taskbars.hasOwnProperty(id) && this.taskbars[id].pTreeCont)
  				{
  					this.taskbars[id].pTreeCont.style.height = (h - topHeight - 42) + 'px';
  				}
  			}
  
  			this.pSearchCont.style.width = w + 'px';
  			if (!BX.browser.IsDoctype())
  			{
  				this.pSearchAli.style.width = (w - 20) + 'px';
  			}
  
  			var _this = this;
  			if (this.resizeTimeout)
  			{
  				this.resizeTimeout = clearTimeout(this.resizeTimeout);
  			}
  
  			this.resizeTimeout = setTimeout(function()
  			{
  				if (parseInt(_this.pTopCont.offsetHeight, 10) !== topHeight)
  				{
  					_this.Resize(w, h);
  				}
  			}, 100);
  		},
  
  		TaskbarSearch: function(e)
  		{
  			var
  				taskbar = this.GetActiveTaskbar(),
  				value = this.pSearchInput.value;
  
  			if (e && e.keyCode == this.editor.KEY_CODES['escape'])
  			{
  				value = this.pSearchInput.value = '';
  			}
  
  			if (value.length < 2)
  			{
  				taskbar.ClearSearchResult();
  			}
  			else
  			{
  				taskbar.Search(value);
  			}
  		}
  	};
  
  
  	/*
  	 *
  	 *
  	 * */
  	function Taskbar(editor)
  	{
  		this.editor = editor;
  		this.manager = this.editor.taskbarManager;
  		this.searchIndex = [];
  		this._searchResult = [];
  		this._searchResultSect = [];
  
  		BX.addCustomEvent(this.manager, 'taskbargroupTitleClick', BX.proxy(this.OnGroupTitleClick, this));
  		BX.addCustomEvent(this.manager, 'taskbarelementClick', BX.proxy(this.OnElementClick, this));
  		BX.addCustomEvent(this.manager, 'taskbarTitleClick', BX.proxy(this.OnTitleClick, this));
  		BX.addCustomEvent(this.manager, 'taskbarMenuClick', BX.proxy(this.OnMenuClick, this));
  	}
  
  	Taskbar.prototype = {
  		GetCont: function()
  		{
  			return this.pTreeCont;
  		},
  
  		GetTitleCont: function()
  		{
  			return this.pTitleCont;
  		},
  
  		BuildSceleton: function()
  		{
  			// Build title & menu
  			this.pTitleCont = BX.create("span", {props: {className: "bxhtmled-split-btn"},html: '<span class="bxhtmled-split-btn-l"><span class="bxhtmled-split-btn-bg">' + this.title + '</span></span><span class="bxhtmled-split-btn-r"><span data-bx-type="taskbar_top_menu" data-bx-taskbar="' + this.id + '" class="bxhtmled-split-btn-bg"></span></span>'});
  			this.pTitleCont.setAttribute('data-bx-type', 'taskbar_title_but');
  			this.pTitleCont.setAttribute('data-bx-taskbar', this.id);
  
  			this.pTreeCont = BX.create("DIV", {props: {className: "bxhtmled-taskbar-tree-cont"}});
  			this.pTreeInnerCont = this.pTreeCont.appendChild(BX.create("DIV", {props: {className: "bxhtmled-taskbar-tree-inner-cont"}}));
  		},
  
  		BuildTree: function(sections, elements)
  		{
  			BX.cleanNode(this.pTreeCont);
  			this.treeSectionIndex = {};
  			this.BuildTreeSections(sections);
  			this.BuildTreeElements(elements);
  		},
  
  		BuildTreeSections: function(sections)
  		{
  			this.sections = [];
  			for (var i = 0; i < sections.length; i++)
  			{
  				this.BuildSection(sections[i]);
  			}
  		},
  
  		GetSectionsTreeInfo: function()
  		{
  			return this.sections;
  		},
  
  		BuildSection: function(section)
  		{
  			var
  				parentCont = this.GetSectionContByPath(section.path),
  				pGroup = BX.create("DIV", {props: {className: "bxhtmled-tskbr-sect-outer"}}),
  				pGroupTitle = pGroup.appendChild(BX.create("DIV", {props: {className: "bxhtmled-tskbr-sect"}})),
  				icon = pGroupTitle.appendChild(BX.create("SPAN", {props: {className: "bxhtmled-tskbr-sect-icon"}})),
  				title = pGroupTitle.appendChild(BX.create("SPAN", {props: {className: "bxhtmled-tskbr-sect-title"}, text: section.title || section.name})),
  				childCont = pGroup.appendChild(BX.create("DIV", {props: {className: "bxhtmled-tskb-child"}})),
  				elementsCont = pGroup.appendChild(BX.create("DIV", {props: {className: "bxhtmled-tskb-child-elements"}}));
  
  			var key = section.path == '' ? section.name : section.path + ',' + section.name;
  			var depth = section.path == '' ? 0 : 1; // Todo....
  
  			var sect = {
  				key: key,
  				children: [],
  				section: section
  			}
  
  			this.treeSectionIndex[key] = {
  				icon: icon,
  				outerCont: pGroup,
  				cont: pGroupTitle,
  				childCont: childCont,
  				elementsCont: elementsCont,
  				sect: sect
  			};
  
  			this.GetSectionByPath(section.path).push(sect);
  
  			if (depth > 0)
  			{
  				BX.addClass(pGroupTitle, "bxhtmled-tskbr-sect-" + depth);
  				BX.addClass(icon, "bxhtmled-tskbr-sect-icon-" + depth);
  			}
  
  			pGroupTitle.setAttribute('data-bx-type', 'taskbargroup_title');
  			pGroupTitle.setAttribute('data-bx-taskbar', this.id);
  
  			pGroup.setAttribute('data-bx-type', 'taskbargroup');
  			pGroup.setAttribute('data-bx-path', key);
  			pGroup.setAttribute('data-bx-taskbar', this.id);
  
  			parentCont.appendChild(pGroup);
  		},
  
  		BuildTreeElements: function(elements)
  		{
  			this.elements = elements;
  			for (var i in elements)
  			{
  				if (elements.hasOwnProperty(i))
  				{
  					this.BuildElement(elements[i]);
  				}
  			}
  		},
  
  		BuildElement: function(element)
  		{
  			var
  				_this = this,
  				parentCont = this.GetSectionContByPath(element.key || element.path, true),
  				pElement = BX.create("DIV", {props: {className: "bxhtmled-tskbr-element"}, html: '<span class="bxhtmled-tskbr-element-icon"></span><span class="bxhtmled-tskbr-element-text">' + element.title + '</span>'});
  
  			var dd = pElement.appendChild(BX.create("IMG", {props: {
  				src: this.editor.util.GetEmptyImage(),
  				className: "bxhtmled-drag"
  			}}));
  
  			this.HandleElementEx(pElement, dd, element);
  
  			this.searchIndex.push({
  				content: (element.title + ' ' + element.name).toLowerCase(),
  				element: pElement
  			});
  
  			dd.onmousedown = function (e)
  			{
  				if (!e)
  				{
  					e = window.event;
  				}
  
  				var
  					target = e.target || e.srcElement,
  					bxTag = _this.editor.GetBxTag(target);
  
  				return _this.OnElementMouseDownEx(e, target, bxTag);
  			};
  
  			dd.ondblclick = function(e)
  			{
  				var
  					target = e.target || e.srcElement,
  					bxTag = _this.editor.GetBxTag(target);
  
  				return _this.OnElementDoubleClick(e, target, bxTag);
  			};
  
  			dd.ondragend = function (e)
  			{
  				if (!e)
  				{
  					e = window.event;
  				}
  				_this.OnDragEndHandler(e, this);
  			};
  
  			pElement.setAttribute('data-bx-type', 'taskbarelement');
  
  			parentCont.appendChild(pElement);
  		},
  
  		HandleElementEx: function(dd)
  		{
  
  		},
  
  		GetSectionContByPath: function(path, bElement)
  		{
  			if (path == '' || !this.treeSectionIndex[path])
  			{
  				return this.pTreeCont;
  			}
  			else
  			{
  				return bElement ? this.treeSectionIndex[path].elementsCont : this.treeSectionIndex[path].childCont;
  			}
  		},
  
  		GetSectionByPath: function(path)
  		{
  			if (path == '' || !this.treeSectionIndex[path])
  			{
  				return this.sections;
  			}
  			else
  			{
  				return this.treeSectionIndex[path].sect.children;
  			}
  		},
  
  		// Open or close
  		ToggleGroup: function(cont, bOpen)
  		{
  			// TODO: animation
  			var path = cont.getAttribute('data-bx-path');
  			if (path)
  			{
  				var group = this.treeSectionIndex[path];
  				if (!group)
  				{
  					return;
  				}
  
  				if (bOpen !== undefined)
  				{
  					group.opened = !bOpen;
  				}
  
  				if (group.opened)
  				{
  					BX.removeClass(group.cont, 'bxhtmled-tskbr-sect-open');
  					BX.removeClass(group.icon, 'bxhtmled-tskbr-sect-icon-open');
  					BX.removeClass(group.outerCont, 'bxhtmled-tskbr-sect-outer-open');
  					group.childCont.style.display = 'none';
  					group.elementsCont.style.display = 'none';
  					group.opened = false;
  				}
  				else
  				{
  					BX.addClass(group.cont, 'bxhtmled-tskbr-sect-open');
  					BX.addClass(group.icon, 'bxhtmled-tskbr-sect-icon-open');
  					BX.addClass(group.outerCont, 'bxhtmled-tskbr-sect-outer-open');
  					group.childCont.style.display = 'block';
  					group.elementsCont.style.display = group.elementsCont.childNodes.length > 0 ? 'block' : 'none';
  					group.opened = true;
  				}
  			}
  		},
  
  		OnDragEndHandler: function(e, node)
  		{
  			var _this = this;
  			this.editor.skipPasteHandler = true;
  			setTimeout(function()
  			{
  				var dd = _this.editor.GetIframeElement(node.id);
  				if (dd && dd.parentNode)
  				{
  					var sur = _this.editor.util.CheckSurrogateNode(dd.parentNode);
  					if (sur)
  					{
  						_this.editor.util.InsertAfter(dd, sur);
  					}
  				}
  				_this.editor.synchro.FullSyncFromIframe();
  				_this.editor.skipPasteHandler = false;
  			}, 10);
  		},
  
  		OnElementMouseDownEx: function(e)
  		{
  			return true;
  		},
  
  		OnElementClick: function(e)
  		{
  			this.OnElementClickEx();
  			return true;
  		},
  
  		OnElementClickEx: function()
  		{
  			return true;
  		},
  
  		OnElementDoubleClick: function(e, target, bxTag)
  		{
  			if (target)
  			{
  				var dd = target.cloneNode(true);
  				this.editor.Focus();
  				this.editor.selection.InsertNode(dd);
  				this.editor.synchro.FullSyncFromIframe();
  			}
  		},
  
  		OnGroupTitleClick: function(pElement)
  		{
  			if (pElement && pElement.getAttribute('data-bx-taskbar') == this.id)
  			{
  				return this.ToggleGroup(pElement.parentNode);
  			}
  			return true;
  		},
  
  		OnTitleClick: function(pElement)
  		{
  			if (pElement && pElement.getAttribute('data-bx-taskbar') == this.id)
  			{
  				return this.manager.ShowTaskbar(this.id);
  			}
  			return true;
  		},
  
  		OnMenuClick: function(pElement)
  		{
  			if (pElement && pElement.getAttribute('data-bx-taskbar') == this.id)
  				return this.ShowMenu(pElement);
  			return true;
  		},
  
  		Activate: function()
  		{
  			this.pTreeCont.style.display = 'block';
  			this.bActive = true;
  			return true;
  		},
  
  		Deactivate: function()
  		{
  			this.pTreeCont.style.display = 'none';
  			this.bActive = false;
  			return true;
  		},
  
  		IsActive: function()
  		{
  			return !!this.bActive;
  		},
  
  		ShowMenu: function(pElement)
  		{
  			var arItems = this.GetMenuItems();
  			BX.PopupMenu.destroy(this.uniqueId + "_menu");
  			BX.PopupMenu.show(this.uniqueId + "_menu", pElement, arItems, {
  					overlay: {opacity: 0.1},
  					events: {
  						onPopupClose: function(){BX.removeClass(this.bindElement, "bxec-add-more-over");}
  					},
  					offsetLeft: 1,
  					zIndex: 3005
  				}
  			);
  			return true;
  		},
  
  		GetMenuItems: function()
  		{
  			return [];
  		},
  
  		Search: function(value)
  		{
  			this.ClearSearchResult();
  			var
  				bFoundItems = false,
  				pSect, el,
  				i, l = this.searchIndex.length;
  
  			value = BX.util.trim(value.toLowerCase());
  
  			BX.addClass(this.pTreeCont, 'bxhtmled-taskbar-tree-cont-search');
  			BX.addClass(this.manager.pSearchCont, 'bxhtmled-search-cont-res');
  
  			for(i = 0; i < l; i++)
  			{
  				el = this.searchIndex[i];
  				if (el.content.indexOf(value) !== -1) // Show element
  				{
  					bFoundItems = true;
  					BX.addClass(el.element, 'bxhtmled-tskbr-search-res');
  					this._searchResult.push(el.element);
  
  					pSect = BX.findParent(el.element, function(node)
  					{
  						return node.getAttribute && node.getAttribute('data-bx-type') == 'taskbargroup';
  					}, this.pTreeCont);
  
  					while (pSect)
  					{
  						BX.addClass(pSect, 'bxhtmled-tskbr-search-res');
  						this.ToggleGroup(pSect, true);
  						this._searchResultSect.push(pSect);
  
  						pSect = BX.findParent(pSect, function(node)
  						{
  							return node.getAttribute && node.getAttribute('data-bx-type') == 'taskbargroup';
  						}, this.pTreeCont);
  					}
  				}
  			}
  
  			if (!bFoundItems)
  			{
  				this.manager.pSearchNothingNotice.style.display = 'block';
  			}
  		},
  
  		ClearSearchResult: function()
  		{
  			BX.removeClass(this.pTreeCont, 'bxhtmled-taskbar-tree-cont-search');
  			BX.removeClass(this.manager.pSearchCont, 'bxhtmled-search-cont-res');
  			this.manager.pSearchNothingNotice.style.display = 'none';
  			var i;
  			if (this._searchResult)
  			{
  				for(i = 0; i < this._searchResult.length; i++)
  				{
  					BX.removeClass(this._searchResult[i], 'bxhtmled-tskbr-search-res');
  				}
  				this._searchResult = [];
  			}
  			if (this._searchResultSect)
  			{
  				for(i = 0; i < this._searchResultSect.length; i++)
  				{
  					BX.removeClass(this._searchResultSect[i], 'bxhtmled-tskbr-search-res');
  					this.ToggleGroup(this._searchResultSect[i], false);
  				}
  				this._searchResultSect = [];
  			}
  		},
  
  		GetId: function()
  		{
  			return this.id;
  		}
  	};
  
  	function ComponentsControl(editor)
  	{
  		// Call parrent constructor
  		ComponentsControl.superclass.constructor.apply(this, arguments);
  
  		this.id = 'components';
  		this.title = BX.message('ComponentsTitle');
  		this.templateId = this.editor.templateId;
  		this.uniqueId = 'taskbar_' + this.editor.id + '_' + this.id;
  		this.searchPlaceholder = BX.message('BXEdCompSearchPlaceHolder');
  
  		this.Init();
  	}
  
  	BX.extend(ComponentsControl, Taskbar);
  
  	ComponentsControl.prototype.Init = function()
  	{
  		this.BuildSceleton();
  		// Build structure
  		var list = this.editor.components.GetList();
  		this.BuildTree(list.groups, list.items);
  	};
  
  	ComponentsControl.prototype.HandleElementEx = function(wrap, dd, params)
  	{
  		this.editor.SetBxTag(dd, {tag: "component_icon", params: params});
  		if (params.complex == "Y")
  		{
  			params.className = 'bxhtmled-surrogate-green';
  			BX.addClass(wrap, 'bxhtmled-tskbr-element-green');
  			wrap.title = BX.message('BXEdComplexComp');
  		}
  	};
  
  	ComponentsControl.prototype.OnElementMouseDownEx = function(e, target, bxTag)
  	{
  		if (!bxTag || bxTag.tag !== 'component_icon')
  		{
  			return false;
  		}
  
  		this.editor.components.LoadParamsList({
  			name: bxTag.params.name
  		});
  	};
  
  	ComponentsControl.prototype.GetMenuItems = function()
  	{
  		var _this = this;
  		return [
  			{
  				text : BX.message('RefreshTaskbar'),
  				title : BX.message('RefreshTaskbar'),
  				className : "",
  				onclick: function()
  				{
  					_this.editor.componentsTaskbar.ClearSearchResult();
  					_this.editor.components.ReloadList();
  					BX.PopupMenu.destroy(_this.uniqueId + "_menu");
  				}
  			}
  		];
  	};
  
  	// Editor dialog
  	function Dialog(editor, params)
  	{
  		this.editor = editor;
  		this.id = params.id;
  		this.params = params;
  		this.className = "bxhtmled-dialog" + (params.className ? ' ' + params.className : '');
  		this.zIndex = params.zIndex || 3008;
  		this.firstFocus = false;
  		this.Init();
  	}
  
  	Dialog.prototype = {
  		Init: function()
  		{
  			var
  				_this = this,
  				config = {
  					title : this.params.title || this.params.name || '',
  					width: this.params.width || 600,
  					resizable: false
  				};
  
  			if (this.params.resizable)
  			{
  				config.resizable = true;
  				config.min_width = this.params.min_width || 400;
  				config.min_height = this.params.min_height || 250;
  				config.resize_id = this.params.resize_id || this.params.id + '_res';
  			}
  
  			this.oDialog = new BX.CDialog(config);
  			config.height = this.params.height || false;
  
  			BX.addCustomEvent(this.oDialog, 'onWindowResize', BX.proxy(this.OnResize, this));
  			BX.addCustomEvent(this.oDialog, 'onWindowResizeFinished', BX.proxy(this.OnResizeFinished, this));
  			BX.addClass(this.oDialog.PARTS.CONTENT, this.className);
  
  			// Clear dialog height for auto resizing
  			if (!config.height)
  			{
  				this.oDialog.PARTS.CONTENT_DATA.style.height = null;
  			}
  
  			// Buttons
  			this.oDialog.SetButtons([
  				new BX.CWindowButton(
  					{
  						title: BX.message('DialogSave'),
  						className: 'adm-btn-save',
  						action: function()
  						{
  							BX.onCustomEvent(_this, "OnDialogSave");
  							_this.oDialog.Close();
  						}
  					}),
  				this.oDialog.btnCancel
  			]);
  
  			BX.addCustomEvent(this.oDialog, 'onWindowUnRegister', function()
  			{
  				BX.unbind(window, "keydown", BX.proxy(_this.OnKeyDown, _this));
  				_this.dialogShownTimeout = setTimeout(function(){_this.editor.dialogShown = false;}, 300);
  				_this.RestoreWindowOverflow();
  			});
  		},
  
  		Show: function()
  		{
  			var _this = this;
  			this.editor.dialogShown = true;
  			if (this.dialogShownTimeout)
  			{
  				this.dialogShownTimeout = clearTimeout(this.dialogShownTimeout);
  			}
  			this.oDialog.Show();
  			this.oDialog.DIV.style.zIndex = this.zIndex;
  			this.oDialog.OVERLAY.style.zIndex = this.zIndex - 2;
  			var
  				top = parseInt(this.oDialog.DIV.style.top) - 180,
  				scrollPos = BX.GetWindowScrollPos(document),
  				scrollTop = scrollPos.scrollTop,
  				minTop = scrollTop + 50;
  
  			this.oDialog.DIV.style.top = (top > minTop ? top : minTop) + 'px';
  			BX.bind(window, "keydown", BX.proxy(this.OnKeyDown, this));
  
  			this.savedBodyOverflow = this.savedScrollLeft = this.savedScrollTop = false;
  
  			setTimeout(function()
  				{
  					// Hack for Opera
  					if (BX.browser.IsOpera())
  						_this.oDialog.Move(1, 1);
  
  					_this.oDialog.__resizeOverlay();
  
  					if (_this.firstFocus)
  					{
  						BX.focus(_this.firstFocus);
  						if (_this.selectFirstFocus)
  							_this.firstFocus.select();
  					}
  				},
  				100
  			);
  		},
  
  		BuildTabControl: function(pCont, arTabs)
  		{
  			var
  				i,
  				pTabsWrap = BX.create('DIV', {props: {className: 'bxhtmled-dlg-tabs-wrap'}}),
  				pContWrap = BX.create('DIV', {props: {className: 'bxhtmled-dlg-cont-wrap'}});
  
  			for (i = 0; i < arTabs.length; i++)
  			{
  				arTabs[i].tab = pTabsWrap.appendChild(BX.create('SPAN', {props: {className: 'bxhtmled-dlg-tab' + (i == 0 ? ' bxhtmled-dlg-tab-active' : '')}, attrs: {'data-bx-dlg-tab-ind': i.toString()}, text: arTabs[i].name}));
  				arTabs[i].cont = pContWrap.appendChild(BX.create('DIV', {props: {className: 'bxhtmled-dlg-cont'}, style: {'display' : i == 0 ? '' : 'none'}}));
  			}
  
  			BX.bind(pTabsWrap, 'click', function(e)
  			{
  				var
  					ind,
  					target = e.target || e.srcElement;
  
  				if (target && target.getAttribute)
  				{
  					ind = parseInt(target.getAttribute('data-bx-dlg-tab-ind'));
  					if (!isNaN(ind))
  					{
  						for (i = 0; i < arTabs.length; i++)
  						{
  							if (i == ind)
  							{
  								arTabs[i].cont.style.display = '';
  								BX.addClass(arTabs[i].tab, 'bxhtmled-dlg-tab-active');
  							}
  							else
  							{
  								arTabs[i].cont.style.display = 'none';
  								BX.removeClass(arTabs[i].tab, 'bxhtmled-dlg-tab-active');
  							}
  						}
  					}
  				}
  			});
  
  			pCont.appendChild(pTabsWrap);
  			pCont.appendChild(pContWrap);
  
  			return {
  				cont: pCont,
  				tabsWrap : pTabsWrap,
  				contWrap : pContWrap,
  				tabs: arTabs
  			};
  		},
  
  		OnKeyDown: function(e)
  		{
  			if (e.keyCode == 13 && this.closeByEnter !== false)
  			{
  				var target = e.target || e.srcElement;
  				if (target && target.nodeName !== 'TEXTAREA')
  				{
  					this.oDialog.PARAMS.buttons[0].emulate();
  				}
  			}
  		},
  
  		SetContent: function(html)
  		{
  			return this.oDialog.SetContent(html);
  		},
  
  		SetTitle: function(title)
  		{
  			return this.oDialog.SetTitle(title);
  		},
  
  		OnResize: function()
  		{
  		},
  
  		OnResizeFinished: function()
  		{
  		},
  
  		GetContentSize: function()
  		{
  			return {
  				width : this.oDialog.PARTS.CONTENT_DATA.offsetWidth,
  				height : this.oDialog.PARTS.CONTENT_DATA.offsetHeight
  			};
  		},
  
  		Save: function()
  		{
  			if (this.savedRange)
  			{
  				this.editor.selection.SetBookmark(this.savedRange);
  			}
  
  			if (this.action && this.editor.action.IsSupported(this.action))
  			{
  				this.editor.action.Exec(this.action, this.GetValues());
  			}
  		},
  
  		Close: function()
  		{
  			if (this.IsOpen())
  			{
  				this.oDialog.Close();
  			}
  		},
  
  		IsOpen: function()
  		{
  			return this.oDialog.isOpen;
  		},
  
  		DisableKeyCheck: function()
  		{
  			this.closeByEnter = false;
  			BX.WindowManager.disableKeyCheck();
  		},
  
  		EnableKeyCheck: function()
  		{
  			var _this = this;
  			setTimeout(function()
  			{
  				_this.closeByEnter = true;
  				BX.WindowManager.enableKeyCheck();
  			}, 200);
  		},
  
  		AddTableRow: function (tbl, firstCell)
  		{
  			var r, c1, c2;
  
  			r = tbl.insertRow(-1);
  			c1 = r.insertCell(-1);
  			c1.className = 'bxhtmled-left-c';
  
  			if (firstCell && firstCell.label)
  			{
  				c1.appendChild(BX.create('LABEL', {props: {className: firstCell.required ? 'bxhtmled-req' : ''}, text: firstCell.label})).setAttribute('for', firstCell.id);
  			}
  
  			c2 = r.insertCell(-1);
  			c2.className = 'bxhtmled-right-c';
  			return {row: r, leftCell: c1, rightCell: c2};
  		},
  
  		SetValues: BX.DoNothing,
  		GetValues: BX.DoNothing,
  
  		CheckSize: function(timeout)
  		{
  			var _this = this;
  
  			if (this.checkSizeTimeout)
  				this.checkSizeTimeout = clearTimeout(this.checkSizeTimeout);
  
  			if (timeout !== true)
  			{
  				this.checkSizeTimeout = setTimeout(function()
  				{
  					_this.CheckSize(true);
  				}, 50);
  				return;
  			}
  
  			var
  				innerSize = BX.GetWindowInnerSize(document),
  				dialogBottom = this.oDialog.DIV.offsetHeight + 50;
  
  			if (dialogBottom >= innerSize.innerHeight)
  			{
  				var scrollPos = BX.GetWindowScrollPos(document);
  				this.savedBodyOverflow = document.body.style.overflow;
  				this.savedScrollTop = scrollPos.scrollTop;
  				this.savedScrollLeft = scrollPos.scrollLeft;
  				document.body.style.overflow = "auto";
  
  				if (this.editor.expanded)
  					BX.unbind(window, "scroll", BX.proxy(this.editor.PreventScroll, this.editor));
  			}
  			else
  			{
  				this.RestoreWindowOverflow();
  			}
  		},
  
  		RestoreWindowOverflow: function()
  		{
  			if (this.savedBodyOverflow !== false)
  			{
  				document.body.style.overflow = this.savedBodyOverflow;
  				this.savedBodyOverflow = false;
  			}
  
  			if (this.savedScrollTop !== false)
  			{
  				window.scrollTo(this.savedScrollLeft, this.savedScrollTop);
  				this.savedScrollLeft = this.savedScrollTop = false;
  			}
  
  			if (this.editor.expanded)
  				BX.bind(window, "scroll", BX.proxy(this.editor.PreventScroll, this.editor));
  		}
  	};
  
  	function ContextMenu(editor)
  	{
  		this.editor = editor;
  		BX.addCustomEvent(this.editor, 'OnIframeContextMenu', BX.delegate(this.Show, this));
  		this.Init();
  	}
  
  	ContextMenu.prototype = {
  		Init: function()
  		{
  			var
  			_this = this,
  			defaultItem = {
  				TEXT: BX.message('ContMenuDefProps'),
  				ACTION: function()
  				{
  					_this.editor.selection.SetBookmark(_this.savedRange);
  					_this.editor.GetDialog('Default').Show(false, _this.savedRange);
  					_this.Hide();
  				}
  			};
  
  			// Remove format ?
  			// Replace Node by children ?
  
  			//this.tagsList = [];
  			this.items = {
  				// Surrogates
  				'php' : [
  					{
  						TEXT: BX.message('BXEdContMenuPhpCode'),
  						ACTION: function()
  						{
  							var items = _this.GetTargetItem();
  							if (items && items.php)
  							{
  								_this.editor.GetDialog('Source').Show(items.php.bxTag);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'anchor' : [
  					{
  						TEXT: BX.message('BXEdEditAnchor'),
  						ACTION: function()
  						{
  							var items = _this.GetTargetItem();
  							if (items && items.anchor)
  							{
  								_this.editor.GetDialog('Anchor').Show(items.anchor.bxTag);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'javascript' : [
  					{
  						TEXT: BX.message('BXEdContMenuJavascript'),
  						ACTION: function()
  						{
  							var items = _this.GetTargetItem();
  							if (items && items.javascript)
  							{
  								_this.editor.GetDialog('Source').Show(items.javascript.bxTag);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'htmlcomment' : [
  					{
  						TEXT: BX.message('BXEdContMenuHtmlComment'),
  						ACTION: function()
  						{
  							var items = _this.GetTargetItem();
  							if (items && items.htmlcomment)
  							{
  								_this.editor.GetDialog('Source').Show(items.htmlcomment.bxTag);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'iframe' : [
  					{
  						TEXT: BX.message('BXEdContMenuIframe'),
  						ACTION: function()
  						{
  							var items = _this.GetTargetItem();
  							if (items && items.iframe)
  							{
  								_this.editor.GetDialog('Source').Show(items.iframe.bxTag);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'style' : [
  					{
  						TEXT: BX.message('BXEdContMenuStyle'),
  						ACTION: function()
  						{
  							var items = _this.GetTargetItem();
  							if (items && items.style)
  							{
  								_this.editor.GetDialog('Source').Show(items.style.bxTag);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'object' : [
  					{
  						TEXT: BX.message('BXEdContMenuObject'),
  						ACTION: function()
  						{
  							var items = _this.GetTargetItem();
  							if (items && items.object)
  							{
  								_this.editor.GetDialog('Source').Show(items.object.bxTag);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'component' : [
  					{
  						TEXT: BX.message('BXEdContMenuComponent'),
  						ACTION: function()
  						{
  							var items = _this.GetTargetItem();
  							if (items && items.component)
  							{
  								// Show dialog
  								_this.editor.components.ShowPropertiesDialog(items.component.bxTag.params, _this.editor.GetBxTag(items.component.bxTag.surrogateId));
  							}
  							_this.Hide();
  						}
  					},
  					{
  						TEXT: BX.message('BXEdContMenuComponentRemove'),
  						ACTION: function()
  						{
  							var items = _this.GetTargetItem();
  							if (items && items.component)
  							{
  								BX.remove(items.component.element);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'printbreak' : [
  					{
  						TEXT: BX.message('NodeRemove'),
  						ACTION: function(e)
  						{
  							var node = _this.GetTargetItem('printbreak');
  							if (node && node.element)
  							{
  								_this.editor.selection.RemoveNode(node.element);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'video': [
  					{
  						TEXT: BX.message('BXEdVideoProps'),
  						bbMode: true,
  						ACTION: function()
  						{
  							var node = _this.GetTargetItem('video');
  							if (node)
  							{
  								_this.editor.GetDialog('Video').Show(node.bxTag);
  							}
  							_this.Hide();
  						}
  					},
  					{
  						TEXT: BX.message('BXEdVideoDel'),
  						bbMode: true,
  						ACTION: function(e)
  						{
  							var node = _this.GetTargetItem('video');
  							if (node && node.element)
  							{
  								_this.editor.selection.RemoveNode(node.element);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'smile' : [],
  
  				// Nodes
  				'A' : [
  					{
  						TEXT: BX.message('ContMenuLinkEdit'),
  						bbMode: true,
  						ACTION: function()
  						{
  							var node = _this.GetTargetItem('A');
  							if (node)
  							{
  								_this.editor.GetDialog('Link').Show([node], this.savedRange);
  							}
  							_this.Hide();
  						}
  					},
  					{
  						TEXT: BX.message('ContMenuLinkDel'),
  						bbMode: true,
  						ACTION: function()
  						{
  							var link = _this.GetTargetItem('A');
  							if (link && _this.editor.action.IsSupported('removeLink'))
  							{
  								_this.editor.action.Exec('removeLink', [link]);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'IMG': [
  					{
  						TEXT: BX.message('ContMenuImgEdit'),
  						bbMode: true,
  						ACTION: function()
  						{
  							var node = _this.GetTargetItem('IMG');
  							if (node)
  							{
  								_this.editor.GetDialog('Image').Show([node], _this.savedRange);
  							}
  							_this.Hide();
  						}
  					},
  					{
  						TEXT: BX.message('ContMenuImgDel'),
  						bbMode: true,
  						ACTION: function()
  						{
  							var node = _this.GetTargetItem('IMG');
  							if (node)
  							{
  								_this.editor.selection.RemoveNode(node);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				'DIV': [
  					{
  						TEXT: BX.message('ContMenuCleanDiv'),
  						title: BX.message('ContMenuCleanDiv_Title'),
  						ACTION: function()
  						{
  							var node = _this.GetTargetItem('DIV');
  							if (node)
  							{
  								_this.editor.On('OnHtmlContentChangedByControl');
  								_this.editor.util.ReplaceWithOwnChildren(node);
  								_this.editor.synchro.FullSyncFromIframe();
  							}
  							_this.Hide();
  						}
  					},
  					defaultItem
  				],
  				'TABLE': [
  
  					{
  						TEXT: BX.message('BXEdTableInsertMenu'),
  						HIDE_ITEM: function()
  						{
  							var cells = _this.editor.action.actions.tableOperation.getSelectedCells(_this.savedRange, _this.GetTargetItem('TABLE'));
  							return !cells || cells.length != 1;
  						},
  						MENU: [
  							// Column
  							{
  								TEXT: BX.message('BXEdTableInsColLeft'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'insertColumnLeft',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								}
  							},
  							{
  								TEXT: BX.message('BXEdTableInsColRight'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'insertColumnRight',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								}
  							},
  							// Row
  							{
  								TEXT: BX.message('BXEdTableInsRowUpper'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'insertRowUpper',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								}
  							},
  							{
  								TEXT: BX.message('BXEdTableInsRowLower'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'insertRowLower',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								}
  							},
  							// Cell
  							{
  								TEXT: BX.message('BXEdTableInsCellBefore'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'insertCellLeft',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								}
  							},
  							{
  								TEXT: BX.message('BXEdTableInsCellAfter'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'insertCellRight',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								}
  							}
  						]
  					},
  					{
  						TEXT: BX.message('BXEdTableRemoveMenu'),
  						MENU: [
  							{
  								TEXT: BX.message('BXEdTableDelCol'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'removeColumn',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								},
  								HIDE_ITEM: function()
  								{
  									var cells = _this.editor.action.actions.tableOperation.getSelectedCells(_this.savedRange, _this.GetTargetItem('TABLE'));
  									return !cells || cells.length != 1;
  								}
  							},
  							{
  								TEXT: BX.message('BXEdTableDelRow'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'removeRow',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								},
  								HIDE_ITEM: function()
  								{
  									var cells = _this.editor.action.actions.tableOperation.getSelectedCells(_this.savedRange, _this.GetTargetItem('TABLE'));
  									return !cells || cells.length != 1;
  								}
  							},
  							{
  								TEXT: BX.message('BXEdTableDellCell'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'removeCell',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								},
  								HIDE_ITEM: function()
  								{
  									var cells = _this.editor.action.actions.tableOperation.getSelectedCells(_this.savedRange, _this.GetTargetItem('TABLE'));
  									return !cells || cells.length != 1;
  								}
  							},
  							{
  								TEXT: BX.message('BXEdTableDellSelectedCells'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'removeSelectedCells',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								},
  								HIDE_ITEM: function()
  								{
  									var cells = _this.editor.action.actions.tableOperation.getSelectedCells(_this.savedRange, _this.GetTargetItem('TABLE'));
  									return !cells || cells.length === 1;
  								}
  							}
  						]
  					},
  					{
  						TEXT: BX.message('BXEdTableMergeMenu'),
  						MENU: [
  							{
  								TEXT: BX.message('BXEdTableMergeSelectedCells'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'mergeSelectedCells',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								},
  								HIDE_ITEM: function()
  								{
  									if (!_this.savedRange.collapsed)
  									{
  										return !_this.editor.action.actions.tableOperation.canBeMerged(false, _this.savedRange, _this.GetTargetItem('TABLE'));
  									}
  
  									return true;
  								}
  							},
  							{
  								TEXT: BX.message('BXEdTableMergeRight'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'mergeRightCell',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								},
  								HIDE_ITEM: function()
  								{
  									return !_this.editor.action.actions.tableOperation.canBeMergedWithRight(_this.savedRange, _this.GetTargetItem('TABLE'));
  								}
  							},
  							{
  								TEXT: BX.message('BXEdTableMergeBottom'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'mergeBottomCell',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								},
  								HIDE_ITEM: function()
  								{
  									return !_this.editor.action.actions.tableOperation.canBeMergedWithBottom(_this.savedRange, _this.GetTargetItem('TABLE'));
  								}
  							},
  							{
  								TEXT: BX.message('BXEdTableMergeRowCells'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'mergeRow',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								},
  								HIDE_ITEM: function()
  								{
  									var cells = _this.editor.action.actions.tableOperation.getSelectedCells(_this.savedRange, _this.GetTargetItem('TABLE'));
  									return !cells || cells.length > 1;
  								}
  							},
  							{
  								TEXT: BX.message('BXEdTableMergeColCells'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'mergeColumn',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								},
  								HIDE_ITEM: function()
  								{
  									var cells = _this.editor.action.actions.tableOperation.getSelectedCells(_this.savedRange, _this.GetTargetItem('TABLE'));
  									return !cells || cells.length > 1;
  								}
  							}
  						]
  					},
  					{
  						TEXT: BX.message('BXEdTableSplitMenu'),
  						HIDE_ITEM: function()
  						{
  							var cells = _this.editor.action.actions.tableOperation.getSelectedCells(_this.savedRange, _this.GetTargetItem('TABLE'));
  							return !cells || cells.length != 1;
  						},
  						MENU: [
  							{
  								TEXT: BX.message('BXEdTableSplitCellHor'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'splitHorizontally',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								}
  							},
  							{
  								TEXT: BX.message('BXEdTableSplitCellVer'),
  								ACTION: function()
  								{
  									_this.editor.action.Exec('tableOperation', {
  										actionType: 'splitVertically',
  										tableNode: _this.GetTargetItem('TABLE'),
  										range: _this.savedRange
  									});
  									_this.Hide();
  								}
  							}
  						]
  					},
  					{SEPARATOR: true},
  
  					{
  						TEXT: BX.message('BXEdTableTableCellProps'),
  						ACTION: function()
  						{
  							var node = _this.GetTargetItem('TABLE');
  							if (node)
  							{
  								var cells = _this.editor.action.actions.tableOperation.getSelectedCells(_this.savedRange, _this.GetTargetItem('TABLE'));
  								_this.editor.GetDialog('Default').Show(cells, _this.savedRange);
  							}
  							_this.Hide();
  						},
  						HIDE_ITEM: function()
  						{
  							var cells = _this.editor.action.actions.tableOperation.getSelectedCells(_this.savedRange, _this.GetTargetItem('TABLE'));
  							return !cells || cells.length != 1;
  						}
  					},
  
  					{
  						TEXT: BX.message('BXEdTableTableProps'),
  						ACTION: function()
  						{
  							var node = _this.GetTargetItem('TABLE');
  							if (node)
  							{
  								_this.editor.GetDialog('Table').Show([node], _this.savedRange);
  							}
  							_this.Hide();
  						}
  					},
  					{
  						TEXT: BX.message('BXEdTableDeleteTable'),
  						bbMode: true,
  						ACTION: function()
  						{
  							var node = _this.GetTargetItem('TABLE');
  							if (node)
  							{
  								_this.editor.selection.RemoveNode(node);
  							}
  							_this.Hide();
  						}
  					}
  				],
  				// ...
  				'DEFAULT': [defaultItem]
  			};
  		},
  
  		Show: function(e, target)
  		{
  			this.savedRange = this.editor.selection.GetBookmark();
  			this.Hide();
  
  			this.editor.contextMenuShown = true;
  			if (this.contextMenuShownTimeout)
  			{
  				this.contextMenuShownTimeout = clearTimeout(this.contextMenuShownTimeout);
  			}
  			this.nodes = [];
  			this.tagIndex = {};
  			var
  				bxTag,
  				i, j, k, menuItems, item, itemGr,
  				arItems = [],
  				maxIter = 20, iter = 0,
  				element = target,
  				label;
  
  			this.targetItems = {};
  			while (true)
  			{
  				if (element.nodeName && element.nodeName.toUpperCase() != 'BODY')
  				{
  					if (element.nodeType != 3)
  					{
  						bxTag = this.editor.GetBxTag(element);
  
  						if (bxTag && bxTag.tag == 'surrogate_dd')
  						{
  							var origTag = this.editor.GetBxTag(bxTag.params.origId);
  							element = this.editor.GetIframeElement(origTag.id);
  							this.PushTargetItem(origTag.tag, {element: element, bxTag: origTag});
  							this.nodes = [element];
  							this.tagIndex[origTag.tag] = 0;
  							iter = 0;
  							element = element.parentNode;
  							continue;
  						}
  						else if (bxTag && bxTag.tag && this.items[bxTag.tag])
  						{
  							this.nodes = [element];
  							this.PushTargetItem(bxTag.tag, {element: element, bxTag: bxTag.tag});
  							this.nodes = [element];
  							this.tagIndex[bxTag.tag] = 0;
  							iter = 0;
  							element = element.parentNode;
  							continue;
  						}
  
  						label = element.nodeName;
  						this.PushTargetItem(label, element);
  						this.nodes.push(element);
  						this.tagIndex[label] = this.nodes.length - 1;
  					}
  					iter++;
  				}
  
  				if (!element ||
  					element.nodeName && element.nodeName.toUpperCase() == 'BODY' ||
  					iter >= maxIter)
  				{
  					break;
  				}
  
  				element = element.parentNode;
  			}
  
  			for (i in this.items)
  			{
  				if (this.items.hasOwnProperty(i) && this.tagIndex[i] != undefined)
  				{
  					if (arItems.length > 0)
  					{
  						arItems.push({SEPARATOR : true});
  					}
  
  					for (j = 0; j < this.items[i].length; j++)
  					{
  						if (typeof this.items[i][j].HIDE_ITEM == 'function'  && this.items[i][j].HIDE_ITEM() === true)
  							continue;
  
  						if (this.editor.bbCode && !this.items[i][j].bbMode)
  							continue;
  
  						if (this.items[i][j].MENU)
  						{
  							itemGr = BX.clone(this.items[i][j]);
  							menuItems = [];
  							for (k = 0; k < itemGr.MENU.length; k++)
  							{
  								item = itemGr.MENU[k];
  								if (typeof item.HIDE_ITEM == 'function'  && item.HIDE_ITEM() === true)
  									continue;
  
  								if (this.editor.bbCode && !item.bbMode)
  									continue;
  
  								menuItems.push(item);
  							}
  
  							if (menuItems.length === 0)
  								continue;
  
  							itemGr.MENU = menuItems;
  
  							arItems.push(itemGr);
  						}
  						else
  						{
  							arItems.push(this.items[i][j]);
  						}
  					}
  				}
  			}
  
  			if (arItems.length == 0)
  			{
  				var def = this.items['DEFAULT'];
  				if (!this.editor.bbCode || def.bbMode)
  				{
  					for (j = 0; j < def.length; j++)
  					{
  						arItems.push(def[j]);
  					}
  				}
  			}
  
  			var
  				x = e.clientX,
  				y = e.clientY;
  
  			if (!this.dummyTarget)
  			{
  				this.dummyTarget = this.editor.dom.iframeCont.appendChild(BX.create('DIV', {props: {className: 'bxhtmled-dummy-target'}}));
  			}
  
  			this.dummyTarget.style.left = x + 'px';
  			this.dummyTarget.style.top = y + 'px';
  			this.dummyTarget.style.zIndex = '2002';
  
  			if (arItems.length > 0)
  			{
  				this.OPENER = new BX.COpener({
  					DIV: this.dummyTarget,
  					MENU: arItems,
  					TYPE: 'click',
  					ACTIVE_CLASS: 'adm-btn-active',
  					CLOSE_ON_CLICK: true
  				});
  				this.OPENER.Open();
  				this.OPENER.GetMenu().DIV.style.zIndex = '3005';
  
  				this.isOpened = true;
  				BX.addCustomEvent(this.editor, 'OnIframeClick', BX.proxy(this.Hide, this));
  				BX.addCustomEvent(this.editor, 'OnIframeKeyup', BX.proxy(this.CheckEscapeClose, this));
  				return BX.PreventDefault(e);
  			}
  		},
  
  		Hide: function()
  		{
  			if (this.OPENER)
  			{
  				var _this = this;
  				this.contextMenuShownTimeout = setTimeout(function(){_this.editor.contextMenuShown = false;}, 300);
  				this.OPENER.bMenuInit = true;
  				this.OPENER.Close();
  				this.isOpened = false;
  				BX.removeCustomEvent(this.editor, 'OnIframeClick', BX.proxy(this.Hide, this));
  				BX.removeCustomEvent(this.editor, 'OnIframeKeyup', BX.proxy(this.CheckEscapeClose, this));
  			}
  		},
  
  		CheckEscapeClose: function(e, keyCode)
  		{
  			if (keyCode == this.editor.KEY_CODES['escape'])
  				this.Hide();
  		},
  
  		GetTargetItem: function(tag)
  		{
  			return tag ? (this.targetItems[tag] || null) : this.targetItems;
  		},
  
  		PushTargetItem: function(key, tag)
  		{
  			if (!this.targetItems[key])
  				this.targetItems[key] = tag;
  		}
  	};
  
  	function Toolbar(editor, topControls)
  	{
  		this.editor = editor;
  		this.pCont = editor.dom.toolbar;
  		this.controls = {};
  		this.bCompact = false;
  		this.topControls = topControls;
  		this.showMoreButton = false;
  		this.shown = true;
  		this.height = 34;
  		this.Init();
  	}
  
  	Toolbar.prototype = {
  		Init: function()
  		{
  			this.BuildControls();
  			// Init Event handlers
  			BX.addCustomEvent(this.editor, "OnIframeFocus", BX.delegate(this.EnableWysiwygButtons, this));
  			BX.addCustomEvent(this.editor, "OnTextareaFocus", BX.delegate(this.DisableWysiwygButtons, this));
  		},
  
  		BuildControls: function()
  		{
  			BX.cleanNode(this.pCont);
  			var
  				i,
  				wrap, moreCont, cont,
  				map = this.GetControlsMap(),
  				wraps = {
  					left: this.pCont.appendChild(BX.create('span', {props: {className: 'bxhtmled-top-bar-left-wrap'}, style: {display: 'none'}})),
  					main: this.pCont.appendChild(BX.create('span', {props: {className: 'bxhtmled-top-bar-wrap'}, style: {display: 'none'}})),
  					right: this.pCont.appendChild(BX.create('span', {props: {className: 'bxhtmled-top-bar-right-wrap'}, style: {display: 'none'}})),
  					hidden: this.pCont.appendChild(BX.create('span', {props: {className: 'bxhtmled-top-bar-hidden-wrap'}}))
  				};
  
  			this.hiddenWrap = wraps.hidden;
  
  			this.editor.normalWidth = this.editor.NORMAL_WIDTH;
  			for (i = 0; i < map.length; i++)
  			{
  				if(map[i].hidden)
  				{
  					map[i].wrap = 'hidden';
  					this.showMoreButton = true;
  				}
  				else if (map[i].checkWidth && map[i].offsetWidth)
  				{
  					this.editor.normalWidth += map[i].offsetWidth;
  				}
  
  				wrap = wraps[(map[i].wrap || 'main')];
  
  				if (!wrap)
  				{
  					// We trying to find wrap as dom element by Id
  					wrap = BX(map[i].wrap);
  					if (wrap)
  					{
  						wraps[map[i].wrap] = wrap;
  					}
  					else
  					{
  						wrap = wraps['main'];
  					}
  				}
  
  				if (wrap.style.display == 'none')
  					wrap.style.display = '';
  
  				if (map[i].separator)
  				{
  					wrap.appendChild(this.GetSeparator()); // Show separator
  				}
  				else if(this.topControls[map[i].id])
  				{
  					if (!this.controls[map[i].id])
  					{
  						this.controls[map[i].id] = new this.topControls[map[i].id](this.editor, wrap);
  					}
  					else
  					{
  						cont = this.controls[map[i].id].GetPopupBindCont ? this.controls[map[i].id].GetPopupBindCont() : this.controls[map[i].id].GetCont();
  
  						if (this.controls[map[i].id].CheckBeforeShow && !this.controls[map[i].id].CheckBeforeShow())
  							continue;
  
  						if (this.controls.More && ((this.bCompact && !map[i].compact) || map[i].hidden))
  						{
  							if (!moreCont)
  							{
  								moreCont = this.controls.More.GetPopupCont();
  							}
  							moreCont.appendChild(cont);
  						}
  						else
  						{
  							wrap.appendChild(cont);
  						}
  					}
  				}
  			}
  
  			for (i in wraps)
  			{
  				if (wraps.hasOwnProperty(i) && i !== 'main' && i !== 'left' && i !== 'right' && i !== 'hidden' && wraps[i].getAttribute('data-bx-check-command') !== 'N')
  				{
  					wraps[i].setAttribute('data-bx-check-command', 'N');
  					BX.bind(wraps[i], "click", BX.proxy(function(e)
  					{
  						this.editor.CheckCommand(e.target || e.srcElement);
  					}, this));
  				}
  			}
  		},
  
  		GetControlsMap: function()
  		{
  			if (this.controlsMap)
  				return this.controlsMap;
  
  			var res = this.editor.config.controlsMap;
  			if (!res)
  			{
  				res = [
  					//{id: 'SearchButton', wrap: 'left', compact: true},
  					{id: 'ChangeView', wrap: 'left', compact: true, sort: 10},
  					{id: 'Undo', compact: false, sort: 20},
  					{id: 'Redo', compact: false, sort: 30},
  					{id: 'StyleSelector', compact: true, sort: 40},
  					{id: 'FontSelector', compact: false, sort: 50},
  					{id: 'FontSize', compact: false, sort: 60},
  					{separator: true, compact: false, sort: 70},
  					{id: 'Bold', compact: true, sort: 80},
  					{id: 'Italic', compact: true, sort: 90},
  					{id: 'Underline', compact: true, sort: 100},
  					{id: 'Strikeout', compact: true, sort: 110},
  					{id: 'RemoveFormat', compact: true, sort: 120},
  					{id: 'Color', compact: true, sort: 130},
  					{separator: true, compact: false, sort: 140},
  					{id: 'OrderedList', compact: true, sort: 150},
  					{id: 'UnorderedList', compact: true, sort: 160},
  					{id: 'IndentButton', compact: true, sort: 170},
  					{id: 'OutdentButton', compact: true, sort: 180},
  					{id: 'AlignList',compact: true, sort: 190},
  					{separator: true, compact: false, sort: 200},
  					{id: 'InsertLink', compact: true, sort: 210},
  					{id: 'InsertImage', compact: true, sort: 220},
  					{id: 'InsertVideo', compact: true, sort: 230},
  					{id: 'InsertAnchor', compact: false, sort: 240},
  					{id: 'InsertTable', compact: false, sort: 250},
  					{id: 'InsertChar', compact: false, hidden: true, sort: 260},
  					{id: 'PrintBreak', compact: false, hidden: true, sort: 270},
  					{id: 'PageBreak', compact: false, hidden: true, sort: 275},
  					{id: 'Spellcheck', compact: false, hidden: true, sort: 280},
  					{id: 'InsertHr', compact: false, hidden: true, sort: 290},
  					{id: 'Sub', compact: false, hidden: true, sort: 310},
  					{id: 'Sup', compact: false, hidden: true, sort: 320},
  					{id: 'TemplateSelector', compact: false, sort: 330},
  					{id: 'Fullscreen', compact: true, sort: 340},
  
  					{id: 'More', compact: true, sort: 400},
  					{id: 'Settings',  wrap: 'right', compact: true, sort: 500}
  				];
  			}
  
  			this.editor.On("GetControlsMap", [res]);
  			res = res.sort(function(a, b){return a.sort - b.sort});
  			this.controlsMap = res;
  			return res;
  		},
  
  		GetSeparator: function()
  		{
  			return BX.create('span', {props: {className: 'bxhtmled-top-bar-separator'}});
  		},
  
  		GetHeight: function()
  		{
  			var res = 0;
  			if (this.shown)
  			{
  				if (!this.height)
  					this.height = parseInt(this.editor.dom.toolbarCont.offsetHeight);
  
  				res = this.height;
  			}
  			return res;
  		},
  
  		DisableWysiwygButtons: function(bDisable)
  		{
  			bDisable = bDisable !== false;
  			for (var i in this.controls)
  			{
  				if (this.controls.hasOwnProperty(i) && typeof this.controls[i].Disable == 'function' && this.controls[i].disabledForTextarea !== false)
  					this.controls[i].Disable(bDisable);
  			}
  		},
  
  		EnableWysiwygButtons: function()
  		{
  			this.DisableWysiwygButtons(false);
  		},
  
  		AdaptControls: function(width)
  		{
  			var bCompact = width < this.editor.normalWidth;
  			if (this.controls.More)
  			{
  				if (bCompact || this.showMoreButton)
  				{
  					this.controls.More.GetCont().style.display = '';
  				}
  				else
  				{
  					this.controls.More.GetCont().style.display = 'none';
  				}
  				this.controls.More.Close();
  			}
  
  			if (!bCompact && this.showMoreButton)
  			{
  				var moreCont = this.controls.More.GetPopupCont();
  				while (this.hiddenWrap.firstChild)
  				{
  					moreCont.appendChild(this.hiddenWrap.firstChild);
  				}
  			}
  
  			if (this.bCompact != bCompact)
  			{
  				this.bCompact = bCompact;
  				this.BuildControls();
  			}
  		},
  
  		Hide: function()
  		{
  			this.shown = false;
  			this.editor.dom.toolbarCont.style.display = 'none';
  			this.editor.ResizeSceleton();
  		},
  
  		Show: function()
  		{
  			this.shown = true;
  			this.editor.dom.toolbarCont.style.display = '';
  			this.editor.ResizeSceleton();
  		},
  
  		IsShown: function()
  		{
  			return this.shown;
  		}
  	};
  
  	function NodeNavi(editor)
  	{
  		this.editor = editor;
  		this.bShown = false;
  		this.pCont = editor.dom.navCont;
  		this.controls = {};
  		this.height = 28;
  		this.Init();
  	}
  
  	NodeNavi.prototype = {
  		Init: function()
  		{
  			BX.addCustomEvent(this.editor, "OnIframeMouseDown", BX.proxy(this.OnIframeMousedown, this));
  			BX.addCustomEvent(this.editor, "OnIframeKeyup", BX.proxy(this.OnIframeKeyup, this));
  			BX.addCustomEvent(this.editor, "OnTextareaFocus", BX.delegate(this.Disable, this));
  			BX.addCustomEvent(this.editor, "OnHtmlContentChangedByControl", BX.delegate(this.OnIframeKeyup, this));
  			BX.bind(this.pCont, 'click', BX.delegate(this.ShowMenu, this));
  
  			var _this = this;
  
  			this.items = {
  				// Surrogates
  				'php' : function(node, bxTag)
  				{
  					_this.editor.GetDialog('Source').Show(bxTag);
  				},
  				'anchor' : function(node, bxTag)
  				{
  					_this.editor.GetDialog('Anchor').Show(bxTag);
  				},
  				'javascript' : function(node, bxTag)
  				{
  					_this.editor.GetDialog('Source').Show(bxTag);
  				},
  				'htmlcomment' : function(node, bxTag)
  				{
  					_this.editor.GetDialog('Source').Show(bxTag);
  				},
  				'iframe' : function(node, bxTag)
  				{
  					_this.editor.GetDialog('Source').Show(bxTag);
  				},
  				'style' : function(node, bxTag)
  				{
  					_this.editor.GetDialog('Source').Show(bxTag);
  				},
  				'video' : function(node, bxTag)
  				{
  					_this.editor.GetDialog('Video').Show(bxTag);
  				},
  				'component' : function(node, bxTag)
  				{
  					_this.editor.components.ShowPropertiesDialog(bxTag.params, _this.editor.GetBxTag(bxTag.surrogateId));
  				},
  				'printbreak' : false,
  
  				// Nodes
  				'A' : function(node)
  				{
  					_this.editor.GetDialog('Link').Show([node]);
  				},
  				'IMG' : function(node)
  				{
  					_this.editor.GetDialog('Image').Show([node]);
  				},
  				'TABLE' : function(node)
  				{
  					_this.editor.GetDialog('Table').Show([node]);
  				},
  				'DEFAULT' : function(node)
  				{
  					_this.editor.GetDialog('Default').Show([node]);
  				}
  			};
  		},
  
  		Show: function(bShow)
  		{
  			this.bShown = bShow = bShow !== false;
  			this.pCont.style.display = bShow ? 'block' : 'none';
  		},
  
  		GetHeight: function()
  		{
  			if (!this.bShown)
  				return 0;
  
  			if (!this.height)
  				this.height = parseInt(this.pCont.offsetHeight);
  
  			return this.height;
  		},
  
  		OnIframeMousedown: function(e, target, bxTag)
  		{
  			this.BuildNavi(target);
  		},
  
  		OnIframeKeyup: function(e, keyCode, target)
  		{
  			this.BuildNavi(target);
  		},
  
  		BuildNavi: function(node)
  		{
  			BX.cleanNode(this.pCont);
  			if (!node)
  			{
  				node = this.editor.GetIframeDoc().body;
  			}
  			this.nodeIndex = [];
  			var itemCont, label, bxTag;
  			while (node)
  			{
  				if (node.nodeType != 3)
  				{
  					bxTag = this.editor.GetBxTag(node);
  					if (bxTag.tag)
  					{
  						if (bxTag.tag == "surrogate_dd")
  						{
  							node = node.parentNode;
  							continue;
  						}
  
  						BX.cleanNode(this.pCont);
  						this.nodeIndex = [];
  
  						label = bxTag.name || bxTag.tag;
  					}
  					else
  					{
  						label = node.nodeName;
  					}
  
  					itemCont = BX.create("SPAN", {props: {className: "bxhtmled-nav-item"}, text: label});
  					itemCont.setAttribute('data-bx-node-ind', this.nodeIndex.length.toString());
  
  					this.nodeIndex.push({node: node, bxTag: bxTag.tag});
  
  					if (this.pCont.firstChild)
  					{
  						this.pCont.insertBefore(itemCont, this.pCont.firstChild);
  						if(!this.AdjustSize())
  						{
  							break;
  						}
  					}
  					else
  					{
  						this.pCont.appendChild(itemCont);
  					}
  				}
  				if (node.nodeName && node.nodeName.toUpperCase() == 'BODY')
  				{
  					break;
  				}
  				node = node.parentNode;
  			}
  
  			this.AdjustSize();
  		},
  
  		AdjustSize: function()
  		{
  			if (this.pCont.lastChild && this.pCont.lastChild.offsetTop > 0)
  			{
  				BX.remove(this.pCont.firstChild);
  				return false;
  			}
  			return true;
  		},
  
  		ShowMenu: function(e)
  		{
  			if (!this.nodeIndex)
  			{
  				return;
  			}
  
  			var
  				_this = this,
  				nodeIndex,
  				origNode,
  				target;
  
  			if (e.target)
  			{
  				target = e.target;
  			}
  			else if (e.srcElement)
  			{
  				target = e.srcElement;
  			}
  			if (target.nodeType == 3)
  			{
  				target = target.parentNode;
  			}
  
  			if (target)
  			{
  				nodeIndex = target.getAttribute('data-bx-node-ind');
  				if (!this.nodeIndex[nodeIndex])
  				{
  					target = BX.findParent(target, function(node)
  					{
  						return node == _this.pCont || (node.getAttribute && node.getAttribute('data-bx-node-ind') >= 0);
  					}, this.pCont);
  					nodeIndex = target.getAttribute('data-bx-node-ind')
  				}
  
  				if (this.nodeIndex[nodeIndex])
  				{
  					var id = 'bx_node_nav_' + Math.round(Math.random() * 1000000000);
  					origNode = this.nodeIndex[nodeIndex].node;
  
  					var arItems = [];
  					if (origNode.nodeName && origNode.nodeName.toUpperCase() != 'BODY')
  					{
  						if (!this.nodeIndex[nodeIndex].bxTag || !this.editor.phpParser.surrogateTags[this.nodeIndex[nodeIndex].bxTag])
  						{
  							arItems.push({
  								text : BX.message('NodeSelect'),
  								title : BX.message('NodeSelect'),
  								className : "",
  								onclick: function()
  								{
  									_this.editor.action.Exec('selectNode', origNode);
  									this.popupWindow.close();
  									this.popupWindow.destroy();
  								}
  							});
  						}
  
  						arItems.push({
  							text : BX.message('NodeRemove'),
  							title : BX.message('NodeRemove'),
  							className : "",
  							onclick: function()
  							{
  								if (origNode && origNode.parentNode)
  								{
  									_this.BuildNavi(origNode.parentNode);
  									_this.editor.selection.RemoveNode(origNode);
  								}
  								this.popupWindow.close();
  								this.popupWindow.destroy();
  							}
  						});
  
  						var showProps = !(this.nodeIndex[nodeIndex] && this.nodeIndex[nodeIndex].bxTag && this.items[this.nodeIndex[nodeIndex].bxTag] == false);
  						if (showProps)
  						{
  							arItems.push({
  								text : BX.message('NodeProps'),
  								title : BX.message('NodeProps'),
  								className : "",
  								onclick: function()
  								{
  									_this.ShowNodeProperties(origNode);
  									this.popupWindow.close();
  									this.popupWindow.destroy();
  								}
  							});
  						}
  					}
  					else
  					{
  						arItems = [
  							{
  								text : BX.message('NodeSelectBody'),
  								title : BX.message('NodeSelectBody'),
  								className : "",
  								onclick: function()
  								{
  									_this.editor.iframeView.CheckContentLastChild();
  									_this.editor.action.Exec('selectNode', origNode);
  									_this.editor.Focus();
  									this.popupWindow.close();
  									this.popupWindow.destroy();
  								}
  							},
  							{
  								text : BX.message('NodeRemoveBodyContent'),
  								title : BX.message('NodeRemoveBodyContent'),
  								className : "",
  								onclick: function()
  								{
  									_this.BuildNavi(origNode);
  									_this.editor.On('OnHtmlContentChangedByControl');
  									_this.editor.iframeView.Clear();
  									_this.editor.util.Refresh(origNode);
  									_this.editor.synchro.FullSyncFromIframe();
  									_this.editor.Focus();
  
  									this.popupWindow.close();
  									this.popupWindow.destroy();
  								}
  							}
  						];
  					}
  
  
  					BX.PopupMenu.show(id + "_menu", target, arItems, {
  							overlay: {opacity: 1},
  							events: {
  								onPopupClose: function()
  								{
  									//BX.removeClass(this.bindElement, "bxec-add-more-over");
  								}
  							},
  							offsetLeft: 1,
  							zIndex: 4000,
  							bindOptions: { position: "top" }
  						}
  					);
  				}
  			}
  		},
  
  		ShowNodeProperties: function(node)
  		{
  			var bxTag, key;
  			if (node.nodeName && node.nodeType == 1)
  			{
  				bxTag = this.editor.GetBxTag(node);
  				key = bxTag.tag ? bxTag.tag : node.nodeName;
  
  				if (this.items[key] && typeof this.items[key] == 'function')
  				{
  					this.items[key](node, bxTag);
  				}
  				else
  				{
  					this.items['DEFAULT'](node, bxTag);
  				}
  			}
  		},
  
  		// TODO: hide it ??
  		Disable: function()
  		{
  			this.BuildNavi(false);
  		},
  
  		Enable: function()
  		{
  		}
  	};
  
  	function Overlay(editor, params)
  	{
  		this.editor = editor;
  		this.id = 'bxeditor_overlay' + this.editor.id;
  		this.zIndex = params && params.zIndex ? params.zIndex : 3001;
  	}
  
  	Overlay.prototype =
  	{
  		Create: function ()
  		{
  			this.bCreated = true;
  			this.bShown = false;
  			var ws = BX.GetWindowScrollSize();
  			this.pWnd = document.body.appendChild(BX.create("DIV", {props: {id: this.id, className: "bxhtmled-overlay"}, style: {zIndex: this.zIndex, width: ws.scrollWidth + "px", height: ws.scrollHeight + "px"}}));
  			this.pWnd.ondrag = BX.False;
  			this.pWnd.onselectstart = BX.False;
  		},
  
  		Show: function(arParams)
  		{
  			if (!this.bCreated)
  				this.Create();
  			this.bShown = true;
  			if (this.shownTimeout)
  			{
  				this.shownTimeout = clearTimeout(this.shownTimeout);
  			}
  			var ws = BX.GetWindowScrollSize();
  			this.pWnd.style.display = 'block';
  			this.pWnd.style.width = ws.scrollWidth + "px";
  			this.pWnd.style.height = ws.scrollHeight + "px";
  
  			if (!arParams)
  			{
  				arParams = {};
  			}
  
  			this.pWnd.style.zIndex = arParams.zIndex || this.zIndex;
  
  			BX.bind(window, "resize", BX.proxy(this.Resize, this));
  			return this.pWnd;
  		},
  
  		Hide: function ()
  		{
  			if (!this.bShown)
  			{
  				return;
  			}
  			var _this = this;
  			_this.shownTimeout = setTimeout(function(){_this.bShown = false;}, 300);
  			this.pWnd.style.display = 'none';
  			BX.unbind(window, "resize", BX.proxy(this.Resize, this));
  			this.pWnd.onclick = null;
  		},
  
  		Resize: function ()
  		{
  			if (this.bCreated)
  			{
  				var ws = BX.GetWindowScrollSize();
  				this.pWnd.style.width = ws.scrollWidth + "px";
  				this.pWnd.style.height = ws.scrollHeight + "px";
  			}
  		}
  	}
  
  	function Button(editor)
  	{
  		this.editor = editor;
  		this.className = 'bxhtmled-top-bar-btn';
  		this.activeClassName = 'bxhtmled-top-bar-btn-active';
  		this.disabledClassName = 'bxhtmled-top-bar-btn-disabled';
  		this.checkableAction = true;
  		this.disabledForTextarea = true;
  	}
  
  	Button.prototype = {
  		Create: function ()
  		{
  			this.pCont = BX.create("SPAN", {props: {className: this.className, title: this.title || ''}, html: '<i></i>'});
  			BX.bind(this.pCont, "click", BX.delegate(this.OnClick, this));
  			BX.bind(this.pCont, "mousedown", BX.delegate(this.OnMouseDown, this));
  			BX.bind(this.pCont, "dblclick", function(e){return BX.PreventDefault(e);});
  
  			if (this.action)
  			{
  				this.pCont.setAttribute('data-bx-type', 'action');
  				this.pCont.setAttribute('data-bx-action', this.action);
  				if (this.value)
  					this.pCont.setAttribute('data-bx-value', this.value);
  
  				if (this.checkableAction)
  				{
  					this.editor.RegisterCheckableAction(this.action, {
  						action: this.action,
  						control: this,
  						value: this.value
  					});
  				}
  			}
  		},
  
  		GetCont: function()
  		{
  			return this.pCont;
  		},
  
  		Check: function (bFlag)
  		{
  			if(bFlag == this.checked || this.disabled)
  				return;
  
  			this.checked = bFlag;
  			if(this.checked)
  			{
  				BX.addClass(this.pCont, this.activeClassName);
  			}
  			else
  			{
  				BX.removeClass(this.pCont, this.activeClassName);
  			}
  		},
  
  		Disable: function(bFlag)
  		{
  			if(bFlag != this.disabled)
  			{
  				this.disabled = !!bFlag;
  				if(bFlag)
  				{
  					if (this.action)
  					{
  						this.pCont.setAttribute('data-bx-type', '');
  					}
  					BX.addClass(this.pCont, this.disabledClassName);
  				}
  				else
  				{
  					if (this.action)
  					{
  						this.pCont.setAttribute('data-bx-type', 'action');
  					}
  					BX.removeClass(this.pCont, this.disabledClassName);
  				}
  			}
  		},
  
  		OnClick: BX.DoNothing,
  		OnMouseUp: function()
  		{
  			if(!this.checked)
  			{
  				BX.removeClass(this.pCont, this.activeClassName);
  			}
  			BX.unbind(document, 'mouseup', BX.proxy(this.OnMouseUp, this));
  			BX.removeCustomEvent(this.editor, "OnIframeMouseUp", BX.proxy(this.OnMouseUp, this));
  
  			if (this.editor.toolbar && this.editor.toolbar.controls && this.editor.toolbar.controls.More)
  			{
  				this.editor.toolbar.controls.More.Close();
  			}
  		},
  
  		OnMouseDown: function()
  		{
  			if (!this.disabled)
  			{
  				if (this.disabledForTextarea || !this.editor.synchro.IsFocusedOnTextarea())
  				{
  					this.savedRange = this.editor.selection.SaveBookmark();
  				}
  				BX.addClass(this.pCont, this.activeClassName);
  				BX.bind(document, 'mouseup', BX.proxy(this.OnMouseUp, this));
  				BX.addCustomEvent(this.editor, "OnIframeMouseUp", BX.proxy(this.OnMouseUp, this));
  			}
  		},
  
  		GetValue: function()
  		{
  			return !!this.checked;
  		},
  
  		SetValue: function(value)
  		{
  			this.Check(value);
  		}
  	};
  
  	// List
  	function DropDown(editor)
  	{
  		this.editor = editor;
  		this.className = 'bxhtmled-top-bar-btn';
  		this.activeClassName = 'bxhtmled-top-bar-btn-active';
  		this.activeListClassName = 'bxhtmled-top-bar-btn-active';
  		this.arValues = [];
  		this.checkableAction = true;
  		this.disabledForTextarea = true;
  		this.posOffset = {top: 6, left: -4};
  		this.zIndex = 3005;
  	}
  
  	DropDown.prototype = {
  		Create: function ()
  		{
  			this.pCont = BX.create("SPAN", {props: {className: this.className}, html: '<i></i>'});
  			this.pValuesCont = BX.create("DIV", {props: {className: "bxhtmled-popup bxhtmled-dropdown-cont"}, html: '<div class="bxhtmled-popup-corner"></div>'});
  			if (this.title)
  			{
  				this.pCont.title = this.title;
  			}
  
  			if(this.zIndex)
  			{
  				this.pValuesCont.style.zIndex = this.zIndex;
  			}
  
  			this.valueIndex = {};
  			this.pValuesContWrap = this.pValuesCont.appendChild(BX.create("DIV"));
  			var but, value, _this = this;
  			for (var i = 0; i < this.arValues.length; i++)
  			{
  				value = this.arValues[i];
  				but = this.pValuesContWrap.appendChild(BX.create("SPAN", {props: {title: value.title, className: value.className}, html: '<i></i>'}));
  				but.setAttribute('data-bx-dropdown-value', value.id);
  				this.valueIndex[value.id] = i;
  
  				if (value.action)
  				{
  					but.setAttribute('data-bx-type', 'action');
  					but.setAttribute('data-bx-action', value.action);
  					if (value.value)
  					{
  						but.setAttribute('data-bx-value', value.value);
  					}
  				}
  
  				BX.bind(but, 'mousedown', function(e)
  				{
  					_this.SelectItem(this.getAttribute('data-bx-dropdown-value'));
  					_this.editor.CheckCommand(this);
  					_this.Close();
  				});
  
  				this.arValues[i].listCont = but;
  			}
  
  			if (this.action && this.checkableAction)
  			{
  				this.editor.RegisterCheckableAction(this.action, {
  					action: this.action,
  					control: this
  				});
  			}
  
  			BX.bind(this.pCont, 'click', BX.proxy(this.OnClick, this));
  			BX.bind(this.pCont, "mousedown", BX.delegate(this.OnMouseDown, this));
  		},
  
  		GetCont: function()
  		{
  			return this.pCont;
  		},
  
  		GetPopupBindCont: function()
  		{
  			return this.pCont;
  		},
  
  		Disable: function(bFlag)
  		{
  			if(bFlag != this.disabled)
  			{
  				this.disabled = !!bFlag;
  				if(bFlag)
  				{
  					BX.addClass(this.pCont, 'bxhtmled-top-bar-btn-disabled');
  				}
  				else
  				{
  					BX.removeClass(this.pCont, 'bxhtmled-top-bar-btn-disabled');
  				}
  			}
  		},
  
  		OnKeyDown: function(e)
  		{
  			if(e.keyCode == 27)
  			{
  				this.Close();
  			}
  		},
  
  		OnClick: function()
  		{
  			if(!this.disabled)
  			{
  				if (this.bOpened)
  				{
  					this.Close();
  				}
  				else
  				{
  					this.Open();
  				}
  			}
  		},
  
  		OnMouseUp: function()
  		{
  			this.editor.selection.RestoreBookmark();
  			if(!this.checked)
  			{
  				BX.removeClass(this.pCont, this.activeClassName);
  			}
  			BX.unbind(document, 'mouseup', BX.proxy(this.OnMouseUp, this));
  			BX.removeCustomEvent(this.editor, "OnIframeMouseUp", BX.proxy(this.OnMouseUp, this));
  		},
  
  		OnMouseDown: function()
  		{
  			if (!this.disabled)
  			{
  				if (this.disabledForTextarea || !this.editor.synchro.IsFocusedOnTextarea())
  				{
  					this.savedRange = this.editor.selection.SaveBookmark();
  				}
  
  				BX.addClass(this.pCont, this.activeClassName);
  				BX.bind(document, 'mouseup', BX.proxy(this.OnMouseUp, this));
  				BX.addCustomEvent(this.editor, "OnIframeMouseUp", BX.proxy(this.OnMouseUp, this));
  			}
  		},
  
  		Close: function ()
  		{
  			var _this = this;
  			this.popupShownTimeout = setTimeout(function(){_this.editor.popupShown = false;}, 300);
  			BX.removeClass(this.pCont, this.activeClassName);
  			this.pValuesCont.style.display = 'none';
  			this.editor.overlay.Hide();
  
  			BX.unbind(window, "keydown", BX.proxy(this.OnKeyDown, this));
  			BX.unbind(document, 'mousedown', BX.proxy(this.CheckClose, this));
  
  			BX.onCustomEvent(this, "OnPopupClose");
  
  			this.bOpened = false;
  		},
  
  		CheckClose: function(e)
  		{
  			if (!this.bOpened)
  			{
  				return BX.unbind(document, 'mousedown', BX.proxy(this.CheckClose, this));
  			}
  
  			var pEl;
  			if (e.target)
  				pEl = e.target;
  			else if (e.srcElement)
  				pEl = e.srcElement;
  			if (pEl.nodeType == 3)
  				pEl = pEl.parentNode;
  
  			if (!BX.findParent(pEl, {className: 'bxhtmled-popup'}))
  			{
  				this.Close();
  			}
  		},
  
  		Open: function ()
  		{
  			this.editor.popupShown = true;
  			if (this.popupShownTimeout)
  			{
  				this.popupShownTimeout = clearTimeout(this.popupShownTimeout);
  			}
  			document.body.appendChild(this.pValuesCont);
  			this.pValuesCont.style.display = 'block';
  			BX.addClass(this.pCont, this.activeClassName);
  			var
  				pOverlay = this.editor.overlay.Show({zIndex: this.zIndex - 1}),
  				bindCont = this.GetPopupBindCont(),
  				pos = BX.pos(bindCont),
  				left = Math.round(pos.left - this.pValuesCont.offsetWidth / 2 + bindCont.offsetWidth / 2 + this.posOffset.left),
  				top = Math.round(pos.bottom + this.posOffset.top),
  				_this = this;
  
  			BX.bind(window, "keydown", BX.proxy(this.OnKeyDown, this));
  			pOverlay.onclick = function(){_this.Close()};
  
  			this.pValuesCont.style.top = top + 'px';
  			this.pValuesCont.style.left = left + 'px';
  			this.bOpened = true;
  
  			setTimeout(function()
  			{
  				BX.bind(document, 'mousedown', BX.proxy(_this.CheckClose, _this));
  			},100);
  		},
  
  		SelectItem: function(id, val)
  		{
  			if (!val)
  				val = this.arValues[this.valueIndex[id]];
  
  			if (this.lastActiveItem)
  				BX.removeClass(this.lastActiveItem, this.activeListClassName);
  
  			if (val)
  			{
  				// Select value in list as active
  				if (val.listCont)
  				{
  					this.lastActiveItem = val.listCont;
  					BX.addClass(val.listCont, this.activeListClassName);
  				}
  
  				this.pCont.className = val.className;
  				this.pCont.title = BX.util.htmlspecialchars(val.title || val.name || '');
  			}
  			else
  			{
  				this.pCont.className = this.className;
  				this.pCont.title = this.title;
  			}
  
  			if (this.disabled)
  			{
  				this.disabled = false;
  				this.Disable(true);
  			}
  
  			return val;
  		},
  
  		SetValue: function()
  		{
  		},
  
  		GetValue: function()
  		{
  		}
  	};
  
  	function DropDownList(editor)
  	{
  		// Call parrent constructor
  		DropDownList.superclass.constructor.apply(this, arguments);
  		this.className = 'bxhtmled-top-bar-select';
  		this.itemClassName = 'bxhtmled-dd-list-item';
  		this.activeListClassName = 'bxhtmled-dd-list-item-active';
  		this.disabledForTextarea = true;
  	}
  	BX.extend(DropDownList, DropDown);
  
  	DropDownList.prototype.Create = function ()
  	{
  		this.pCont = BX.create("SPAN", {props: {className: this.className, title: this.title}, attrs: {unselectable: 'on'}, text: ''});
  		if (this.width)
  			this.pCont.style.width = this.width + 'px';
  
  		this.pValuesCont = BX.create("DIV", {props: {className: "bxhtmled-popup bxhtmled-dropdown-list-cont"}, html: '<div class="bxhtmled-popup-corner"></div>'});
  		this.pValuesContWrap = this.pValuesCont.appendChild(BX.create("DIV", {props: {className: "bxhtmled-dd-list-wrap"}}));
  		this.valueIndex = {};
  
  		if(this.zIndex)
  		{
  			this.pValuesCont.style.zIndex = this.zIndex;
  		}
  
  		var but, value, _this = this, itemClass, i, html;
  		for (i = 0; i < this.arValues.length; i++)
  		{
  			value = this.arValues[i];
  			itemClass = this.itemClassName;
  			if (value.className)
  				itemClass += ' ' + value.className;
  
  			html = value.tagName ? ('<' + value.tagName + '>' + value.name + '</' + value.tagName + '>') : value.name;
  			but = this.pValuesContWrap.appendChild(BX.create("SPAN", {props: {title: value.title || value.name, className: itemClass}, html: html, style: value.style}));
  
  			but.setAttribute('data-bx-dropdown-value', value.id);
  			this.valueIndex[value.id] = i;
  
  			if (value.defaultValue)
  				this.SelectItem(null, value);
  
  			if (value.action)
  			{
  				but.setAttribute('data-bx-type', 'action');
  				but.setAttribute('data-bx-action', value.action);
  				if (value.value)
  					but.setAttribute('data-bx-value', value.value);
  			}
  
  			BX.bind(but, 'mousedown', function(e)
  			{
  				if (!e)
  					e = window.event;
  				_this.SelectItem(this.getAttribute('data-bx-dropdown-value'));
  				_this.editor.CheckCommand(this);
  			});
  
  			this.arValues[i].listCont = but;
  		}
  
  		if (this.action && this.checkableAction)
  		{
  			this.editor.RegisterCheckableAction(this.action, {
  				action: this.action,
  				control: this
  			});
  		}
  
  		BX.bind(this.pCont, 'click', BX.proxy(this.OnClick, this));
  	};
  
  	DropDownList.prototype.SelectItem = function (valDropdown, val, bClose)
  	{
  		bClose = bClose !== false;
  		if (!val)
  		{
  			val = this.arValues[this.valueIndex[valDropdown]];
  		}
  
  		if (this.lastActiveItem)
  		{
  			BX.removeClass(this.lastActiveItem, this.activeListClassName);
  		}
  
  		if (val)
  		{
  			this.pCont.innerHTML = BX.util.htmlspecialchars((val.topName || val.name || val.id));
  			this.pCont.title = this.title + ': ' + BX.util.htmlspecialchars(val.title || val.name);
  
  
  			// Select value in list as active
  			if (val.listCont)
  			{
  				this.lastActiveItem = val.listCont;
  				BX.addClass(val.listCont, this.activeListClassName);
  			}
  		}
  
  		if (this.bOpened && bClose)
  		{
  			this.Close();
  		}
  	};
  
  	DropDownList.prototype.SetValue = function(active, state)
  	{
  	};
  
  	DropDownList.prototype.SetWidth = function(width)
  	{
  		width = parseInt(width, 10);
  		if (width)
  		{
  			this.width = width;
  			this.pCont.style.width = width + 'px';
  		}
  	};
  
  	DropDownList.prototype.Disable = function(bFlag)
  	{
  		if(bFlag != this.disabled)
  		{
  			this.disabled = !!bFlag;
  			if(bFlag)
  			{
  				BX.addClass(this.pCont, 'bxhtmled-top-bar-select-disabled');
  			}
  			else
  			{
  				BX.removeClass(this.pCont, 'bxhtmled-top-bar-select-disabled');
  			}
  		}
  	};
  
  	// Combobox with multiple choice of values
  	function ComboBox(editor, params)
  	{
  		this.values = [];
  		this.pInput = params.input;
  		this.editor = editor;
  		this.value = params.value || '';
  		this.defaultValue = params.defaultValue || '';
  		this.posOffset = {top: 8, left: -4};
  		this.zIndex = 3010;
  		this.SPLIT_SYMBOL = ',';
  		this.itemClassName = 'bxhtmled-dd-list-item';
  		this.itemClassNameActive = 'bxhtmled-dd-list-item-active';
  	}
  
  	ComboBox.prototype = {
  		Init: function()
  		{
  			BX.bind(this.pInput, 'focus', BX.proxy(this.Focus, this));
  			BX.bind(this.pInput, 'click', BX.proxy(this.Focus, this));
  			BX.bind(this.pInput, 'blur', BX.proxy(this.Blur, this));
  			BX.bind(this.pInput, 'keyup', BX.proxy(this.KeyUp, this));
  
  			this.visibleItemsLength = this.values.length;
  			this.currentItem = false;
  		},
  
  		UpdateValues: function(values)
  		{
  			this.bCreated = false;
  			this.values = values;
  			this.visibleItemsLength = this.values.length;
  			this.currentItem = false;
  			if (this.bOpened)
  			{
  				this.ClosePopup();
  			}
  		},
  
  		Create: function()
  		{
  			this.pValuesCont = BX.create("DIV", {props: {className: "bxhtmled-popup bxhtmled-combo-cont"}, html: '<div class="bxhtmled-popup-corner"></div>'});
  			this.pValuesCont.style.zIndex = this.zIndex;
  
  			if (this.pValuesContWrap)
  			{
  				BX.cleanNode(this.pValuesContWrap);
  				this.pValuesCont.appendChild(this.pValuesContWrap);
  			}
  			else
  			{
  				this.pValuesContWrap = this.pValuesCont.appendChild(BX.create("DIV", {props: {className: "bxhtmled-dd-list-wrap"}}));
  
  				BX.bind(this.pValuesContWrap, 'mousedown', function(e)
  				{
  					var target = e.target || e.srcElement;
  					if (!target.getAttribute('data-bx-dropdown-value'))
  					{
  						target = BX.findParent(target, function(n)
  						{
  							return n.getAttribute && n.getAttribute('data-bx-dropdown-value');
  						}, _this.pValuesContWrap);
  					}
  
  					if (target)
  					{
  						_this.currentItem = parseInt(target.getAttribute('data-bx-dropdown-value'), 10);
  						_this.SetValueFromList();
  					}
  
  					_this.ClosePopup();
  				});
  			}
  			this.valueIndex = {};
  
  			var but, value, _this = this, itemClass, i, html;
  			for (i = 0; i < this.values.length; i++)
  			{
  				value = this.values[i];
  				itemClass = this.itemClassName || '';
  				this.values[i].TITLE = this.values[i].TITLE || this.values[i].NAME;
  
  				if (this.values[i].VALUE && this.values[i].VALUE !== this.values[i].TITLE)
  				{
  					this.values[i].TITLE += ' (' + this.values[i].VALUE + ')';
  				}
  				else
  				{
  					this.values[i].VALUE = this.values[i].NAME;
  				}
  
  				but = this.pValuesContWrap.appendChild(BX.create("SPAN", {props: {className: itemClass}, html: value.TITLE}));
  				but.setAttribute('data-bx-dropdown-value', i);
  				this.values[i].cont = but;
  			}
  
  			this.bCreated = true;
  		},
  
  		KeyUp: function(e)
  		{
  			var keyCode = e.keyCode;
  			if (keyCode == this.editor.KEY_CODES['down'])
  			{
  				this.SelectItem(1);
  			}
  			else if (keyCode == this.editor.KEY_CODES['up'])
  			{
  				this.SelectItem(-1);
  			}
  			else if (keyCode == this.editor.KEY_CODES['escape'])
  			{
  				if (this.bOpened)
  				{
  					this.ClosePopup();
  					return BX.PreventDefault(e);
  				}
  			}
  			else if (keyCode == this.editor.KEY_CODES['enter'])
  			{
  				if (this.bOpened)
  				{
  					this.SetValueFromList();
  					this.ClosePopup();
  					return BX.PreventDefault(e);
  				}
  			}
  			else
  			{
  				this.FilterValue();
  			}
  		},
  
  		FilterValue: function()
  		{
  			// Range
  			var
  				i, val,
  				splitedVals = this.GetSplitedValues(),
  				caretPos = this.GetCaretPos(this.pInput);
  
  			for (i = 0; i < splitedVals.length; i++)
  			{
  				val = splitedVals[i];
  				if (caretPos >= val.start && caretPos <= val.end)
  				{
  					break;
  				}
  			}
  
  			// Filter values && highlight values
  			this.FilterAndHighlight(val.value);
  		},
  
  		GetSplitedValues: function()
  		{
  			var
  				arVals, i, gStart, gEnd, val,
  				res = [],
  				str = this.pInput.value;
  
  			if (str.indexOf(this.SPLIT_SYMBOL) === -1 || this.bMultiple === false)
  			{
  				res.push(
  					{
  						start: 0,
  						end: str.length,
  						value: BX.util.trim(str)
  					}
  				);
  			}
  			else
  			{
  				arVals = str.split(this.SPLIT_SYMBOL);
  				gStart = 0;
  				gEnd = 0;
  				for (i = 0; i < arVals.length; i++)
  				{
  					val = arVals[i];
  					gEnd += val.length + i;
  					res.push(
  						{
  							start: gStart,
  							end: gEnd,
  							value: BX.util.trim(val)
  						}
  					);
  					gStart = gEnd;
  				}
  			}
  
  			return res;
  		},
  
  		FilterAndHighlight: function(needle)
  		{
  			needle = BX.util.trim(needle);
  			var val, i, showPopup = false, pos;
  
  			this.visibleItemsLength = 0;
  			for (i = 0; i < this.values.length; i++)
  			{
  				val = this.values[i];
  				if (needle === '')
  				{
  					showPopup = true;
  					val.cont.style.display = '';
  					this.visibleItemsLength++;
  				}
  				else
  				{
  					pos = val.TITLE.toLowerCase().indexOf(needle.toLowerCase());
  					if (pos !== -1 || needle == '')
  					{
  						val.cont.innerHTML = BX.util.htmlspecialchars(val.TITLE.substr(0, pos)) + '<b>' + BX.util.htmlspecialchars(needle) + '</b>' + BX.util.htmlspecialchars(val.TITLE.substr(pos + needle.length));
  						showPopup = true;
  						val.cont.style.display = '';
  						val.cont.setAttribute('data-bx-dropdown-value', this.visibleItemsLength);
  						this.visibleItemsLength++;
  					}
  					else
  					{
  						val.cont.innerHTML = BX.util.htmlspecialchars(val.TITLE);
  						val.cont.style.display = 'none';
  					}
  				}
  			}
  
  			this.currentItem = false;
  
  			if (showPopup && !this.bOpened)
  			{
  				this.ShowPopup();
  			}
  			else if (!showPopup && this.bOpened)
  			{
  				this.ClosePopup();
  			}
  		},
  
  		GetCaretPos: function(input)
  		{
  			var caretPos = 0;
  
  			// IE Support
  			if (document.selection)
  			{
  				BX.focus(input);
  				var oSel = document.selection.createRange();
  				oSel.moveStart ('character', - input.value.length);
  				// The caret position is selection length
  				caretPos = oSel.text.length;
  			}
  			else if (input.selectionStart || input.selectionStart == '0')
  			{
  				caretPos = input.selectionStart;
  			}
  			return (caretPos);
  		},
  
  		SetValue: function(value)
  		{
  			this.pInput.value = value;
  		},
  
  		SetValueFromList: function()
  		{
  			var ind = 0, val, i;
  			for (i = 0; i < this.values.length; i++)
  			{
  				val = this.values[i];
  				if (val.cont.style.display != 'none')
  				{
  					if (ind == this.currentItem)
  					{
  						BX.addClass(val.cont, this.itemClassNameActive);
  						break;
  					}
  					ind++;
  				}
  			}
  
  			var
  				splVal,
  				splitedVals = this.GetSplitedValues(),
  				caretPos = this.GetCaretPos(this.pInput);
  
  			for (i = 0; i < splitedVals.length; i++)
  			{
  				splVal = splitedVals[i];
  				if (caretPos >= splVal.start && caretPos <= splVal.end)
  				{
  					break;
  				}
  			}
  
  			var
  				glue = this.SPLIT_SYMBOL == ' ' ? ' ' : this.SPLIT_SYMBOL + ' ',
  				curValue = this.pInput.value,
  				before = curValue.substr(0, splVal.start),
  				after = curValue.substr(splVal.end);
  
  			before = before.replace(/^[\s\r\n\,]+/g, '').replace(/[\s\r\n\,]+$/g, '');
  			after = after.replace(/^[\s\r\n\,]+/g, '').replace(/[\s\r\n\,]+$/g, '');
  
  			this.pInput.value = before +
  				(before == '' ? '' : glue) +
  				val.VALUE +
  				(after == '' ? '' : glue) +
  				after;
  
  			this.FilterAndHighlight('');
  		},
  
  		SelectItem: function(delta)
  		{
  			var ind, val, i, len;
  			if (this.currentItem === false)
  			{
  				this.currentItem = 0;
  			}
  			else if(delta !== undefined)
  			{
  				this.currentItem += delta;
  
  				if (this.currentItem > this.visibleItemsLength - 1)
  				{
  					this.currentItem = 0;
  				}
  				else if(this.currentItem < 0)
  				{
  					this.currentItem = this.visibleItemsLength - 1;
  				}
  			}
  
  			if (document.querySelectorAll)
  			{
  				var selected = this.pValuesContWrap.querySelectorAll("." + this.itemClassNameActive);
  				if (selected)
  				{
  					for (i = 0; i < selected.length; i++)
  					{
  						BX.removeClass(selected[i], this.itemClassNameActive);
  					}
  				}
  			}
  
  			ind = 0;
  			len = this.values.length;
  			for (i = 0; i < this.values.length; i++)
  			{
  				val = this.values[i];
  				if (val.cont.style.display != 'none')
  				{
  					if (ind == this.currentItem)
  					{
  						BX.addClass(val.cont, this.itemClassNameActive);
  						break;
  					}
  					ind++;
  				}
  			}
  		},
  
  		Focus: function(e)
  		{
  			if (this.values.length > 0 && !this.bFocused)
  			{
  				BX.focus(this.pInput);
  				this.bFocused = true;
  				if (this.value == this.defaultValue)
  				{
  					this.value = '';
  				}
  
  				this.ShowPopup();
  			}
  		},
  
  		Blur: function()
  		{
  			if (this.values.length > 0 && this.bFocused)
  			{
  				this.bFocused = false;
  				this.ClosePopup();
  			}
  		},
  
  		ShowPopup: function()
  		{
  			if (!this.bCreated)
  			{
  				this.Create();
  			}
  
  			this.editor.popupShown = true;
  			if (this.popupShownTimeout)
  			{
  				this.popupShownTimeout = clearTimeout(this.popupShownTimeout);
  			}
  
  			document.body.appendChild(this.pValuesCont);
  			this.pValuesCont.style.display = 'block';
  
  			var
  				i,
  				pos = BX.pos(this.pInput),
  				left = pos.left + this.posOffset.left,
  				top = pos.bottom + this.posOffset.top;
  
  			this.pValuesCont.style.top = top + 'px';
  			this.pValuesCont.style.left = left + 'px';
  			this.bOpened = true;
  
  			if (document.querySelectorAll)
  			{
  				var selected = this.pValuesContWrap.querySelectorAll("." + this.itemClassNameActive);
  				if (selected)
  				{
  					for (i = 0; i < selected.length; i++)
  					{
  						BX.removeClass(selected[i], this.itemClassNameActive);
  					}
  				}
  			}
  
  			BX.onCustomEvent(this, "OnComboPopupOpen");
  		},
  
  		ClosePopup: function()
  		{
  			var _this = this;
  			this.popupShownTimeout = setTimeout(function(){_this.editor.popupShown = false;}, 300);
  			this.pValuesCont.style.display = 'none';
  			this.editor.overlay.Hide();
  
  			this.bOpened = false;
  			BX.onCustomEvent(this, "OnComboPopupClose");
  		},
  
  		OnChange: function()
  		{
  		},
  
  		CheckClose: function(e)
  		{
  			if (!this.bOpened)
  			{
  				return BX.unbind(document, 'mousedown', BX.proxy(this.CheckClose, this));
  			}
  
  			var pEl;
  			if (e.target)
  				pEl = e.target;
  			else if (e.srcElement)
  				pEl = e.srcElement;
  			if (pEl.nodeType == 3)
  				pEl = pEl.parentNode;
  
  			if (!BX.findParent(pEl, {className: 'bxhtmled-popup'}))
  				this.Close();
  		}
  	};
  
  	function ClassSelector(editor, params)
  	{
  		// Call parrent constructor
  		ClassSelector.superclass.constructor.apply(this, arguments);
  		this.filterTag = params.filterTag || '';
  		this.lastTemplateId = this.editor.GetTemplateId();
  		this.values = this.GetClasses();
  		this.SPLIT_SYMBOL = ' ';
  		this.Init();
  	}
  	BX.extend(ClassSelector, ComboBox);
  
  	ClassSelector.prototype.OnChange = function()
  	{
  		if (this.lastTemplateId != this.editor.GetTemplateId())
  		{
  			this.lastTemplateId = this.editor.GetTemplateId();
  			this.values = this.GetClasses();
  			this.bCreated = false;
  		}
  	};
  
  	ClassSelector.prototype.GetClasses = function()
  	{
  		var
  			title,
  			classes = this.editor.GetCurrentCssClasses(this.filterTag);
  
  		this.values = [];
  		if (classes && classes.length > 0)
  		{
  			for (var i = 0; i < classes.length; i++)
  			{
  				title = null;
  				if (classes[i].classTitle && typeof classes[i].classTitle == 'object')
  				{
  					if (classes[i].classTitle.title)
  					{
  						title = classes[i].classTitle.title;
  					}
  					else
  					{
  						continue;
  					}
  				}
  				else if (classes[i].classTitle)
  				{
  					title = classes[i].classTitle;
  				}
  
  				this.values.push(
  					{
  						VALUE: classes[i].className,
  						TITLE:  title,
  						NAME: classes[i].className
  					}
  				);
  			}
  		}
  		return this.values;
  	};
  
  	function __run()
  	{
  		window.BXHtmlEditor.TaskbarManager = TaskbarManager;
  		window.BXHtmlEditor.Taskbar = Taskbar;
  		window.BXHtmlEditor.ComponentsControl = ComponentsControl;
  		window.BXHtmlEditor.ContextMenu = ContextMenu;
  		window.BXHtmlEditor.Dialog = Dialog;
  		window.BXHtmlEditor.Toolbar = Toolbar;
  		window.BXHtmlEditor.NodeNavigator = NodeNavi;
  		window.BXHtmlEditor.Button = Button;
  		window.BXHtmlEditor.DropDown = DropDown;
  		window.BXHtmlEditor.DropDownList = DropDownList;
  		window.BXHtmlEditor.ComboBox = ComboBox;
  		window.BXHtmlEditor.ClassSelector = ClassSelector;
  		window.BXHtmlEditor.Overlay = Overlay;
  
  		BX.onCustomEvent(window.BXHtmlEditor, 'OnEditorBaseControlsDefined');
  	}
  
  	if (window.BXHtmlEditor)
  	{
  		__run();
  	}
  	else
  	{
  		BX.addCustomEvent(window, "OnBXHtmlEditorInit", __run);
  	}
  })();
  