Skip to content

Commit 6454948

Browse files
authored
PCIP-642: add expiration date to basic sample (#29)
1 parent ed4a8ea commit 6454948

10 files changed

Lines changed: 155 additions & 87 deletions

File tree

angular-14-example/src/app/secure-fields.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export class SecureFieldsService {
5252
});
5353

5454
this.secureFields.on('change', (data: any) => {
55-
// Fill epxiry date on card autocomplete
55+
// Fill expiration date date on card autocomplete
5656
if(!data.fields.cardNumber.paymentMethod) {
5757
this.cardType = 'Unknown';
5858
}

assets/js/expirationdate.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
function formatExpirationDate (val) {
2+
var p1 = parseInt(val[0], 10),
3+
p2 = parseInt(val[1], 10);
4+
5+
return /^\d$/.test(val) && "0" !== val && "1" !== val
6+
? "0" + val + " / "
7+
: /^\d\d$/.test(val)
8+
? p2 > 2 && 0 !== p1 ? "0" + p1 + " / " + p2 : "" + val + " / "
9+
: val
10+
}
11+
12+
function handleExpirationDate(element, focusOnFilled) {
13+
['input', 'keydown', 'keyup', 'mousedown', 'mouseup', 'select', 'contextmenu', 'drop'].forEach(function (key) {
14+
element.addEventListener(key, function (e) {
15+
if (/^\d+$/.test(e.key)) {
16+
this.value = formatExpirationDate(this.value);
17+
}
18+
19+
if (/^\d{0,2}[\/]?\d{0,2}/.test(this.value)) {
20+
this.oldValue = this.value;
21+
this.oldSelectionStart = this.selectionStart;
22+
this.oldSelectionEnd = this.selectionEnd;
23+
} else if (this.hasOwnProperty('oldValue')) {
24+
this.value = this.oldValue;
25+
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
26+
} else {
27+
this.value = '';
28+
}
29+
if (this.oldSelectionEnd === 7 && key === 'keyup' && e.key.match(/^[0-9]$/)) {
30+
secureFields.focus(focusOnFilled);
31+
}
32+
});
33+
});
34+
}
35+
36+
function getExpirationDateObject (value) {
37+
var split = value.split('/')
38+
expm = split[0].trim();
39+
expy = split[1].trim();
40+
41+
return {
42+
expm: expm,
43+
expy: expy
44+
};
45+
}

index.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
</head>
1010
<body style="margin: 0;">
1111
<nav style="text-align: center; background: #213d62; padding: 10px; margin-bottom: 40px;">
12-
<a style="color: #fff; margin: 0 10px; text-decoration: none;" href="pciproxy-examples/index.html">Basic Example</a>
13-
<a style="color: #fff; margin: 0 10px; text-decoration: none;" href="pciproxy-examples/inline-example.html">Inline Example</a>
14-
<a style="color: #fff; margin: 0 10px; text-decoration: none;" href="pciproxy-examples/floating-label.html">Floating Label Example</a>
15-
<a style="color: #fff; margin: 0 10px; text-decoration: none;" href="pciproxy-examples/iban.html">IBAN Example</a>
16-
<a style="color: #fff; margin: 0 10px; text-decoration: none;" href="pciproxy-examples/account.html">Account Number Example</a>
12+
<a style="color: #fff; margin: 0 10px; text-decoration: none;" href="pciproxy-examples/index.html">Basic</a>
13+
<a style="color: #fff; margin: 0 10px; text-decoration: none;" href="pciproxy-examples/inline-example.html">Inline</a>
14+
<a style="color: #fff; margin: 0 10px; text-decoration: none;" href="pciproxy-examples/floating-label.html">Floating Label</a>
15+
<a style="color: #fff; margin: 0 10px; text-decoration: none;" href="pciproxy-examples/iban.html">IBAN</a>
16+
<a style="color: #fff; margin: 0 10px; text-decoration: none;" href="pciproxy-examples/account.html">Account Number</a>
1717
</nav>
1818
<p style="text-align: center;">Please select an example above.</p>
1919
<script>

pciproxy-examples/account.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
</head>
1010
<body style="margin: 0;">
1111
<nav style="text-align: center; background: #213d62; padding: 10px; margin-bottom: 40px;">
12-
<a href="index.html">Basic Example</a>
13-
<a href="inline-example.html">Inline Example</a>
14-
<a href="floating-label.html">Floating Label Example</a>
15-
<a href="iban.html">IBAN Example</a>
16-
<a style="text-decoration: underline;" href="account.html">Account Number Example</a>
12+
<a href="index.html">Basic</a>
13+
<a href="inline-example.html">Inline</a>
14+
<a href="floating-label.html">Floating Label</a>
15+
<a href="iban.html">IBAN</a>
16+
<a style="text-decoration: underline;" href="account.html">Account Number</a>
1717
<a href="show.html">Reveal Card (Show API)</a>
1818
</nav>
1919
<form style="max-width: 400px; margin: 0 auto;">

pciproxy-examples/floating-label.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
</head>
1010
<body style="margin: 0;">
1111
<nav style="text-align: center; background: #213d62; padding: 10px; margin-bottom: 40px;">
12-
<a href="index.html">Basic Example</a>
13-
<a href="inline-example.html">Inline Example</a>
14-
<a style="text-decoration: underline;" href="floating-label.html">Floating Label Example</a>
15-
<a href="iban.html">IBAN Example</a>
16-
<a href="account.html">Account Number Example</a>
12+
<a href="index.html">Basic</a>
13+
<a href="inline-example.html">Inline</a>
14+
<a style="text-decoration: underline;" href="floating-label.html">Floating Label</a>
15+
<a href="iban.html">IBAN</a>
16+
<a href="account.html">Account Number</a>
1717
<a href="show.html">Reveal Card (Show API)</a>
1818
</nav>
1919
<form style="max-width: 400px; margin: 0 auto;">

pciproxy-examples/iban.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
</head>
1010
<body style="margin: 0;">
1111
<nav style="text-align: center; background: #213d62; padding: 10px; margin-bottom: 40px;">
12-
<a href="index.html">Basic Example</a>
13-
<a href="inline-example.html">Inline Example</a>
14-
<a href="floating-label.html">Floating Label Example</a>
15-
<a style="text-decoration: underline;" href="iban.html">IBAN Example</a>
16-
<a href="account.html">Account Number Example</a>
12+
<a href="index.html">Basic</a>
13+
<a href="inline-example.html">Inline</a>
14+
<a href="floating-label.html">Floating Label</a>
15+
<a style="text-decoration: underline;" href="iban.html">IBAN</a>
16+
<a href="account.html">Account Number</a>
1717
<a href="show.html">Reveal Card (Show API)</a>
1818
</nav>
1919
<form style="max-width: 400px; margin: 0 auto;">

pciproxy-examples/index.html

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
66
<title>PCI Proxy Web Tokenization</title>
77
<script src="https://pay.sandbox.datatrans.com/upp/payment/js/secure-fields-2.0.0.min.js"></script>
8+
<script src="../assets/js/expirationdate.js"></script>
89
<link rel="stylesheet" type="text/css" href="../assets/css/stylesheet.css">
910
</head>
1011
<body style="margin: 0;">
1112
<nav style="text-align: center; background: #213d62; padding: 10px; margin-bottom: 40px;">
12-
<a style="text-decoration: underline;" href="index.html">Basic Example</a>
13-
<a href="inline-example.html">Inline Example</a>
14-
<a href="floating-label.html">Floating Label Example</a>
15-
<a href="iban.html">IBAN Example</a>
16-
<a href="account.html">Account Number Example</a>
13+
<a style="text-decoration: underline;" href="index.html">Basic</a>
14+
<a href="inline-example.html">Inline</a>
15+
<a href="floating-label.html">Floating Label</a>
16+
<a href="iban.html">IBAN</a>
17+
<a href="account.html">Account Number</a>
1718
<a href="show.html">Reveal card (Show API)</a>
1819
</nav>
1920
<form style="max-width: 400px; margin: 0 auto;">
@@ -35,9 +36,23 @@
3536
</div>
3637
</div>
3738
</div>
38-
<div style="max-width: 150px; margin-top: 20px">
39+
<div style="margin-top: 20px; display: flex; flex-flow: row wrap; justify-content: space-between">
40+
<!-- Expiry date -->
41+
<div id="expiry-container" class="secure-field secure-field__input secure-field__base secure-field__has-actions secure-field__has-card-icon" style="max-width: 150px;">
42+
<label for="expiry">Expiration Date</label>
43+
<div class="secure-field--input-container" style="height: 40px">
44+
<input id="expiry" type="tel" maxlength="7" placeholder="MM / YY" class="secure-field--input" style="height: 40px; outline: none; font-size: 100%" autocomplete="off" />
45+
<div class="secure-field--actions">
46+
<span class="secure-field--action secure-field--action__card-icon">
47+
<span class="secure-field--action-card-wrap">
48+
<img class="secure-field--card-icon secure-field--card-icon__error" src="../assets/img/cvc-error.svg">
49+
</span>
50+
</span>
51+
</div>
52+
</div>
53+
</div>
3954
<!-- CVV markup -->
40-
<div id="cvv-container" class="secure-field secure-field__input secure-field__base secure-field__has-actions secure-field__has-card-icon">
55+
<div id="cvv-container" class="secure-field secure-field__input secure-field__base secure-field__has-actions secure-field__has-card-icon" style="max-width: 150px;">
4156
<label for="cvv-number">CVV</label>
4257
<div class="secure-field--input-container" style="height: 40px">
4358
<div class="secure-field--input" id="cvv-number"></div>
@@ -91,6 +106,7 @@
91106

92107
var cardContainer = document.getElementById('card-number-container');
93108
var cvvContainer = document.getElementById('cvv-container');
109+
var expiryContainer = document.getElementById('expiry-container')
94110

95111
// Set focus to input fields when clicking containers
96112
cardContainer.addEventListener('click', function () {
@@ -102,6 +118,21 @@
102118

103119
// Set class names when fields change
104120
secureFields.on('change', function (data) {
121+
// Fill expiration date date on card autocomplete
122+
if (data.event.type === 'autocomplete') {
123+
if (data.event.field === 'expiryYear') {
124+
var value = (expiryInput.value || '/')
125+
expiryInput.value = value.split('/')[0].trim() + ' / ' + data.event.value.slice(-2)
126+
return
127+
}
128+
129+
if (data.event.field === 'expiryMonth') {
130+
var value = (expiryInput.value || '/')
131+
expiryInput.value = data.event.value + ' / ' + value.split('/')[1].trim()
132+
return
133+
}
134+
}
135+
105136
var cardImage = cardContainer.querySelector('.secure-field--card-icon__recognized-card');
106137
cardContainer.classList.remove('secure-field__has-error');
107138
cvvContainer.classList.remove('secure-field__has-error');
@@ -132,7 +163,21 @@
132163
});
133164

134165
document.getElementById('form-submit').addEventListener('click', function () {
135-
secureFields.submit();
166+
// validate your expiration date field here
167+
var result
168+
try {
169+
result = getExpirationDateObject(document.getElementById('expiry').value)
170+
} catch {
171+
// nothing to catch here
172+
}
173+
if (result) {
174+
secureFields.submit({
175+
expm: result.expm,
176+
expy: result.expy
177+
});
178+
return;
179+
}
180+
expiryContainer.classList.add('secure-field__has-error');
136181
});
137182

138183
secureFields.on('success', function (data) {
@@ -142,6 +187,11 @@
142187
result.style.display = 'block';
143188
}
144189
});
190+
191+
document.getElementById("expiry").addEventListener('input', function () {
192+
expiryContainer.classList.remove('secure-field__has-error');
193+
});
194+
handleExpirationDate(document.getElementById("expiry"), "cvv");
145195
</script>
146196
<style>
147197
/* The following styles are NOT required */

pciproxy-examples/inline-example.html

Lines changed: 25 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
66
<title>PCI Proxy Web Tokenization</title>
77
<script src="https://pay.sandbox.datatrans.com/upp/payment/js/secure-fields-2.0.0.min.js"></script>
8+
<script src="../assets/js/expirationdate.js"></script>
89
<link rel="stylesheet" type="text/css" href="../assets/css/stylesheet.css">
910
<link rel="stylesheet" type="text/css" href="../assets/css/inline.css">
1011
</head>
1112
<body style="margin: 0;">
1213
<nav style="text-align: center; background: #213d62; padding: 10px; margin-bottom: 40px;">
13-
<a href="index.html">Basic Example</a>
14-
<a style="text-decoration: underline;" href="inline-example.html">Inline Example</a>
15-
<a href="floating-label.html">Floating Label Example</a>
16-
<a href="iban.html">IBAN Example</a>
17-
<a href="account.html">Account Number Example</a>
14+
<a href="index.html">Basic</a>
15+
<a style="text-decoration: underline;" href="inline-example.html">Inline</a>
16+
<a href="floating-label.html">Floating Label</a>
17+
<a href="iban.html">IBAN</a>
18+
<a href="account.html">Account Number</a>
1819
<a href="show.html">Reveal Card (Show API)</a>
1920
</nav>
2021
<form style="max-width: 390px; margin: 0 auto;">
@@ -36,7 +37,7 @@
3637
</div>
3738
</div>
3839
<div>
39-
<input id="expiry" name="expiry" placeholder="MM/YY" type="tel" maxlength="7" />
40+
<input id="expiry" name="expiry" placeholder="MM/YY" type="tel" maxlength="7" autocomplete="off" />
4041
</div>
4142
<!-- CVV markup -->
4243
<div id="cvv-container" class="secure-field secure-field__input secure-field__base">
@@ -55,45 +56,6 @@
5556
<footer>
5657
<a href="https://github.com/datatrans/secure-fields-sample/blob/master/pciproxy-examples/inline-example.html">View this page on GitHub</a>
5758
</footer>
58-
<script>
59-
// Expiry date
60-
function setInputFilter(textbox, inputFilter) {
61-
['input', 'keydown', 'keyup', 'mousedown', 'mouseup', 'select', 'contextmenu', 'drop'].forEach(function (key) {
62-
textbox.addEventListener(key, function (e) {
63-
if (/^\d+$/.test(e.key)) {
64-
this.value = formatExpriy(this.value);
65-
}
66-
67-
if (inputFilter(this.value)) {
68-
this.oldValue = this.value;
69-
this.oldSelectionStart = this.selectionStart;
70-
this.oldSelectionEnd = this.selectionEnd;
71-
} else if (this.hasOwnProperty('oldValue')) {
72-
this.value = this.oldValue;
73-
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
74-
} else {
75-
this.value = '';
76-
}
77-
if (this.oldSelectionEnd === 7 && key === 'keyup' && e.key.match(/^[0-9]$/)) {
78-
secureFields.focus('cvv');
79-
}
80-
});
81-
});
82-
}
83-
84-
setInputFilter(document.getElementById("expiry"), function(value) { return /^\d{0,2}[\/]?\d{0,2}/.test(value); });
85-
86-
function formatExpriy (val) {
87-
var p1 = parseInt(val[0], 10),
88-
p2 = parseInt(val[1], 10);
89-
90-
return /^\d$/.test(val) && "0" !== val && "1" !== val
91-
? "0" + val + " / "
92-
: /^\d\d$/.test(val)
93-
? p2 > 2 && 0 !== p1 ? "0" + p1 + " / " + p2 : "" + val + " / "
94-
: val
95-
}
96-
</script>
9759
<script>
9860
// Credit Card and CVV
9961
var secureFields = new SecureFields();
@@ -138,7 +100,7 @@
138100
});
139101

140102
secureFields.on('change', function (data) {
141-
// Fill epxiry date on card autocomplete
103+
// Fill expiration date date on card autocomplete
142104
if (data.event.type === 'autocomplete') {
143105
if (data.event.field === 'expiryYear') {
144106
var value = (expiryInput.value || '/')
@@ -170,7 +132,7 @@
170132
cardImage.src = '../assets/img/brands/' + data.fields.cardNumber.paymentMethod + '.svg';
171133
cardContainer.classList.add('secure-field__is-recognized');
172134
}
173-
if (data.event.type === 'keyUp' && data.event.field === 'cardNumber' && data.event.eventData.isNumber && data.fields.cardNumber.valid) {
135+
if (data.event.type === 'keyUp' && data.event.field === 'cardNumber' && data.event.eventData && data.event.eventData.isNumber && data.fields.cardNumber.valid) {
174136
document.getElementById('expiry').focus();
175137
}
176138
})
@@ -196,12 +158,21 @@
196158
});
197159

198160
document.getElementById('form-submit').addEventListener('click', function () {
199-
// validate your expiry field here
200-
if (document.getElementById('expiry').value !== '') {
201-
secureFields.submit();
202-
} else {
203-
paymentContainer.classList.add('field__has-error');
161+
// validate your expiration date field here
162+
var result
163+
try {
164+
result = getExpirationDateObject(document.getElementById('expiry').value)
165+
} catch {
166+
// nothing to catch here
204167
}
168+
if (result) {
169+
secureFields.submit({
170+
expm: result.expm,
171+
expy: result.expy
172+
});
173+
return;
174+
}
175+
paymentContainer.classList.add('field__has-error');
205176
});
206177

207178
secureFields.on('success', function (data) {
@@ -211,6 +182,8 @@
211182
result.style.display = 'block';
212183
}
213184
});
185+
186+
handleExpirationDate(document.getElementById("expiry"), "cvv");
214187
</script>
215188
<style>
216189
/* The following styles are NOT required */

pciproxy-examples/show.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
</head>
1010
<body style="margin: 0;">
1111
<nav style="text-align: center; background: #213d62; padding: 10px; margin-bottom: 40px;">
12-
<a href="index.html">Basic Example</a>
13-
<a href="inline-example.html">Inline Example</a>
14-
<a href="floating-label.html">Floating Label Example</a>
15-
<a href="iban.html">IBAN Example</a>
16-
<a href="account.html">Account Number Example</a>
12+
<a href="index.html">Basic</a>
13+
<a href="inline-example.html">Inline</a>
14+
<a href="floating-label.html">Floating Label</a>
15+
<a href="iban.html">IBAN</a>
16+
<a href="account.html">Account Number</a>
1717
<a style="text-decoration: underline;" href="show.html">Reveal Card (Show API)</a>
1818
</nav>
1919
<div style="max-width: 400px; margin: 0 auto;">

react-example-init/src/securefields/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export function SecureFields({
147147
<Icon fieldType={fields.cvv.placeholderElementId} iconType={cvvIcon} />
148148
</Field>
149149
<div className='pb-2 pl-2'>
150-
<label>Expiry Date</label>
150+
<label>Expiration Date</label>
151151
<div className='flex items-end'>
152152
<input
153153
type='tel'

0 commit comments

Comments
 (0)