Posizione del cursore con jquery

Tags: 

Problema: ottenere la posizione del cursore all'interno di un textfield (o di una textarea).

La soluzione sembra decisamente problematica a giudicare dalle innumerevoli proposte che si trovano in giro, ognuna con i suoi problemini su qualche versione di qualche browser (il problema principale comunque è sempre lo stesso: IE)

Non ho avuto molto tempo per provare la soluzione adottata su tutti i browser, diciamo che mi sono fidato dei commenti trovati.

Considerando che l'ideale per me era trovare una funzione che si integrasse bene con jquery ho deciso di estrarre prendere spunto dal plugin jqery Masket Input, che permette di ottenere degli input field con delle maschere di inserimento (tra l'altro un plugin interessante che potrei utilizzare in futuro).

Si trova qui: http://plugins.jquery.com/project/maskedinput

Home Page: http://digitalbush.com/projects/masked-input-plugin/

Al di la della funzionalità principale, un metodo non documentato (a parte una riga nel changelog) permette appunto di prelevare (e impostare) la posizione del cursore di un textfield, con una semplice chiamata $(input).caret()

Il risultato è un oggetto { begin: X, end: Y }

Questo il codice della sola funzione:

$.fn.extend({
	caret: function(begin, end) {
		if (this.length == 0) return;
		if (typeof begin == 'number') {
			end = (typeof end == 'number') ? end : begin;
			return this.each(function() {
				if (this.setSelectionRange) {
					this.focus();
					this.setSelectionRange(begin, end);
				} else if (this.createTextRange) {
					var range = this.createTextRange();
					range.collapse(true);
					range.moveEnd('character', end);
					range.moveStart('character', begin);
					range.select();
				}
			});
		} else {
			if (this[0].setSelectionRange) {
				begin = this[0].selectionStart;
				end = this[0].selectionEnd;
			} else if (document.selection && document.selection.createRange) {
				var range = document.selection.createRange();
				begin = 0 - range.duplicate().moveStart('character', -100000);
				end = begin + range.text.length;
			}
			return { begin: begin, end: end };
		}
	}
});

Un'altra soluzione (non jquery) interessante è quella proposta qui:

http://blogs.nitobi.com/alexei/?p=173

Il creatore si è posto il problema di trovare una soluzione ottimale confrontando con altri script. Probabilmente è migliore di quella sopra.

Questo il codice:

getCaretInfo = function(oTextarea) {
	var docObj = oTextarea.ownerDocument;
	var result = {start:0, end:0, caret:0};
 
	if (navigator.appVersion.indexOf("MSIE")!=-1) {
		if (oTextarea.tagName.toLowerCase() == "textarea") {
			if (oTextarea.value.charCodeAt(oTextarea.value.length-1) < 14) {
				oTextarea.value=oTextarea.value.replace(/34/g,'')+String.fromCharCode(28);
			}
			var oRng = docObj.selection.createRange();
			var oRng2 = oRng.duplicate();
			oRng2.moveToElementText(oTextarea);
			oRng2.setEndPoint('StartToEnd', oRng);
			result.end = oTextarea.value.length-oRng2.text.length;
			oRng2.setEndPoint('StartToStart', oRng);
			result.start = oTextarea.value.length-oRng2.text.length; 
			result.caret = result.end;
			if (oTextarea.value.substr(oTextarea.value.length-1) == String.fromCharCode(28)) {
				oTextarea.value = oTextarea.value.substr(0, oTextarea.value.length-1);
			}			
		} else {
			var range = docObj.selection.createRange();
			var r2 = range.duplicate();			
			result.start = 0 - r2.moveStart('character', -100000);
			result.end = result.start + range.text.length;	
			result.caret = result.end;
		}			
	} else {
		result.start = oTextarea.selectionStart;
    	result.end = oTextarea.selectionEnd;
		result.caret = result.end;
	}
	if (result.start < 0) {
		 result = {start:0, end:0, caret:0};
	}	
	return result;
}

Per finire una soluzione jQuery è anche qui, non mi sono fidato ad usarlo solo perchè è ferma da anni (e il blog del creatore è sparito):

http://laboratorium.0xab.cd/jquery/fieldselection/

Aggiungi un commento

Scrivi la risposta in lettere (ad esempio "tre" e non "3")