mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
267 lines
7.1 KiB
JavaScript
267 lines
7.1 KiB
JavaScript
|
/*
|
||
|
* Copyright (c) 2007 Josh Bush (digitalbush.com)
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person
|
||
|
* obtaining a copy of this software and associated documentation
|
||
|
* files (the "Software"), to deal in the Software without
|
||
|
* restriction, including without limitation the rights to use,
|
||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
* copies of the Software, and to permit persons to whom the
|
||
|
* Software is furnished to do so, subject to the following
|
||
|
* conditions:
|
||
|
|
||
|
* The above copyright notice and this permission notice shall be
|
||
|
* included in all copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Version: 1.1
|
||
|
* Release: 2007-09-08
|
||
|
*/
|
||
|
(function($) {
|
||
|
//Helper Functions for Caret positioning
|
||
|
function getCaretPosition(ctl){
|
||
|
var res = {begin: 0, end: 0 };
|
||
|
if (ctl.setSelectionRange){
|
||
|
res.begin = ctl.selectionStart;
|
||
|
res.end = ctl.selectionEnd;
|
||
|
}else if (document.selection && document.selection.createRange){
|
||
|
var range = document.selection.createRange();
|
||
|
res.begin = 0 - range.duplicate().moveStart('character', -100000);
|
||
|
res.end = res.begin + range.text.length;
|
||
|
}
|
||
|
return res;
|
||
|
};
|
||
|
|
||
|
function setCaretPosition(ctl, pos){
|
||
|
if(ctl.setSelectionRange){
|
||
|
ctl.focus();
|
||
|
ctl.setSelectionRange(pos,pos);
|
||
|
}else if (ctl.createTextRange){
|
||
|
var range = ctl.createTextRange();
|
||
|
range.collapse(true);
|
||
|
range.moveEnd('character', pos);
|
||
|
range.moveStart('character', pos);
|
||
|
range.select();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//Predefined character definitions
|
||
|
var charMap={
|
||
|
'9':"[0-9]",
|
||
|
'a':"[A-Za-z]",
|
||
|
'*':"[A-Za-z0-9]"
|
||
|
};
|
||
|
|
||
|
//Helper method to inject character definitions
|
||
|
$.mask={
|
||
|
addPlaceholder : function(c,r){
|
||
|
charMap[c]=r;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
$.fn.unmask=function(){
|
||
|
return this.trigger("unmask");
|
||
|
};
|
||
|
|
||
|
//Main Method
|
||
|
$.fn.mask = function(mask,settings) {
|
||
|
settings = $.extend({
|
||
|
placeholder: "_",
|
||
|
completed: null
|
||
|
}, settings);
|
||
|
|
||
|
//Build Regex for format validation
|
||
|
var reString="^";
|
||
|
for(var i=0;i<mask.length;i++)
|
||
|
reString+=(charMap[mask.charAt(i)] || ("\\"+mask.charAt(i)));
|
||
|
reString+="$";
|
||
|
var re = new RegExp(reString);
|
||
|
|
||
|
return this.each(function(){
|
||
|
var input=$(this);
|
||
|
var buffer=new Array(mask.length);
|
||
|
var locked=new Array(mask.length);
|
||
|
|
||
|
//Build buffer layout from mask
|
||
|
for(var i=0;i<mask.length;i++){
|
||
|
locked[i]=charMap[mask.charAt(i)]==null;
|
||
|
buffer[i]=locked[i]?mask.charAt(i):settings.placeholder;
|
||
|
}
|
||
|
|
||
|
/*Event Bindings*/
|
||
|
function focusEvent(){
|
||
|
checkVal();
|
||
|
writeBuffer();
|
||
|
setTimeout(function(){
|
||
|
setCaretPosition(input[0],0);
|
||
|
},0);
|
||
|
};
|
||
|
input.bind("focus",focusEvent);
|
||
|
|
||
|
input.bind("blur",checkVal);
|
||
|
|
||
|
//Paste events for IE and Mozilla thanks to Kristinn Sigmundsson
|
||
|
if ($.browser.msie)
|
||
|
this.onpaste= function(){setTimeout(checkVal,0);};
|
||
|
else if ($.browser.mozilla)
|
||
|
this.addEventListener('input',checkVal,false);
|
||
|
|
||
|
var ignore=false; //Variable for ignoring control keys
|
||
|
|
||
|
function keydownEvent(e){
|
||
|
var pos=getCaretPosition(this);
|
||
|
var k = e.keyCode;
|
||
|
ignore=(k < 16 || (k > 16 && k < 32 ) || (k > 32 && k < 41));
|
||
|
|
||
|
//delete selection before proceeding
|
||
|
if((pos.begin-pos.end)!=0 && (!ignore || k==8 || k==46)){
|
||
|
clearBuffer(pos.begin,pos.end);
|
||
|
}
|
||
|
//backspace and delete get special treatment
|
||
|
if(k==8){//backspace
|
||
|
while(pos.begin-->=0){
|
||
|
if(!locked[pos.begin]){
|
||
|
buffer[pos.begin]=settings.placeholder;
|
||
|
if($.browser.opera){
|
||
|
//Opera won't let you cancel the backspace, so we'll let it backspace over a dummy character.
|
||
|
writeBuffer(pos.begin);
|
||
|
setCaretPosition(this,pos.begin+1);
|
||
|
}else{
|
||
|
writeBuffer();
|
||
|
setCaretPosition(this,pos.begin);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}else if(k==46){//delete
|
||
|
clearBuffer(pos.begin,pos.begin+1);
|
||
|
writeBuffer();
|
||
|
setCaretPosition(this,pos.begin);
|
||
|
return false;
|
||
|
}else if (k==27){
|
||
|
clearBuffer(0,mask.length);
|
||
|
writeBuffer();
|
||
|
setCaretPosition(this,0);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
};
|
||
|
input.bind("keydown",keydownEvent);
|
||
|
|
||
|
function keypressEvent(e){
|
||
|
if(ignore){
|
||
|
ignore=false;
|
||
|
return;
|
||
|
}
|
||
|
e=e||window.event;
|
||
|
var k=e.charCode||e.keyCode||e.which;
|
||
|
|
||
|
var pos=getCaretPosition(this);
|
||
|
var caretPos=pos.begin;
|
||
|
|
||
|
if(e.ctrlKey || e.altKey){//Ignore
|
||
|
return true;
|
||
|
}else if ((k>=41 && k<=122) ||k==32 || k>186){//typeable characters
|
||
|
while(pos.begin<mask.length){
|
||
|
var reString=charMap[mask.charAt(pos.begin)];
|
||
|
var match;
|
||
|
if(reString){
|
||
|
var reChar=new RegExp(reString);
|
||
|
match=String.fromCharCode(k).match(reChar);
|
||
|
}else{//we're on a mask char, go forward and try again
|
||
|
pos.begin+=1;
|
||
|
pos.end=pos.begin;
|
||
|
caretPos+=1;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(match)
|
||
|
buffer[pos.begin]=String.fromCharCode(k);
|
||
|
else
|
||
|
return false;//reject char
|
||
|
|
||
|
while(++caretPos<mask.length){//seek forward to next typable position
|
||
|
if(!locked[caretPos])
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}else
|
||
|
return false;
|
||
|
|
||
|
writeBuffer();
|
||
|
if(settings.completed && caretPos>=buffer.length)
|
||
|
settings.completed.call(input);
|
||
|
else
|
||
|
setCaretPosition(this,caretPos);
|
||
|
|
||
|
return false;
|
||
|
};
|
||
|
input.bind("keypress",keypressEvent);
|
||
|
|
||
|
/*Helper Methods*/
|
||
|
function clearBuffer(start,end){
|
||
|
for(var i=start;i<end;i++){
|
||
|
if(!locked[i])
|
||
|
buffer[i]=settings.placeholder;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
function writeBuffer(pos){
|
||
|
var s="";
|
||
|
for(var i=0;i<mask.length;i++){
|
||
|
s+=buffer[i];
|
||
|
if(i==pos)
|
||
|
s+=settings.placeholder;
|
||
|
}
|
||
|
input.val(s);
|
||
|
return s;
|
||
|
};
|
||
|
|
||
|
function checkVal(){
|
||
|
//try to place charcters where they belong
|
||
|
var test=input.val();
|
||
|
var pos=0;
|
||
|
for(var i=0;i<mask.length;i++){
|
||
|
if(!locked[i]){
|
||
|
while(pos++<test.length){
|
||
|
//Regex Test each char here.
|
||
|
var reChar=new RegExp(charMap[mask.charAt(i)]);
|
||
|
if(test.charAt(pos-1).match(reChar)){
|
||
|
buffer[i]=test.charAt(pos-1);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
var s=writeBuffer();
|
||
|
if(!s.match(re)){
|
||
|
input.val("");
|
||
|
clearBuffer(0,mask.length);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
input.one("unmask",function(){
|
||
|
input.unbind("focus",focusEvent);
|
||
|
input.unbind("blur",checkVal);
|
||
|
input.unbind("keydown",keydownEvent);
|
||
|
input.unbind("keypress",keypressEvent);
|
||
|
if ($.browser.msie)
|
||
|
this.onpaste= null;
|
||
|
else if ($.browser.mozilla)
|
||
|
this.removeEventListener('input',checkVal,false);
|
||
|
});
|
||
|
|
||
|
});
|
||
|
};
|
||
|
})(jQuery);
|