﻿//todo: $show(el), $hide(el)

var vbT=String.fromCharCode(9);
var vbV=String.fromCharCode(11);
var vbE=String.fromCharCode(13);
var vbEsc=String.fromCharCode(27);//для сигнализирования об ошибке
function $class() {return function() {this.initialize.apply(this, arguments)}};

var $onload_list=new Array();
function $onload(func){
//	if (window.addEventListener) window.addEventListener('load', func, false);
//		else 	
//		{
//			window.attachEvent("onload", func)
//		}
	if ($onload_list.length==0) {
		if (window.addEventListener) window.addEventListener('load', $onload_exec, false); else window.attachEvent("onload", $onload_exec);
	}
	$onload_list[$onload_list.length]=func;
};
function $onload_exec(){
	for(var i=0;i<$onload_list.length;i++) $onload_list[i]();
	$onload_list=undefined;
}

String.prototype.startWith=function(s){return(this.substr(0,s.length)==s)};
String.prototype.endWith=function(s){return(this.slice(-s.length)==s)};
String.prototype.truncate=function(length) {length = length || 30;return (this.length > length ?  this.slice(0, length - 3) +  '...' : this)};
String.prototype.escapeHTML=function() {var p=document.createElement('div');p.appendChild(document.createTextNode(this));return p.innerHTML};
String.prototype.trim=function(){return this.replace(/(^\s+)|(\s+$)/g, '')};
//каждая первая буква слова - заглавная. учитываем .,-
String.prototype.properCase=function(){return this.replace(/(^[a-zа-я])|([\s\.\,\-]{1}[a-zа-я])/g,function(w){return w.toUpperCase()})};
//содержит ли строка только цифры
String.prototype.isDigits=function(allowEmpty){return ((allowEmpty && this.length==0) || /^\d+$/.test(this))};
//поиск эл-та в массиве. они есть и в IE но более тормозные
Array.prototype.indexOf=function(v,startIndex,param){
	if(param)//ищем v в параметре объекта
		{for(var i=startIndex || 0;i<this.length;i++) if(this[i][param]==v) return i; return -1;}
	else
		{for(var i=startIndex || 0;i<this.length;i++) if(this[i]==v) return i; return -1;}
	};
Array.prototype.lastIndexOf=function(v,startIndex,param){
	if(param)//ищем v в параметре объекта
		{for(var i=startIndex || this.length-1;i>=0;i--) if(this[i][param]==v) return i; return -1;}
	else
		{for(var i=startIndex || this.length-1;i>=0;i--) if(this[i]==v) return i; return -1;}
	};

function $eval(s){//if string return function
	return typeof(s)=='string'?eval(s):s;
};

function $e(name){return document.getElementById(name)};
function $html(name,value){
	if(value==undefined) 
		return document.getElementById(name).innerHTML;
	else
		document.getElementById(name).innerHTML=value
};
function $v(name){return document.getElementById(name).value};
function $V(name,value){document.getElementById(name).value=value};
function $E(name){var obj=(typeof(name)=='object'?name:document.getElementById(name)); if (!obj) return undefined; else return $el(obj)};
function $Z(value){if ($N(value)==0) return ''; else return value; }//zero to nothing

function $show(el,isShow){
		if(el.constructor==String) el=document.getElementById(el);
		if(el) el.style.display=(isShow==undefined || isShow)? 'block':'none';
	}
function $hide(el){$show(el,false);}

function $reveal(el,isShow){
		if(el.constructor==String) el=document.getElementById(el);
		if(el) el.style.visibility=(isShow==undefined || isShow)? 'visible':'hidden';
	}
function $conceal(el){$reveal(el,false);}

function $el(tagName,H,innerHTML,ownerDoc){//создаем элемент с аттрибутами
	//tagName  может быть указан className после точки
	//ownerDoc - объект document в к-м будет создаваться данный таг, по дефолту document
	if (typeof(tagName)=='object')
		e=tagName;//если объект, просто прилепим ему наши навороты
	else
	{	var css, i=tagName.indexOf('.');
		
		if (i>=0) {css=tagName.substring(i+1); tagName=tagName.substring(0,i)};
		e= (ownerDoc || document).createElement(tagName);
		if (css) e.className=css;
		if(H)	
			{
			if(H.style) //перемещаем стили
				{
					var k=H.style.split(';');
					for(var j=0;j<k.length;j++)
						{
						if(k[j].length==0) continue;
						var k2=k[j].split(':');
						e.style[k2[0].trim()]=k2[1].trim();
						}
					delete H.style;
				}
			for(i in H) e.setAttribute(i,H[i])
			};
		if(innerHTML) e.innerHTML=innerHTML;
	};
	e.remove=function(){this.parentNode.removeChild(this)};
	e.attr=function(H){for(i in H) e.setAttribute(i,H[i]); return this};
	e.add=function(el){this.appendChild(el); return this};
	e.write=function(html){this.insertAdjacentHTML('beforeEnd', html); return this};
	e.html=function(html){if(html==null) return this.innerHTML;  this.innerHTML=html; return this};
	e.addEl=function(tagName,H,innerHTML){this.appendChild($el(tagName,H,innerHTML)); return this};
	
	e.event=function(evName,action){
		var a=(typeof(action)=='string'? function(){eval(action)}: action);
		if (this.addEventListener) 
			this.addEventListener(evName, a, false);
		else 
			this.attachEvent("on" + evName,a);
		return this;
		};
	
	e.addFirst=function(el){this.insertBefore(el,this.firstChild)};//вставить первым
	e.addBefore=function(el){this.parentNode.insertBefore(el,this)};//вставить перед эл-том
	e.into=function(el,isFirst){//вставить этот элемент в другой
			if (!el) el=e.ownerDocument.body;//document.body;
			if (isFirst) 
				el.insertBefore(this,el.firstChild);
			else
				el.appendChild(this);
		};
	e.setStyle=function(H){ for (i in H) this.style[i]=H[i]; return this};
	
	e.show=function(b){this.style.display=(typeof(b)=='undefined' || b==true?'block':'none'); return this;};
	e.hide=function(){this.style.display='none'; return this;};
	e.toggle=function(){this.style.display=this.style.display=='none'?'block':'none'; return this;};
	
	e.reveal=function(b){this.style.visibility=(typeof(b)=='undefined' || b==true?'visible':'hidden'); return this;};
	e.conceal=function(){this.style.visibility='hidden'; return this;};
	e.hasClass=function(name){if(!this.className) return false; return (new RegExp("(^|\\s)" + name + "(\\s|$)")).test(this.className)};
	e.addClass=function(name){if(!this.className) {this.className=name;return this}; if (!this.hasClass(name)) this.className+=' '+name; return this};
	e.delClass=function(name){ if(!this.className) return this;
		this.className=this.className.replace(new RegExp("(^|\\s+)" + name + "(\\s+|$)"), ' ').trim();return this;
		if (this.className.length==0) this.className=undefined;
		};
	return e;
}

function This(e){//кроссбраузерный srcElement. e - event
	if(!e) return event.srcElement; 
	if(e.target) return e.target; else return e.srcElement;
};
//получаем путь к данному скрипту
function ScriptPath(Src, ownerDoc){//Src - папка и имя скрипта
	Src=Src.toLowerCase();
	var L=Src.length;
	var d=(ownerDoc || document).scripts;
	for (i=0;i<d.length;i++) 
		if(d[i].src.substring(d[i].src.length-L).toLowerCase()==Src) {
			Src=d[i].src;
			L=Src.lastIndexOf('/');
			if (L<0) return ''; else return Src.substr(0,L+1);
			};
	return null;
};

function $nbsp(v){return (v==undefined || v==null || (v.constructor==String && v.length==0)? '&nbsp':v);}
function undef(obj){return (obj==undefined)};
function def(obj){return (obj!=undefined)};
//is it prototype? 
function undefP(obj){return (obj==undefined || obj.constructor!=Object)};
function defP(obj){return (obj!=undefined && obj.constructor==Object)};
function DefP(obj,value){return ((obj==undefined || obj.constructor!=Object)?(value?value:{}):obj)};

function Def(obj,value){return (obj==undefined?value:obj)};
function DefN(obj,value){return (obj==undefined || obj==null?value:obj)};
function Def$(obj,item,value){if (obj!=undefined) return Def(obj[item],value); else return value};//проверяет если объект obj, и его свойство item, если да то возвращает, иначе value
function DEF(obj,item,value){//если параметр item не существует, устанавливаем
	if (obj==undefined) {obj={item:value}; return;}
	if(obj[item]==undefined) obj[item]=value;
};

//тоже что и DEF но для групповой инициализации. P-{name:defValue, ...}
function DEF_init$(obj,P){for(var i in P) if(obj[i]==undefined) obj[i]=P[i]}; //если obj уже объявлено. 

function DEF_init(obj,P){//возвращаем измененный объект. obj может быть не объявлено
	if (obj==undefined || obj.constructor!=Object) obj={};
	for(var i in P) if(obj[i]==undefined) obj[i]=P[i];
	return obj;
};

function f_Dollars(v){v=Number(v); if (isNaN(v)) return '$0.00';
	v = v.toString().replace(/\$|\,/g,'');
	dv = parseFloat(v);
	if(dv==0) return '$0.00';
	b = (dv == (dv = Math.abs(dv)));	dv = Math.floor(dv*100+0.50000000001);iC = dv%100;	sC = iC.toString();dv = Math.floor(dv/100).toString();if(iC<10)	sC = "0" + sC;	for (var i = 0; i < Math.floor((dv.length-(1+i))/3); i++)
	dv = dv.substring(0,dv.length-(4*i+3))+' '/*delimeter*/ + dv.substring(dv.length-(4*i+3));	
			return ('$' + ((b)?'':'-') +  dv + '.' + sC);
};
function f_DollarsN(v){v=Number(v); if (isNaN(v) || v==0) return '';
	v = v.toString().replace(/\$|\,/g,'');	
	dv = parseFloat(v);
	if(dv==0) return '$0.00';
	b = (dv == (dv = Math.abs(dv)));	dv = Math.floor(dv*100+0.50000000001);iC = dv%100;	sC = iC.toString();dv = Math.floor(dv/100).toString();if(iC<10)	sC = "0" + sC;	for (var i = 0; i < Math.floor((dv.length-(1+i))/3); i++)
	dv = dv.substring(0,dv.length-(4*i+3))+' '/*delimeter*/ + dv.substring(dv.length-(4*i+3));	
	return ('$' + ((b)?'':'-') +  dv + '.' + sC);
};

function f_Phone(v){//10-значный USPhone
	if (v==undefined) return '';
	v=v.toString();
	if (v.length==0 || v=='0') return '';
	if (v.length<10) {v=('__________').substr(10-v.length)+v}
	return '('+v.substr(0,3)+') '+v.substr(3,3)+'-'+v.substr(6,4)
};

function $sel(obj){//ф-ции для <Select>
	if (typeof(obj)=='string') obj=document.getElementById(obj);
	if(!obj) return;//нет такого контрола

	var sel={}; sel.obj=obj;
	sel.text=function(value){
 		//если value не указан, возвращаем выделенный текст, иначе ищем указанное значение и возвращаем текст
		var s=this.obj.options;
		if (undef(value))
			{if (this.obj.selectedIndex<0) return;
			return s[this.obj.selectedIndex].text;
			}
		for(var i=0;i<s.length;i++) if(s[i].value==value) return s[i].text;
	};
	
	sel.selected=function(){return this.obj.options[this.obj.selectedIndex]};//выделенный Option
	sel.selectText=function(text,elseIndex){//ищем текст и выделяем
		//elseIndex - номер строки если value не найден. по умолчанию -1
		var s=this.obj.options;
		for(var i=0;i< s.length;i++) if (s[i].text==text) {s[i].selected=true;return s[i];}
		this.obj.selectedIndex=Def(elseIndex,-1);
		};
	sel.selectValue=function(value,elseIndex){//ищем значение и выделяем
		this.obj.value=value;
		if (this.obj.selectedIndex<0 && def(elseIndex)) this.obj.selectedIndex=elseIndex;
		};
	sel.add=function(text,value,isSelect){	var o=new Option(text,value); 
		this.obj.options[this.obj.options.length]=o; 
		if (isSelect) o.selected=true;
		return o;
		};
		
	return sel;
};

function $N(n){if(!n)return 0; n=Number(n); if (isNaN(n)) return 0; else return n};
function $isInt(n){return /^\d+$/.test(n)};

function getRadioValue(rObj){
  for (var i=0; i < rObj.length; i++)  if (rObj[i].checked) return rObj[i].value;
  return null;
};

function $query(Name){// получаем QueryString. если нет такого ключа, возвращаем undefined
	var s=location.href;
	var i1=s.indexOf('?'); if (i1<0) return;
	if (!Name) return s.substring(i1+1);
	s=s.toLowerCase();	Name=Name.toLowerCase();
	var i=s.indexOf('?'+Name+'=',i1); if (i<0) i=s.indexOf('&'+Name+'=',i1); if (i<0) return;
	i+=Name.length+2;
	i1=s.indexOf('&',i);
	if (i1<0) return unescape(location.href.substring(i)); else return unescape(location.href.substring(i,i1));
};

function $tbl(obj){
	if(undef(obj)) 
		{obj=document.createElement('table');}//если не указан объект, создаем новый
	else 
		{if (typeof(obj)=='string') obj=document.getElementById(obj);
		if(!obj) return;//нет такого контрола
		}
	var tbl=obj; 
	tbl.clear=function(from,to){//очищаем таблицу от строк
			from=Def(from,0); if(undef(to)) to=this.rows.length-1;
			for(var i=from;i<=to;i++){this.deleteRow(from)}
		};
	tbl.row=function(H,Index){//H - аттрибуты: css-ClassName
		var tr=(def(Index)?this.insertRow(Index):this.insertRow());
		//if(def(Index)) tr.row=this.obj.insertRow(Index); else tr.row=this.obj.insertRow();
		if(H) {
			if (H.css) {tr.className=H.css; delete H.css;}
			for(var i in H) {tr[i]=H[i];}
		}
		tr.cell=function(html,H){//H - {атрибуты}, если строка тогда ClassName 
			var c=this.insertCell();
			//if(html) c.innerHTML=html; 
			c.insertAdjacentHTML('beforeEnd',html);
			if(def(H)) {
				if (H.constructor==String)
					c.className=H;
				else	
					if (H.css) {c.className=H.css; delete H.css;}	for(var i in H) c[i]=H[i];
				}
			return this;
		};
		return tr;
	};
	return tbl;
}

//удаляем эл-т по индексу. H - объект типа JSON compact
function jsonDel(H,ind){H.rows-=1; for(i in H.content) H.content[i].splice(ind,1)};

function $H_Q(h){//значение в querystring. если hash разделяем vbV, vbT
	if(h.constructor!=Object)  return h;
	var s=''; 
	for(var i in h) s+=vbV+i+vbT+h[i];
	if (s.length>0) s=s.substring(1);
	return s;
}

//замер времени производительности
var $time={
	 a:undefined
	, maxD:undefined
	, start: function(descr){this.a=new Array(); this.step(descr || 'Start');}
	, step:function(description){
		if(!this.a) this.clear();
		description=description || ('Step '+this.a.length);
		var endTime=new Date();
		var r=new Array();

		if (this.a.length>0){
			r['time']=(endTime-this.a[this.a.length-1]['rawtime']);
			r['desc']=description;
			r['rawtime']=endTime;
			if (typeof console != "undefined") 
			console.debug(r['desc']+' : %s ', r['time']); //for mozilla firebug
			this.a.push(r);//[arrTime.length+1]=recStep;
			if(this.maxD<description.length) this.maxD=description.length;
		}
		else{
			r['time']=0;
			r['desc']=description;
			r['rawtime']=endTime;
			this.maxD=description.length;
			this.a.push(r);
		}
	},
	finish: function(descr){this.step(descr || 'Finish');
		
		var strOut='',totalTime=0,d,s;
		var tab=String.fromCharCode(9);
		for(var i=0;i<this.a.length;i++){
			totalTime+=this.a[i]['time'];
			d=this.a[i]['desc'];
			s=(new Array(Math.floor((this.maxD-d.length)/7)+1)).join(tab)+tab;
			strOut+="\n"+d+s+' : '+this.a[i]['time']+tab+'t: '+totalTime;
			}
		strOut+="\n"+'-------------------------\nTotal: '+totalTime+' ms';
		alert(strOut);	
	}
};

function $loadScript(path,ownerDoc){
	var doc=(ownerDoc || document);
	var script=doc.createElement('script'); 
	script.type = 'text/javascript'; 
	script.src = path; 
	doc.getElementsByTagName('head')[0].appendChild(script); 
}

function ClearFilterForm(tblID){
	$$('#'+tblID+' input[type="text"]').each(function(o){o.value=''; if (o.$emptyTxt) $emptyTxt_clear(o)});
	$$('#'+tblID+' select').each(function(o){o.selectedIndex=0});
	dFrom.reset();dTo.reset();
}
//при пустой текстовой строке и отсутствии текста вставляет альт. текст
//вызывать в onLoad но перед установкой на него фокуса. возвращает объект как $el()
function $emptyTxt(txtObj, altText, altStyle){
	//txtObj - контрол или его имя
	//altText - альтернативный текст
	//altStyle - стиль альт. надписи в виде{}
	var el=$E(txtObj);
	el.$emptyTxt=true;
	if(altStyle==undefined) altStyle='fontStyle:italic;color:gray;';
	var d=$el('span'
		,{style:'position:absolute;display:none;padding:2px 0px 0px 7px;z-index:1;'+altStyle, onclick:$emptyTxt_focusD}
		,altText
		);
	el.addBefore(d);
	
	el.event('focus', $emptyTxt_focus).event('blur', $emptyTxt_blur).event('change', $emptyTxt_blur);
	$emptyTxt_blur({target:el});
}

function $emptyTxt_focusD(){this.nextSibling.focus();}
function $emptyTxt_focus(ev){var obj=This(ev); if (obj.value.length==0) obj.previousSibling.style.display='none';}
function $emptyTxt_blur(ev){var obj=This(ev); obj.previousSibling.style.display=(obj.value.length==0?'block':'none');}
function $emptyTxt_clear(obj){obj.previousSibling.style.display='block';}

//для использования фильтра поиска
var $filter={
	  resTblID: 'tblList'
	, resDivID: 'tdBody'
	, url:null
	, curQ:null
	, lastQ: null
	, callback:null //вызывается после поиска: передает true если есть рез-ты
	, init: function(h){
			$filter.callback=$filter.curQ=$filter.lastQ=null;
			$filter.resTblID= 'tblList';
			$filter.resDivID= 'tdBody'
			$filter.url= null;
			
			if(h)	for(var i in h) $filter[i]=h[i];
		}
  , go:function(q, h) {
		if(h)  $filter.init(h);
		
		q=q || '';
		if(q.constructor==Object)
		{
			var s='';
			for(var v in q) s+="&"+v+"="+escape(q[v]);
			q=s;
		}

		$filter.curQ=(q.length>0?q+"&mpP=":"mpP=");
		if (q.length>0 && q.charAt(0)=='&') q=q.substring(1);
		$filter.open(q);
	}
  , open: function(q){
		//if(! $filter.resDivID) {location.href=$filter.url+'?'+q; return;}
	
		$filter.lastQ=q;
		$.ajaX({
			url:$filter.url
			,q:q
			,cache:false
			,target:{obj:$filter.resDivID,img:'#circle'}
			,on:$filter.fOpen
		});			
	}
  , fOpen: function(){
		//var t=document.getElementById($filter.resTblID);
		//if (t) gridA(t);
		if($filter.callback)  $filter.callback(t!=undefined);
	  }
  , reload: function(){ //перегрузить учитывая текущую страницу
		$filter.open($filter.lastQ);  
	}
  , pg: function(i){
		$filter.open($filter.curQ+i);
	}
}