Fix formatting on change and paste events.

This commit is contained in:
Paulo Reis 2016-08-18 17:56:53 +01:00
parent 26e21732f8
commit 67290fd6a7

View file

@ -99,6 +99,30 @@ define [
groups = $.grep(groups, (n) -> n) # Filter empty groups
groups.join(' ')
formatExpiry = (expiry) ->
parts = expiry.match(/^\D*(\d{1,2})(\D+)?(\d{1,4})?/)
return '' unless parts
mon = parts[1] || ''
sep = parts[2] || ''
year = parts[3] || ''
if year.length > 0
sep = ' / '
else if sep is ' /'
mon = mon.substring(0, 1)
sep = ''
else if mon.length == 2 or sep.length > 0
sep = ' / '
else if mon.length == 1 and mon not in ['0', '1']
mon = "0#{mon}"
sep = ' / '
return mon + sep + year
parseExpiry = (value = "") ->
[month, year] = value.split(/[\s\/]+/, 2)
@ -119,6 +143,7 @@ define [
fromNumber: cardFromNumber
fromType: cardFromType
cardType: cardType
formatExpiry: formatExpiry
formatCardNumber: formatCardNumber
defaultFormat: defaultFormat
defaultInputFormat: defaultInputFormat
@ -137,6 +162,45 @@ define [
false
safeVal = (value, $target) ->
try
cursor = $target.prop('selectionStart')
catch error
cursor = null
last = $target.val()
$target.val(value)
if cursor != null && $target.is(":focus")
cursor = value.length if cursor is last.length
# This hack looks for scenarios where we are changing an input's value such
# that "X| " is replaced with " |X" (where "|" is the cursor). In those
# scenarios, we want " X|".
#
# For example:
# 1. Input field has value "4444| "
# 2. User types "1"
# 3. Input field has value "44441| "
# 4. Reformatter changes it to "4444 |1"
# 5. By incrementing the cursor, we make it "4444 1|"
#
# This is awful, and ideally doesn't go here, but given the current design
# of the system there does not appear to be a better solution.
#
# Note that we can't just detect when the cursor-1 is " ", because that
# would incorrectly increment the cursor when backspacing, e.g. pressing
# backspace in this scenario: "4444 1|234 5".
if last != value
prevPair = last[cursor-1..cursor]
currPair = value[cursor-1..cursor]
digit = value[cursor]
cursor = cursor + 1 if /\d/.test(digit) and
prevPair == "#{digit} " and currPair == " #{digit}"
$target.prop('selectionStart', cursor)
$target.prop('selectionEnd', cursor)
# Replace Full-Width Chars
replaceFullWidthChars = (str = '') ->
fullWidth = '\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19'
@ -160,6 +224,7 @@ define [
value = $target.val()
value = replaceFullWidthChars(value)
value = value.replace(/\D/g, '')
safeVal(value, $target)
# Format Card Number
reFormatCardNumber = (e) ->
@ -168,6 +233,7 @@ define [
value = $target.val()
value = replaceFullWidthChars(value)
value = ccUtils.formatCardNumber(value)
safeVal(value, $target)
formatCardNumber = (e) ->
# Only format if input is a number
@ -249,7 +315,9 @@ define [
setTimeout ->
value = $target.val()
value = replaceFullWidthChars(value)
value = $.payment.formatExpiry(value)
value = ccUtils.formatExpiry(value)
safeVal(value, $target)
formatExpiry = (e) ->
# Only format if input is a number
@ -328,6 +396,7 @@ define [
value = $target.val()
value = replaceFullWidthChars(value)
value = value.replace(/\D/g, '')[0...4]
safeVal(value, $target)
# Restrictions
restrictNumeric = (e) ->
@ -429,11 +498,15 @@ define [
restrict: "A"
require: "ngModel"
link: (scope, el, attrs, ngModel) ->
el.on "keypress", ccFormat.restrictNumeric
el.on "keypress", ccFormat.restrictExpiry
el.on "keypress", ccFormat.formatExpiry
el.on "keypress", ccFormat.formatForwardSlash
el.on "keypress", ccFormat.formatForwardExpiry
el.on "keydown", ccFormat.formatBackExpiry
el.on "change", ccFormat.reFormatExpiry
el.on "input", ccFormat.reFormatExpiry
el.on "paste", ccFormat.reFormatExpiry
ngModel.$parsers.push ccFormat.parseExpiry
ngModel.$formatters.push ccFormat.parseExpiry
@ -442,6 +515,7 @@ define [
restrict: "A"
require: "ngModel"
link: (scope, el, attrs, ngModel) ->
el.on "keypress", ccFormat.restrictNumeric
el.on "keypress", ccFormat.restrictCardNumber
el.on "keypress", ccFormat.formatCardNumber
el.on "keydown", ccFormat.formatBackCardNumber