Javascript-форум (https://javascript.ru/forum/)
-   Ваши сайты и скрипты (https://javascript.ru/forum/project/)
-   -   Маскированный ввод (https://javascript.ru/forum/project/1623-maskirovannyjj-vvod.html)

ZoNT 25.08.2008 13:15

Маскированный ввод
 
Написал скрипт для маскированного ввода в инпуты.
Потестируйте, если есть какие предложения - тоже высказывайте.
function setMask(I,M){
	function R(s){return new RegExp('('+s.replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\//g,'\\/').replace(/9/g,'\\d').replace(/a/g,'[a-zа-яё]').replace(/\*/g,'[a-zа-яё0-9]')+')','gi')}
	function N(c){
		for(var i=0,s='';i<L;i++)s+=$[i]||c;
		
		return s
	}
	function D(e,p,i){
		p=I.gC();
		if (p[0]==p[1]) {
			if(e)p[1]++;
			else p[0]--
		}
		for(i=p[0];i<p[1];i++)
			if(!S[i]&&$[i]){
				$[i]=0;
				j--
			}
		return p
	}
	function V(){
		setTimeout(function(k){
				if (R(M).test(I.value)) {
					I.value=RegExp.$1;
					$=I.value.split('');
					for(k=0;k<L;k++)if(!S[k])j++
				}
				else {
					I.value = N('_');
					I.sC(i)
				}
			},0)
	}
	function P(c){
		if (c<35&&c!=8||c==45) return 1;
		switch(c){
			case 8:		i=D()[0]; return 0;
			case 46:	i=D(1)[1]; return 0;
			case 35:	i = L; return 1;
			case 36:	i = 1;
			case 37:	if (i-=2<-1) i=-1;
			case 39:	if (++i>L) i=L; return 1;
			default:	i=I.gC()[0];
						while(i<L&&S[i]){i++}
						if (i==L) return 0;
						
						c = String.fromCharCode(c)
						if (R(M.charAt(i)).test(c)) {
							D(1);
							$[i++] = c;
							j++;
							while(i<L&&S[i]){i++}
						}
						return 0
		}
	}
	
	var d=document, c='character', y=-100000, L=M.length, G=!c, i=0, j=0, $=M.split(''), S=M.split('');
	
	for (var k=0;k<L;k++) if (/a|9|\*/.test($[k])) $[k]=S[k]=0;
	I = typeof I=='string' ? d.getElementById(I) : I;
	
	I.sC = function(l,g){
		if(this.setSelectionRange) this.setSelectionRange(l,l);
		else {
			g = this.createTextRange();
			g.collapse(true);
			g.moveStart(c,y);
			g.move(c,l);
			g.select();
		}
	}
	I.gC = function(r,b){
		if (this.setSelectionRange) return [this.selectionStart,this.selectionEnd];
		else {
			r = d['selection'].createRange();
			b = 0-r.duplicate().moveStart(c,y)
			return [b,b+r.text.length]
		}
	}
	I.onfocus = function(){
		this.value=N('_');
		setTimeout(function(){I.sC(j?i:0)},0)
	}
	I.onblur = function(){
		this.value = j?N(' '):''
	}
	I.onkeydown = function(e,c){
		e = e||event;
		c = e.keyCode||e.charCode;

		i = this.gC()[0];
		
		if (c==8||c==46) {
			G = true;
			P(c);
			this.value = N('_');
			this.sC(i);
			return !G
		}
		else if (!window.netscape&&(c>34&&c<38||c==39)) P(c)
	}
	I.onkeypress = function(e){
		if (G) return G=!G;
		
		e = e||event;
		
		if (P(e.keyCode||e.charCode)) return !G;
		
		this.value = N('_');
		this.sC(i);
		
		return G
	}
	
	if (d.all&&!window.opera) I.onpaste=V;
	else I.addEventListener('input',V,false)
}


Вызывается: setMask('i1','99.99.9999');
первый параметр - инпут (или его айди)
второй параметр - маска

формат маски:
a - любая буква
9 - любая цифра
* - буква или цифра.

ZoNT 26.08.2008 13:06

Исправлен баг с неправильным подсчётом введёных символов при вставке из буфера.
+ немного косметических правок...

function setMask(I,M){
	function R(s){return new RegExp('('+s.replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\//g,'\\/').replace(/9/g,'\\d').replace(/a/g,'[a-zа-яё]').replace(/\*/g,'[a-zа-яё0-9]')+')','gi')}
	function N(c,j,x){
		for(var k=0,s='';k<L;k++)s+=$[k]||c||'_';
		I.value=s;
		x?0:I.sC(!j?i:0)
	}
	function D(e,p,i){
		p=I.gC();
		if (p[0]==p[1]) {
			if(e)p[1]++;
			else p[0]--
		}
		for(i=p[0];i<p[1];i++)
			if(!S[i]&&$[i]){
				$[i]=0;
				j--
			}
		return p
	}
	function V(){
		setTimeout(function(k){
				if (R(M).test(I.value)) {
					I.value=RegExp.$1;
					$=I.value.split('');
					for(k=j=0;k<L;k++)if(!S[k])j++
				}
				else N()
			},0)
	}
	function P(c){
		if (c<35&&c!=8||c==45) return 1;
		switch(c){
			case 8:		i=D()[0]; return 0;
			case 46:	i=D(1)[1]; return 0;
			case 35:	i = L; return 1;
			case 36:	i = 1;
			case 37:	if (i-=2<-1) i=-1;
			case 39:	if (++i>L) i=L; return 1;
			default:	i=I.gC()[0];
						while(i<L&&S[i]){i++}
						if (i==L) return 0;
						
						c = String.fromCharCode(c)
						if (R(M.charAt(i)).test(c)) {
							D(1);
							$[i++] = c;
							j++;
							while(i<L&&S[i]){i++}
						}
						return 0
		}
	}
	
	var d=document, c='character', y=-100000, L=M.length, G=!c, i=0, j=0, $=M.split(''), S=M.split('');
	
	for (var k=0;k<L;k++) if (/a|9|\*/.test($[k])) $[k]=S[k]=0;
	I = typeof I=='string' ? d.getElementById(I) : I;
	
	I.sC = function(l,g){
		if(this.setSelectionRange) this.setSelectionRange(l,l);
		else {
			g = this.createTextRange();
			g.collapse(true);
			g.moveStart(c,y);
			g.move(c,l);
			g.select();
		}
	}
	I.gC = function(r,b){
		if (this.setSelectionRange) return [this.selectionStart,this.selectionEnd];
		else {
			r = d['selection'].createRange();
			b = 0-r.duplicate().moveStart(c,y)
			return [b,b+r.text.length]
		}
	}
	I.onfocus = function(){
		setTimeout(function(){N(0,!j)},0)
	}
	I.onblur = function(){
		j ? N(' ',0,1) : this.value=''
	}
	I.onkeydown = function(e,c){
		e = e||event;
		c = e.keyCode||e.charCode;
		
		if (c==8||c==46) {
			G = true;
			P(c);
			N();
			return !G
		}
		else if (!window.netscape&&(c>34&&c<38||c==39)) P(c)
	}
	I.onkeypress = function(e){
		if (G) return G=!G;
		
		e = e||event;
		
		if (P(e.keyCode||e.charCode)) return !G;
		
		N();
		
		return G
	}
	
	if (d.all&&!window.opera) I.onpaste=V;
	else I.addEventListener('input',V,false)
}

valenok2003 16.04.2009 16:05

Спаибо за ответ, попробую с этим разобраться.:cray:

ZoNT 16.04.2009 18:05

тебе нужны функции I.sC (setCursor) и I.gC (getCursor). Вот в них разбирайся...

valenok2003 21.04.2009 10:09

Спасибо, это именно то, что было нужно.

valenok2003 21.04.2009 11:48

Всё, вроде допёр.

archi 02.09.2009 23:51

в IE бажит... в остальных браузерах все клево

ZoNT 03.09.2009 14:22

что именно бажит?

archi 03.09.2009 16:28

маска setMask('_tt','99.99.9999');
браузер IE 8:
когда курсор в начальной (крайней левой) позиции, почти всегда нажатие на цифру первый раз не вызывает реакции, а начиная со второго нажатия только начинают набираться цифры. Также когда курсор в начальной левой позиции, нажатие на пробел ведет к сдвигу всей маски ввода вправо (т.е. пробелы печатаются)

кстати, в других браузерах (ff, Opera) поведение при нажатии на пробел тоже не совсем понятно - курсор иногда перемещается в какую-то другую позицию, а иногда остается, где был...

ZoNT 03.09.2009 17:14

Да, в ИЕ ошибки действительно есть, спасибо что выловил, а в ФФ у меня с пробелом всё нормально.


Часовой пояс GMT +3, время: 02:19.