﻿
// =====================================================
//  Расширение функциональности стандартных объектов
// =====================================================
String.prototype.trim = function() { return this.replace(/(^\s+|\s+$)/g, ''); };
String.prototype.growLeft = function(num, charStr) {var val = this;var m = num-val.length;for(var i=0;i<m;i++) val = charStr + val;  return val; };

Array.prototype.add = function(o){var l=this.length; this[l] = o; return l;};
Array.prototype.indexOf = function(o){var l=this.length; for(var i=0; i<l; i++){ if(o==this[i]){return i;} } return -1; };

/*
function ShowProps(obj){
		var win = window.open();
		var doc = win.document;
		doc.open();
		var name, val;
    for (var i in obj){
			name = i.toString();
			val = obj[i];
			if(name=='outerHTML' || name=='innerHTML'){
				val = val.replace((/\</ig), '&lt;');
				val = val.replace((/\>/ig), '&gt;');
			}
			doc.write(name + ' = <span style="color:gray;">' + val + '</span><br />\n');
		}
		doc.close();
}
*/


// =====================================================
//  Вспомогательные функции
// =====================================================

// Проверяем, является ли параметр объектом
function IsValid(val){ 
  if(val==null)
    return false;
  else{
    var s = ''+val;
    if(s=='undefined' || s.length==0) 
      return false;
  }
  return true;
};

// Предварительная загрузка картинок для rolloverа
function loadImage(){
  if(!IsValid(window.__loadImageArr)){

    window.__loadImageArr = new Array();
  
    Events.Attach(window, 'onload',     
      function() {
        var l = window.__loadImageArr.length;
        for(var i=0;i<l;i++){
          (new Image()).src = window.__loadImageArr[i];
        }
      }
);
    
    Events.Attach(window, 'onunload', function(){window.__loadImageArr = null;});
  }
  
  var l = loadImage.arguments.length;
  for(var i=0;i<l;i++){
    window.__loadImageArr.add(loadImage.arguments[i]);
  }
};

function PopUpWindow(url, width, height, name, scrollbar, resizable, toolbar)
{
	if(typeof(scrollbar)=='undefined') 
	  name = (new Date()).getTime().toString();		
	  
	scrollbar = (typeof(scrollbar)=='undefined'||scrollbar==false) ? 'no' : 'yes';
	toolbar = (typeof(toolbar)=='undefined'||toolbar==false) ? 'no' : 'yes';
	resizable = (typeof(resizable)=='undefined') ? 'yes' : (resizable==true) ? 'yes' : 'no';
	
	var left = (screen.width/2) - width/2;
	var top = (screen.height/2) - height/2;
	
	var style = 'toolbar='+toolbar+',location=no,directories=no,status=no,menubar=no,scrollbars='+scrollbar+',resizable='+resizable+',width='+width+',height='+height+',left='+left+',top='+top+',screenX='+left+',screenY='+top;
	var win = window.open(url, name, style);
	if(win==null){
	  alert('ВНИМАНИЕ!\n\nНе удалось открыть новое окно!\n\nНеобходимо разрешить открытие страницы в новом окне!');
	}
	else{
	  win.opener = self;
	  win.focus();
	}
	return win;
}

// =====================================================
//  Объект, для работы с DOM
// =====================================================

var DOMHelper = new function(){
  this.GetChild = function(obj, index){
    if(typeof(obj.children)!='undefined'){
      return obj.children[index];
    }
    else{
      var nodes = obj.childNodes;
      var l = nodes.length;
      var ii = 0;
      for(var i=0; i<l; i++){
      if(nodes[i].nodeType==1){    
          if(ii==index){
            return nodes[i];
            break;
          }
          ii++;
        }
      }
    }
    return null;  
  };
};

// =====================================================
//  Объект, предоставляющий информацию о браузере
// =====================================================

var Browser = new function(){
  // Типы поддерживаемых браузеров
  this.Unknown = 0;
  this.IE = 1;
  this.Opera = 2;
  this.Netscape = 3;
  this.Mozilla = 4;
  this.Firefox = 5;
  
  // Семейство браузеров
  this.GeckoFamily = 1;
  
  // Информация о браузере
  this.Type = null; // Тип браузера
  this.Family = null; // Семейство браузера
  this.Version = null;
	this.MajorVersion = null;
	this.MinorVersion = null;
	
	this.ClientArea = null; // Клиентская область окна
	this.Shadow = null;// Объект, реализующий тень под плавающим слоем
	
	
	this.__underControls = null; // контейнер
	
  // Инициализируем информацию о браузере
  this.Init = function(){
	  var agent = navigator.userAgent;
  	
	  var agentList = new Array(
		  { type: this.Opera,			family:null,              re: 'Opera[\\s|\\/](\\d*.\\d*)'                   }, 
		  { type: this.IE,				family:null,              re: 'MSIE\\s(\\d*.\\d*)'                          }, 
		  { type: this.Netscape,	family:this.GeckoFamily,  re: 'Gecko\\/\\d*? Netscape\\d?\\/(\\d*.\\d*).*$' }, 
		  { type: this.Mozilla,		family:this.GeckoFamily,  re: 'rv:(\\d*.\\d*).*?Gecko\\/\\d*$'              }, 
		  { type: this.Firefox,		family:this.GeckoFamily,  re: 'Gecko\\/\\d*? Firefox\\/(\\d*.\\d*).*$'      }
	);
  	
	  var l = agentList.length;
	  for(var i=0; i<l; i++){
	    var obj = agentList[i];
	    var res = (new RegExp(obj.re ,'i')).test(agent);
	    if(res) {
		    this.Type = obj.type;
		    this.Family = obj.family;
		    this.Version = RegExp.$1;
  		  
		    var v = this.Version.split('.');
		    this.MajorVersion = parseInt(v[0], 10);
		    this.MinorVersion = parseInt(v[1].substr(0,1), 10);
		    break;
	    }
	  }
  }; // end: Init

  // Получаем объект типа Point c координатами объекта
  this.GetElementCoord = function(el){
  	var pt = new Point(0, 0);
	  var obj = el;
	  do { 
		  pt.X += obj.offsetLeft;
		  pt.Y += obj.offsetTop; 
		  if(Browser.Type==Browser.IE){
		    if(obj.tagName.toUpperCase() == 'DIV'){
    		  pt.X -= obj.scrollLeft;
		      pt.Y -= obj.scrollTop; 
		    }
		  }
		  obj = obj.offsetParent;
	  } while(IsValid(obj));
	  return pt;
  }; // GetElementCoord
  
  // Получаем объект типа Area c координатами объекта
  this.GetElementArea = function(el, hasShadow){
  	var pt = this.GetElementCoord(el);
  	var ar = new Area(pt.X, pt.Y, pt.X+el.offsetWidth, pt.Y+el.offsetHeight);
  	
  	if(hasShadow==true){
  	  var shadow = this.GetShadow();
  	  ar.Right += shadow.Shift.X;
  	  ar.Bottom += shadow.Shift.Y;
  	}
  	
  	return ar;
  }; // GetElementArea
  
  // Получаем клиентскую область окна
  this.GetClientArea = function(){  
    if(this.ClientArea==null){
      this.ClientArea =  new ClientArea();
      this.ClientArea.Padding = new Area(10, 10, 18, 18);
    }
    
    return this.ClientArea;
  };
  
  this.GetEventPoint = function(ev){
		var pt = new Point(0,0);
		if(!IsValid(ev.pageY)){
	    pt.Y = document.body.scrollTop  + ev.clientY;
	    pt.X = document.body.scrollLeft + ev.clientX;	
		}
		else {
	    pt.Y = ev.pageY;
	    pt.X = ev.pageX;	
		}
		return pt;
	};
  
  // Получаем объект, реализующий тень под плавающим слоем
  this.GetShadow = function(){  
    if(this.Shadow==null){
      this.Shadow =  new ShadowLayer();
    }
    
    return this.Shadow;
  };
  
  // Показываем или скрываем контрол SELECT находящийся под слоем
  this.ShowUnderControls = function(obj, show, hasShadow){
    if(Browser.Type==Browser.IE){
    
      if(this.__underControls==null) this.__underControls = new Array();

      var ucID = obj.getAttribute('__ucID');
      
      if(show){
        var arr = this.__underControls[ucID];
        
        var l = arr.length;
        for(var i=0;i<l;i++){
          arr[i].style.visibility = 'visible';
          arr[i] = null;
        }
        
        arr.length = 0;
        this.__underControls[ucID] = null;
      }
      else {
        var arr = new Array();
      
		    var s;
			  var selects = document.getElementsByTagName('SELECT');
    		
			  var l = selects.length;
			  var box = this.GetElementArea(obj, hasShadow);
			  for(var i=0;i<l;i++) {
				  s = selects[i];
				  if(box.IsOverlap(this.GetElementArea(s))){
				    s.style.visibility = 'hidden';
				    arr.add(s);
				  }
			  }

        if(IsValid(ucID))
          this.__underControls[ucID] = arr;
        else
        {
          var id = this.__underControls.add(arr);
          obj.setAttribute('__ucID', id);
        }
      }
    }
  };
  
  // Освобождаем объекты
  this.Dispose = function(){
	  this.ClientArea = null;

	  if(this.Shadow!=null){
	    this.Shadow.Dispose();
	    this.Shadow = null;
	  }
  };
  
	// инициализация
	this.Init();
};

// =====================================================
//  Framework для работы с событиями
// 
//  Пример использования:
//
//    Вызов функции по событию:
//      Events.Attach(document, 'onclick', function(){alert('Круто!');});
//    Вызов метода объекта:
//      Events.Attach(document, 'onclick', this, 'ShowInfo'});
// =====================================================

var Events = new function() {
	this._hasAttach = window.attachEvent ? true : false;
	this._id = 0;
	this._handlers = new Array();
	
  this.StopPropagation = function(ev)
  {
    if(Browser.Family==Browser.GeckoFamily){
      if(ev.cancelable) ev.preventDefault();
      ev.stopPropagation();
    }
    else{
      ev.cancelBubble = true;
      ev.returnValue = false;
    }
    
    return false;
  }; // end: StopPropagation

  // добавление обработчика
  this.Attach = function(element, eventName, object, functionName){
  
    if(typeof(element)=='undefined' || element==null){
      alert("Invalid parameter 'element' for Events.Attach!");
    }
      
	  var handlerFunc = function(ev){ 
		  if(window.event) ev = window.event; 
  		
		  // Добавляем к объекту event метод GetPoint, 
		  // который возращает кординату события
		  if(IsValid(ev)){
		    ev.GetPoint = function(){
		      var x, y;
		      if(''+this.pageY=='undefined'){
	          y = document.body.scrollTop  + this.clientY;
	          x = document.body.scrollLeft + this.clientX;	
		      }
		      else {
	          y = this.pageY;
	          x = this.pageX;	
		      }
		      return new Point(x, y);
		    }; // end:GetPoint
		  }
  		
		  if(typeof(object) == 'function')
		    return object(element, ev);
		  else if(typeof(object) == 'object' && object!=null)
		    return object[ functionName ](element, ev);
	  }; // end: handlerFunc
	  
	  if(this._hasAttach) 
		  element.attachEvent(eventName, handlerFunc);
	  else
		  element.addEventListener(eventName.replace('on', ''), handlerFunc, false);

    this._id++;
	  this._handlers[ this._id ] = {el: element, en: eventName, handler: handlerFunc};
  	
	  return this._id;    
  }, // end: Attach
	
  // удаление обработчика
  this.Detach = function(id) {  
	  var obj = this._handlers[ id ];
	  if(obj != null) {
		  var element = obj.el;
		  var eventName = obj.en;
  		
		  if(this._hasAttach)
			  element.detachEvent(eventName, obj.handler);
		  else
			  element.removeEventListener(eventName.replace('on', ''), obj.handler, false);
  		
		  obj.handler = null;
		  this._handlers[ id ] = null;
	  }
  }, // end: Detach
	
  // очистка всего списка обработчиков
  this.DetachAll = function(element, ev) {
    if(Browser.Family==Browser.GeckoFamily){
      for(var ii=2; ii <= this._id; ii++){
        var obj = this._handlers[ ii ];

        if(obj!=null){
          if(obj.el==element && obj.en=='onunload')
            obj.handler(window, ev);

          this.Detach(ii);
        }
      }
      this.Detach(1);
    }
    else
      for(var ii=1; ii <= this._id; ii++)
        this.Detach(ii);
        
  }, // end: DetachAll
  
  this.FireOnLoadEvents = function()
  {
    for(var i=1; i <= this._id; i++){
      if(this._handlers[i].en == 'onload'){
        this._handlers[i].handler();// = {el: element, en: eventName, handler: handlerFunc};
        this.Detach(i);
      }
    }
  }

  this.Attach(window, 'onunload', this, 'DetachAll');
  this.Attach(window, 'onunload', Browser, 'Dispose');
};

// =====================================================
//  Объект "Точка"
// =====================================================

function Point(x, y){
  this.X = x;
  this.Y = y;

  // Сдвиг на указанное значение
  this.Shift = function(pt){
    this.X += pt.X;
    this.Y += pt.Y;
  } 
};

// =====================================================
//  Объект "Область"
// =====================================================

function Area(left, top, right, bottom){
  var paramCount = Area.arguments.length;
  
  switch(paramCount){
    case 0:
      this.Left = this.Top = this.Right = this.Bottom = 0;
      break;
    case 1:
      this.Left = this.Top = this.Right = this.Bottom = Area.arguments[0];
      break;
    case 2:
      this.Left = this.Right = Area.arguments[0];
      this.Top = this.Bottom = Area.arguments[1];
      break;
    case 4:
      this.Left = Area.arguments[0];
      this.Top = Area.arguments[1];
      this.Right = Area.arguments[2];
      this.Bottom = Area.arguments[3];
      break;
    default:
      alert('Неверное количество параметров при инициализации области!');
  }

  // Точка верхнего левого угла квадрата
  this.GetTopLeftPoint = function(){
    return new Point(this.Left, this.Top);
  };

  // Точка нижнего правого угла квадрата
  this.GetBottomRightPoint = function(){
    return new Point(this.Right, this.Bottom);
  };

  // Ширина квадрата
  this.GetWidth = function(){
    return this.Right - this.Left; 
  };

  // Высота квадрата
  this.GetHeight = function(){
    return this.Bottom - this.Top;
  }; 

  // Вписываем область area в текущую
  this.TypeIn = function(area){
    var shift=0;

    if(area.Right > this.Right)
      shift = area.Right-this.Right;
      
    if(area.Left-shift<this.Left)
      shift = area.Left - this.Left;
    
    area.Left -=shift;  
    area.Right -=shift;
    
    shift=0;
    
    if(area.Bottom > this.Bottom)
      shift = area.Bottom-this.Bottom;
      
    if(area.Top-shift<this.Top)
      shift = area.Top - this.Top;
    
    area.Top -=shift;  
    area.Bottom -=shift;
  };

  // Проверяем, перекрываются ли области
  this.IsOverlap = function(area){
    var ptl1 = this.GetTopLeftPoint();
    var ptl2 = area.GetTopLeftPoint();

    var pbr1 = this.GetBottomRightPoint();
    var pbr2 = area.GetBottomRightPoint();
    
    if(
      ((ptl1.X<=ptl2.X && ptl2.X<=pbr1.X) || (ptl1.X<=pbr2.X && pbr2.X<=pbr1.X) || (ptl2.X<=ptl1.X && ptl1.X<=pbr2.X))
      &&
      ((ptl1.Y<=ptl2.Y && ptl2.Y<=pbr1.Y) || (ptl1.Y<=pbr2.Y && pbr2.Y<=pbr1.Y) || (ptl2.Y<=ptl1.Y && ptl1.Y<=pbr2.Y))
      ) 
      return true;
    else
      return false;
  };
};

// =====================================================
//  Объект ClientArea предназначен для работы 
//  c видимой областью окна браузера
// =====================================================

function ClientArea(){

  // Отступ от краев видимой области 
  // Padding.Top - отступ с верху и т.д.
	this.Padding = null; 
	
	
	// Для flow-верстки ID якоря 
	this.AnchorID = null;
	
	// Для flow-верстки параметры сдвига относительно якоря:
  // Shift.Left - расстояние от якоря до левой границы области
	// Shift.Right - расстояние от якоря до правой границы области
	// Shift.Top - расстояние от якоря до верхней границы области
	// Shift.Bottom - расстояние от якоря до нижней границы области
	// значение == -1 - выравнивать по границе окна
	this.Shift   = null; 
	
	// Приватные свойства
	this._anchor = null;

  // Получаеим сласс типа Area 
  // с координатами видимой области экрана 
  this.GetWindowArea = function(){
	  var area = new Area() ;
	  if(Browser.Family == Browser.GeckoFamily){
  	  area.Left   = window.pageXOffset;
		  area.Top    = window.pageYOffset;
		  area.Right  = area.Left + window.innerWidth;
		  area.Bottom = area.Top + window.innerHeight;
	  }
	  else{
		  area.Left   = document.body.scrollLeft;
		  area.Top    = document.body.scrollTop;
		  area.Right  = area.Left + document.body.clientWidth;
		  area.Bottom = area.Top + document.body.clientHeight;
	  }
	  return area;
  };

  // Вписываем область area в экран с учетом параметров экземпляра класса ClientArea
  this.TypeInArea = function(area){
	  this.GetArea().TypeIn(area);
  },

  // Получаеим класс типа Area с координатами области экрана 
  this.GetArea = function(){
	  var area = this.GetWindowArea();
  	
	  if(this.AnchorID!=null && this.Shift!=null){
	    this.TypeInFlowArea(area);
    }
  	
	  if(this.Padding!=null){
	    area.Left += this.Padding.Left;
	    area.Top += this.Padding.Top;
	    area.Right -= this.Padding.Right;
	    area.Bottom -= this.Padding.Bottom;
	  }

	  return area;
  };

  // Обрабатываем вписывание в указанную область для flow-верстки
  this.TypeInFlowArea = function(area){
    if(this._anchor==null)
	    this._anchor = document.getElementById(this.AnchorID);
  	  
	  var pt = Browser.GetElementCoord(this._anchor);

	  area.Left   = (this.Shift.Left<0) ? area.Left   : Math.max(pt.X + this.Shift.Left,   area.Left);
	  area.Top    = (this.Shift.Top<0) ? area.Top    : Math.max(pt.Y + this.Shift.Top,    area.Top);
	  area.Right  = (this.Shift.Right<0) ? area.Right  : Math.min(pt.X + this.Shift.Right,  area.Right);
	  area.Bottom = (this.Shift.Bottom<0) ? area.Bottom : Math.min(pt.Y + this.Shift.Bottom, area.Bottom);
  };
};

// =====================================================
//  Объект, создающий тень под плавающим слоем
// =====================================================

function ShadowLayer(){
  this.Shift	= new Point(10, 10);
  this.Color = '#A8B5C5';
  this.Alpha = 65;

  this._div = null;
  this._objects = new Array();
  
  this._createLayer = function(){
    var div = document.createElement('DIV');
    with(div.style){
      width = height = 1;
      left = top = -10;
      position = 'absolute';
      visibility = 'hidden';
    }
    
    if(Browser.Type==Browser.IE){
      div.style.filter = 'alpha(opacity='+this.Alpha+')';
      div.style.backgroundColor = this.Color;
    }
    else if(Browser.Type==Browser.Netscape && Browser.MajorVersion<7){
      div.style.backgroundColor = this.Color;
    }
    else{
      var src = 'webres.ashx?file=img.png&color='+escape(this.Color)+'&alpha='+this.Alpha;
      loadImage(src);
      div.style.backgroundImage = 'url('+src+')';	
    }    
    
    document.body.insertBefore(div, document.body.firstChild);
    return div;
  };

  this.Show = function(obj){
    var shadowID = obj.getAttribute('shadowID');
    var div;
    
    if(IsValid(shadowID))
      div = this._objects[shadowID];
    else
    {
      div = this._createLayer();
      var id = this._objects.add(div);
      obj.setAttribute('shadowID', id);
    }
    
    var zIndex = parseInt(obj.style.zIndex, 10);
    if(isNaN(zIndex)){
      zIndex = 0;
      obj.style.zIndex = 1;
    }
    else{
      if(zIndex<=0){
        obj.style.zIndex = 1;
        zIndex = 0;
      }
      else{
        zIndex--;
      }
    }

    var style = div.style;
    style.width = obj.offsetWidth;
    style.height = obj.offsetHeight;
    
    // значения top и left должны быть заданны!
    style.top = parseInt(obj.style.top, 10) + this.Shift.X;
    style.left = parseInt(obj.style.left, 10) + this.Shift.Y;
    
    style.zIndex = zIndex;
    style.visibility = 'visible';
  };

  this.Hide = function(obj){
    var shadowID = obj.getAttribute('shadowID');
    if(IsValid(shadowID)){
      with(this._objects[shadowID].style){
        width = 1;
        height = 1;
        top = -10;
        left = -10;
        visibility = 'hidden';
      }
    }
  };
  
  this.Dispose = function(){
    var l = this._objects.length;
    for(var i=0; i<l; i++) this._objects[i] = null;
		this._objects = null;
    this._shift = null;
    this._div = null;
  };
};

function Tooltip(id, sw, sh){
  this._div = document.getElementById(id);
  this._table = document.getElementById('t_'+id);
  this._style = this._div.style;
  this._shift	= new Point(sw, sh);
  
  this._hideHandlerID = '';
  this._firstHide = true;

  this._style.display = '';
  var w = document.getElementById('t_'+id).offsetWidth;
  if(w>parseInt(this._style.width, 10)) this._style.width = w;  
  this._style.display = 'none';
  
  Events.Attach(window, 'onunload', this, 'Dispose');
  Events.Attach(this._div, 'onclick', this, '__handlerClick');
  
  this.__handlerClick = function(o, ev){ev.cancelBubble = true;}
  
  this.Show = function(obj, ev){
    if(this._style.display == 'none'){
      var pt = Browser.GetEventPoint(ev);
      with(this._style){display = '';visibility = 'hidden';top = pt.Y + this._shift.Y;left = pt.X + this._shift.X;}
     
      var area = Browser.GetElementArea(this._div, true);
      Browser.GetClientArea().TypeInArea(area);
      pt = area.GetTopLeftPoint();
      
      with(this._style){visibility = 'visible';top = pt.Y;left = pt.X;}    

      Browser.GetShadow().Show(this._div);
      
      this._hideHandlerID = 
        Events.Attach(document,'onclick',this,'_hide') + '|' +
        Events.Attach(window,'onscroll',this,'_hide') + '|' +
        Events.Attach(window,'onresize',this,'_hide');
        
      this._firstHide = true;
      
      if(IsValid(cleckEvents = obj.getAttribute('onClientClick'))) eval(cleckEvents);
      
      Browser.ShowUnderControls(this._div, false, true);
    }
  };
  
  this._hide = function(){
    if(this._style.display == '' && !this._firstHide){
      this._style.display = 'none';
      Browser.GetShadow().Hide(this._div);
      
      var handlerArr = this._hideHandlerID.split('|');
      var l = handlerArr.length;
      for(var i=0; i<l; i++)
        Events.Detach(parseInt(handlerArr[i],10));
        
            
      Browser.ShowUnderControls(this._div, true);
    }
    
    this._firstHide = false;
  };
  
  this.Hide = function(){
    this._firstHide = false;
    this._hide();
  };

  this.Dispose = function(){
    this._div = null;
    this._table = null;
    this._style = null;
    this._shift = null;
  };
};
