jQuery Положение курсора «Прыжки» на Safari & Edge - PullRequest
0 голосов
/ 21 января 2020

Я использую jQuery маскировку и проверку при вводе формы для кредитных карт. Похоже, что он отлично работает на Chrome и Firefox, но в Safari (настольном и мобильном) и Microsoft Edge несколько неожиданно работает.

  1. Курсор «перепрыгивает» в конец кредита поле номера карты при попытке ввода информации в поле CVV. После каждого нажатия клавиши в поле CVV курсор перемещается в поле номера карты.
  2. Автоматическое заполнение не работает в поле Имя. В Safari появляется предложение, но нажатие на него не дает результата.

Я не очень хорошо разбираюсь в Javascript или jQuery и создал этот код на основе нескольких различных примеров, которые я нашел в Интернете. Любая помощь в диагностике это очень ценится.

Javascript / jQuery:

var acceptedCreditCards = {
  visa: /^4[0-9]{12}(?:[0-9]{3})?$/,
  mastercard: /^5[1-5][0-9]{14}$|^2(?:2(?:2[1-9]|[3-9][0-9])|[3-6][0-9][0-9]|7(?:[01][0-9]|20))[0-9]{12}$/,
  amex: /^3[47][0-9]{13}$/,
  discover: /^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})$/,
  diners_club: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
  jcb: /^(?:2131|1800|35[0-9]{3})[0-9]{11}$/,
};

$('#cc, #cvv').on('input', function(){
  if (validateCard($('#cc').val()) && validateCVV($('#cc').val(), $('#cvv').val())) {
    $('#disabled').prop('disabled', false);
  } else {
    $('#disabled').prop('disabled', true);
  }

  var node = $('#cc')[0]; // vanilla javascript element
  var cursor = node.selectionStart; // store cursor position
  var lastValue = $('#cc').val(); // get value before formatting

  var formattedValue = formatCardNumber(lastValue);
  $('#cc').val(formattedValue); // set value to formatted

  // keep the cursor at the end on addition of spaces
  if(cursor === lastValue.length) {
    cursor = formattedValue.length;
    // decrement cursor when backspacing
    // i.e. "4444 |" => backspace => "4444|"
    if($('#cc').attr('data-lastvalue') && $('#cc').attr('data-lastvalue').charAt(cursor - 1) == " ") {
      cursor--;
    }
  }

  if (lastValue != formattedValue) {
    // increment cursor when inserting character before a space
    // i.e. "1234| 6" => "5" typed => "1234 5|6"
    if(lastValue.charAt(cursor) == " " && formattedValue.charAt(cursor - 1) == " ") {
      cursor++;
    }
  }

  // set cursor position
  node.selectionStart = cursor;
  node.selectionEnd = cursor;
  // store last value
  $('#cc').attr('data-lastvalue', formattedValue);
});

function formatCardNumber(value) {
  // remove all non digit characters
  var value = value.replace(/\D/g, '');
  var formattedValue;
  var maxLength;
  // american express, 15 digits
  if ((/^3[47]\d{0,13}$/).test(value)) {
    formattedValue = value.replace(/(\d{4})/, '$1 ').replace(/(\d{4}) (\d{6})/, '$1 $2 ');
    maxLength = 17;
  } else if((/^3(?:0[0-5]|[68]\d)\d{0,11}$/).test(value)) { // diner's club, 14 digits
    formattedValue = value.replace(/(\d{4})/, '$1 ').replace(/(\d{4}) (\d{6})/, '$1 $2 ');
    maxLength = 16;
  } else if ((/^\d{0,16}$/).test(value)) { // regular cc number, 16 digits
    formattedValue = value.replace(/(\d{4})/, '$1 ').replace(/(\d{4}) (\d{4})/, '$1 $2 ').replace(/(\d{4}) (\d{4}) (\d{4})/, '$1 $2 $3 ');
    maxLength = 19;
  }

  $('#cc').attr('maxlength', maxLength);
  return formattedValue;
}


function validateCard(value) {
  // remove all non digit characters
  var value = value.replace(/\D/g, '');
  var sum = 0;
  var shouldDouble = false;
  // loop through values starting at the rightmost side
  for (var i = value.length - 1; i >= 0; i--) {
    var digit = parseInt(value.charAt(i));

    if (shouldDouble) {
      if ((digit *= 2) > 9) digit -= 9;
    }

    sum += digit;
    shouldDouble = !shouldDouble;
  }

  var valid = (sum % 10) == 0;
  var accepted = false;

  // loop through the keys (visa, mastercard, amex, etc.)
  Object.keys(acceptedCreditCards).forEach(function(key) {
    var regex = acceptedCreditCards[key];
    if (regex.test(value)) {
      accepted = true;
    }
  });

  return valid && accepted;
}


function validateCVV(creditCard, cvv) {
  // remove all non digit characters
  var creditCard = creditCard.replace(/\D/g, '');
  var cvv = cvv.replace(/\D/g, '');
  // american express and cvv is 4 digits
  if ((acceptedCreditCards.amex).test(creditCard)) {
    if((/^\d{4}$/).test(cvv))
      return true;
  } else if ((/^\d{3}$/).test(cvv)) { // other card & cvv is 3 digits
    return true;
  }
  return false;
}

HTML:

<form method="post" action="thank-you.php">
            <div class="cart">
                <div class="cc_form checkout_form_style">
                    <h4>Payment Information</h4>
                    <div class="row">
                    <div class="col-25"><label for="cc">Card Number</label></div>
                    <div class="col-75"><input inputmode="numeric" id="cc" type="text" name="creditcard" placeholder="XXXX XXXX XXXX XXXX">
                    </div></div>
                    <div class="row">
                    <div class="col-25"><label for="cc_name">Name on Card</label></div>
                    <div class="col-75"><input id="cc_name" type="text" name="cc_name" placeholder="John Smith">
                    </div></div>
                    <div class="row">
                    <div class="col-25"><label for="cvv">CVV/CID</label></div>
                    <div class="col-75"><input inputmode="numeric" id="cvv" type="text" name="cvv" placeholder="123">
                    </div></div>
                    <div class="row">
                    <div class="col-25"><label for="cc_month">Exp Month</label></div>
                    <div class="col-75">
                        <select id="cc_month" name="cc_month">
                            <option value="01">01-January</option>
                            <option value="02">02-February</option>
                            <option value="03">03-March</option>
                            <option value="04">04-April</option>
                            <option value="05">05-May</option>
                            <option value="06">06-June</option>
                            <option value="07">07-July</option>
                            <option value="08">08-August</option>
                            <option value="09">09-September</option>
                            <option value="10">10-October</option>
                            <option value="11">11-November</option>
                            <option value="12">12-December</option>
                        </select>
                    </div></div>
                    <div class="row">
                    <div class="col-25"><label for="cc_year">Exp Year</label></div>
                    <div class="col-75">
                        <select id="cc_year" name="cc_year">
                            <option value="2020">2020</option>
                            <option value="2021">2021</option>
                            <option value="2022">2022</option>
                            <option value="2023">2023</option>
                            <option value="2024">2024</option>
                            <option value="2025">2025</option>
                        </select>
                    </div></div>
                </div>
                <input id="disabled" type="submit" name="payment" class="button dark bgcolor2" value="Pay Now" disabled>
                </form>
...