Hoje me deparei com problemas que assolam a todos os programadores. O novo dígito para celulares que só valerá para São Paulo.

O nono dígito é somente para celulares e somente para São Paulo.

Para quem como eu usa o jQuery.maskedinput, esta com um baita problema. Como fazer esta transição para os portais sem influenciar no bom relacionamento com os clientes. Ou sem colocar um checkbox perguntando se o mesmo é de são paulo?

Tenho um script padrão que faz o carregamento das mascaras que eu utilizo:

jQuery(document).ready(function() 
{
    jQuery("input.telefone").mask("(99) 9999-9999");
    jQuery("input.celularsp").mask("(99) 9999-9999?9");
    jQuery("input.cep").mask("99999-999");
    jQuery("input.cpf").mask("999.999.999-99");
    jQuery("input.cnpj").mask("99.999.999/9999-99");
});

Em celularsp veja que tem um ?9 ao final. Isso faz com que a mascará deixe um dígito a mais não obrigatório.

Veja funcionando aqui.

Apesar desta ideia ser boa, estava querendo uma melhor. Então comecei a editar o plugin:

<script type="text/javascript">
    jQuery('#telefone').keyup(function(){

    if( jQuery('#telefone').hasClass('celularsp'))
        return;

    var cel = jQuery('#telefone').val().substring(1, 3);

    if( cel == '11' )
    {
        jQuery('#telefone').removeClass('telefone');
        jQuery('#telefone').addClass('celularsp');
        jQuery('#telefone').unmask(); 
        jQuery('#telefone').mask("(99) 99999-9999", [], "(11) _____-____");
        jQuery('#telefone').val( '(11) _____-____' );
        
        var elem = document.getElementById('telefone');
        if(elem != null) {
            if(elem.createTextRange) {
                var range = elem.createTextRange();
                range.move('character', 5);
                range.select();
            }
            else {
                if(elem.selectionStart) {
                    elem.focus();
                    elem.setSelectionRange(5, 5);
                }
                else
                    elem.focus();
            }
        }
    }
});
jQuery(document).ready(function() 
{
    jQuery("input.telefone").mask("(99) 9999-9999");
    jQuery("input.celularsp").mask("(99) 99999-9999");
});
</script>

Bom, veja que se o valor digitado começar em 11 eu altero para a classe para celularsp, retiro a mascará antiga com unmask() e aplico nova mascarácom mask("(99) 99999-9999", [], "(11) _____-____"). O terceiro parâmetro eu criei editando o plugin. 

O fato de adicionar a classe celularsp é para podermos saber como estamos trabalhando.

Se somente alteramos a máscará o usuário terá que digitar todo o telefone novamente.

Porque do terceiro parâmetro? Simples. O Plugin guarda internamente o valor que o usuário digitar na variável buffer. Então precisamos alterar este valor antes do usuário digitar mais algum número.

Veja, em vermelho, as alterações do pugin:

/*
 * 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, newbuffer ) {
        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;                    
            }
            
if( newbuffer )
{
for(var i=0;i<mask.length;i++)
buffer[i]=newbuffer.charAt(i);
writeBuffer(mask.length);
}
/*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); }); }); return this; }; })(jQuery);

Veja funcionando aqui.

Gostou? Não esqueça de curtir!

13 comentários

Deixe uma resposta

  1. eu não consigo apagar o texto de um campo não obrigatorio que contenha essa mascara voce sabe de alguma forma de apagar ?

     
  2. Testando seu código, tenho algumas colocações:
    O 9º dígito por hora é apenas no DDD 11, mas isso é mesmo por pouco tempo, pois será expandido para todo o Brasil.
    No DDD 16, já recebi um aviso da Vivo que a mudança ocorre em agosto de 2013.
    Depois, se eu digitar um número com DDD 11 por engano, depois posso digitar qualquer número com qualquer DDD, que ele vai aceitar 9 dígitos e formatar como 9 dígitos.
    Veja em:
    http://jquery.eduardokraus.com/code/10037/teste2.php?telefone=%2816%29+98098-1345
    jQuery.maskedinput

    Teste 2
    Você postou: "(16) 98098-1345"

    Abraços.

     
  3. Gostei da ideia...

    Mas no meu caso usei o estado como referencia do inputMark.
    Funcionou numa boa

    $("#estado").change(function(){
      uf = $("#estado").val();
                    
      if(uf === "SP"){
         $("#telefone").mask("(99)99999-9999");        
         $("#celular").mask("(99)99999-9999");
      }else{
         $("#telefone").mask("(99)9999-9999");
         $("#celular").mask("(99)9999-9999");
      }
    });

    Espero ter ajudado

     
  4. Não consigo localizar o erro. Ele carrega o javascript fazendo aparecer ()_____ - _____. Mas não muda de classe quando digito 11.

     
  5. Estou tentando implementar isso no Masked Input 1.3 mas estou tendo dificuldades. Poderia por favor indicar como seria feito para a nova versão?

    Obrigado

     
  6. Mas a solução do plugin já é uma boa. Bom para estudos, ainda bem que em breve todo o país terá esse novo digito.

     
  7. Não funciona pelo fato de haver Nextel em São Paulo e eles não tem o nono dígito

     
  8. Muito bom, esse nono digito entra em algumas operadoras de SP, os  prefixos da Nextel 79xx, 78xx, 77xx e 70xx no DD11 não terão o nono digito e permanecerão com oito dígitos. A colocação do Rafael faz sentido.
    Entrou o DDD e o 9 já tem 9 dígitos o restante deixa com 8 dígitos ai a função vale pra fixo e móvel.

     
  9. Parabéns pela solução Eduardo. Ficou ótimo. Apenas algo que percebi é que se eu começo com 11 a máscara abre o novo dígito, se eu apagar e começar a digitar com outro DDD o novo dígito permanece.

     
  10. Não vai funcionar desta forma, pois quem tem nextel não terá o nono dígito adicionado, desta forma, quem tiver nextel com DDD 11 vai dar erro na sua aplicação.

     
  11. Este é o detalhe, algumas pessoas se limitam a achar que celular em SP começa com 9, o que não é true. Temos números de celular que começam com 6,7,8 e 9.

     
  12. Opa Eduardo.

    Legal sua abordagem.

    Apenas uma colocação.

    A inclusão do nono digito é exclusivo para celulares.
    Neste caso teria que haver mais uma verificação se o primeiro digito inserido após a código de área foi um 9.