svelte-cleavejs
Version:
Cleave.js action for Svelte
1,397 lines (1,108 loc) • 56 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Cleavejs = {}));
})(this, (function (exports) { 'use strict';
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
var NumeralFormatter = function (numeralDecimalMark,
numeralIntegerScale,
numeralDecimalScale,
numeralThousandsGroupStyle,
numeralPositiveOnly,
stripLeadingZeroes,
prefix,
signBeforePrefix,
tailPrefix,
delimiter) {
var owner = this;
owner.numeralDecimalMark = numeralDecimalMark || '.';
owner.numeralIntegerScale = numeralIntegerScale > 0 ? numeralIntegerScale : 0;
owner.numeralDecimalScale = numeralDecimalScale >= 0 ? numeralDecimalScale : 2;
owner.numeralThousandsGroupStyle = numeralThousandsGroupStyle || NumeralFormatter.groupStyle.thousand;
owner.numeralPositiveOnly = !!numeralPositiveOnly;
owner.stripLeadingZeroes = stripLeadingZeroes !== false;
owner.prefix = (prefix || prefix === '') ? prefix : '';
owner.signBeforePrefix = !!signBeforePrefix;
owner.tailPrefix = !!tailPrefix;
owner.delimiter = (delimiter || delimiter === '') ? delimiter : ',';
owner.delimiterRE = delimiter ? new RegExp('\\' + delimiter, 'g') : '';
};
NumeralFormatter.groupStyle = {
thousand: 'thousand',
lakh: 'lakh',
wan: 'wan',
none: 'none'
};
NumeralFormatter.prototype = {
getRawValue: function (value) {
return value.replace(this.delimiterRE, '').replace(this.numeralDecimalMark, '.');
},
format: function (value) {
var owner = this, parts, partSign, partSignAndPrefix, partInteger, partDecimal = '';
// strip alphabet letters
value = value.replace(/[A-Za-z]/g, '')
// replace the first decimal mark with reserved placeholder
.replace(owner.numeralDecimalMark, 'M')
// strip non numeric letters except minus and "M"
// this is to ensure prefix has been stripped
.replace(/[^\dM-]/g, '')
// replace the leading minus with reserved placeholder
.replace(/^\-/, 'N')
// strip the other minus sign (if present)
.replace(/\-/g, '')
// replace the minus sign (if present)
.replace('N', owner.numeralPositiveOnly ? '' : '-')
// replace decimal mark
.replace('M', owner.numeralDecimalMark);
// strip any leading zeros
if (owner.stripLeadingZeroes) {
value = value.replace(/^(-)?0+(?=\d)/, '$1');
}
partSign = value.slice(0, 1) === '-' ? '-' : '';
if (typeof owner.prefix != 'undefined') {
if (owner.signBeforePrefix) {
partSignAndPrefix = partSign + owner.prefix;
} else {
partSignAndPrefix = owner.prefix + partSign;
}
} else {
partSignAndPrefix = partSign;
}
partInteger = value;
if (value.indexOf(owner.numeralDecimalMark) >= 0) {
parts = value.split(owner.numeralDecimalMark);
partInteger = parts[0];
partDecimal = owner.numeralDecimalMark + parts[1].slice(0, owner.numeralDecimalScale);
}
if(partSign === '-') {
partInteger = partInteger.slice(1);
}
if (owner.numeralIntegerScale > 0) {
partInteger = partInteger.slice(0, owner.numeralIntegerScale);
}
switch (owner.numeralThousandsGroupStyle) {
case NumeralFormatter.groupStyle.lakh:
partInteger = partInteger.replace(/(\d)(?=(\d\d)+\d$)/g, '$1' + owner.delimiter);
break;
case NumeralFormatter.groupStyle.wan:
partInteger = partInteger.replace(/(\d)(?=(\d{4})+$)/g, '$1' + owner.delimiter);
break;
case NumeralFormatter.groupStyle.thousand:
partInteger = partInteger.replace(/(\d)(?=(\d{3})+$)/g, '$1' + owner.delimiter);
break;
}
if (owner.tailPrefix) {
return partSign + partInteger.toString() + (owner.numeralDecimalScale > 0 ? partDecimal.toString() : '') + owner.prefix;
}
return partSignAndPrefix + partInteger.toString() + (owner.numeralDecimalScale > 0 ? partDecimal.toString() : '');
}
};
var NumeralFormatter_1 = NumeralFormatter;
var DateFormatter = function (datePattern, dateMin, dateMax) {
var owner = this;
owner.date = [];
owner.blocks = [];
owner.datePattern = datePattern;
owner.dateMin = dateMin
.split('-')
.reverse()
.map(function(x) {
return parseInt(x, 10);
});
if (owner.dateMin.length === 2) owner.dateMin.unshift(0);
owner.dateMax = dateMax
.split('-')
.reverse()
.map(function(x) {
return parseInt(x, 10);
});
if (owner.dateMax.length === 2) owner.dateMax.unshift(0);
owner.initBlocks();
};
DateFormatter.prototype = {
initBlocks: function () {
var owner = this;
owner.datePattern.forEach(function (value) {
if (value === 'Y') {
owner.blocks.push(4);
} else {
owner.blocks.push(2);
}
});
},
getISOFormatDate: function () {
var owner = this,
date = owner.date;
return date[2] ? (
date[2] + '-' + owner.addLeadingZero(date[1]) + '-' + owner.addLeadingZero(date[0])
) : '';
},
getBlocks: function () {
return this.blocks;
},
getValidatedDate: function (value) {
var owner = this, result = '';
value = value.replace(/[^\d]/g, '');
owner.blocks.forEach(function (length, index) {
if (value.length > 0) {
var sub = value.slice(0, length),
sub0 = sub.slice(0, 1),
rest = value.slice(length);
switch (owner.datePattern[index]) {
case 'd':
if (sub === '00') {
sub = '01';
} else if (parseInt(sub0, 10) > 3) {
sub = '0' + sub0;
} else if (parseInt(sub, 10) > 31) {
sub = '31';
}
break;
case 'm':
if (sub === '00') {
sub = '01';
} else if (parseInt(sub0, 10) > 1) {
sub = '0' + sub0;
} else if (parseInt(sub, 10) > 12) {
sub = '12';
}
break;
}
result += sub;
// update remaining string
value = rest;
}
});
return this.getFixedDateString(result);
},
getFixedDateString: function (value) {
var owner = this, datePattern = owner.datePattern, date = [],
dayIndex = 0, monthIndex = 0, yearIndex = 0,
dayStartIndex = 0, monthStartIndex = 0, yearStartIndex = 0,
day, month, year, fullYearDone = false;
// mm-dd || dd-mm
if (value.length === 4 && datePattern[0].toLowerCase() !== 'y' && datePattern[1].toLowerCase() !== 'y') {
dayStartIndex = datePattern[0] === 'd' ? 0 : 2;
monthStartIndex = 2 - dayStartIndex;
day = parseInt(value.slice(dayStartIndex, dayStartIndex + 2), 10);
month = parseInt(value.slice(monthStartIndex, monthStartIndex + 2), 10);
date = this.getFixedDate(day, month, 0);
}
// yyyy-mm-dd || yyyy-dd-mm || mm-dd-yyyy || dd-mm-yyyy || dd-yyyy-mm || mm-yyyy-dd
if (value.length === 8) {
datePattern.forEach(function (type, index) {
switch (type) {
case 'd':
dayIndex = index;
break;
case 'm':
monthIndex = index;
break;
default:
yearIndex = index;
break;
}
});
yearStartIndex = yearIndex * 2;
dayStartIndex = (dayIndex <= yearIndex) ? dayIndex * 2 : (dayIndex * 2 + 2);
monthStartIndex = (monthIndex <= yearIndex) ? monthIndex * 2 : (monthIndex * 2 + 2);
day = parseInt(value.slice(dayStartIndex, dayStartIndex + 2), 10);
month = parseInt(value.slice(monthStartIndex, monthStartIndex + 2), 10);
year = parseInt(value.slice(yearStartIndex, yearStartIndex + 4), 10);
fullYearDone = value.slice(yearStartIndex, yearStartIndex + 4).length === 4;
date = this.getFixedDate(day, month, year);
}
// mm-yy || yy-mm
if (value.length === 4 && (datePattern[0] === 'y' || datePattern[1] === 'y')) {
monthStartIndex = datePattern[0] === 'm' ? 0 : 2;
yearStartIndex = 2 - monthStartIndex;
month = parseInt(value.slice(monthStartIndex, monthStartIndex + 2), 10);
year = parseInt(value.slice(yearStartIndex, yearStartIndex + 2), 10);
fullYearDone = value.slice(yearStartIndex, yearStartIndex + 2).length === 2;
date = [0, month, year];
}
// mm-yyyy || yyyy-mm
if (value.length === 6 && (datePattern[0] === 'Y' || datePattern[1] === 'Y')) {
monthStartIndex = datePattern[0] === 'm' ? 0 : 4;
yearStartIndex = 2 - 0.5 * monthStartIndex;
month = parseInt(value.slice(monthStartIndex, monthStartIndex + 2), 10);
year = parseInt(value.slice(yearStartIndex, yearStartIndex + 4), 10);
fullYearDone = value.slice(yearStartIndex, yearStartIndex + 4).length === 4;
date = [0, month, year];
}
date = owner.getRangeFixedDate(date);
owner.date = date;
var result = date.length === 0 ? value : datePattern.reduce(function (previous, current) {
switch (current) {
case 'd':
return previous + (date[0] === 0 ? '' : owner.addLeadingZero(date[0]));
case 'm':
return previous + (date[1] === 0 ? '' : owner.addLeadingZero(date[1]));
case 'y':
return previous + (fullYearDone ? owner.addLeadingZeroForYear(date[2], false) : '');
case 'Y':
return previous + (fullYearDone ? owner.addLeadingZeroForYear(date[2], true) : '');
}
}, '');
return result;
},
getRangeFixedDate: function (date) {
var owner = this,
datePattern = owner.datePattern,
dateMin = owner.dateMin || [],
dateMax = owner.dateMax || [];
if (!date.length || (dateMin.length < 3 && dateMax.length < 3)) return date;
if (
datePattern.find(function(x) {
return x.toLowerCase() === 'y';
}) &&
date[2] === 0
) return date;
if (dateMax.length && (dateMax[2] < date[2] || (
dateMax[2] === date[2] && (dateMax[1] < date[1] || (
dateMax[1] === date[1] && dateMax[0] < date[0]
))
))) return dateMax;
if (dateMin.length && (dateMin[2] > date[2] || (
dateMin[2] === date[2] && (dateMin[1] > date[1] || (
dateMin[1] === date[1] && dateMin[0] > date[0]
))
))) return dateMin;
return date;
},
getFixedDate: function (day, month, year) {
day = Math.min(day, 31);
month = Math.min(month, 12);
year = parseInt((year || 0), 10);
if ((month < 7 && month % 2 === 0) || (month > 8 && month % 2 === 1)) {
day = Math.min(day, month === 2 ? (this.isLeapYear(year) ? 29 : 28) : 30);
}
return [day, month, year];
},
isLeapYear: function (year) {
return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
},
addLeadingZero: function (number) {
return (number < 10 ? '0' : '') + number;
},
addLeadingZeroForYear: function (number, fullYearMode) {
if (fullYearMode) {
return (number < 10 ? '000' : (number < 100 ? '00' : (number < 1000 ? '0' : ''))) + number;
}
return (number < 10 ? '0' : '') + number;
}
};
var DateFormatter_1 = DateFormatter;
var TimeFormatter = function (timePattern, timeFormat) {
var owner = this;
owner.time = [];
owner.blocks = [];
owner.timePattern = timePattern;
owner.timeFormat = timeFormat;
owner.initBlocks();
};
TimeFormatter.prototype = {
initBlocks: function () {
var owner = this;
owner.timePattern.forEach(function () {
owner.blocks.push(2);
});
},
getISOFormatTime: function () {
var owner = this,
time = owner.time;
return time[2] ? (
owner.addLeadingZero(time[0]) + ':' + owner.addLeadingZero(time[1]) + ':' + owner.addLeadingZero(time[2])
) : '';
},
getBlocks: function () {
return this.blocks;
},
getTimeFormatOptions: function () {
var owner = this;
if (String(owner.timeFormat) === '12') {
return {
maxHourFirstDigit: 1,
maxHours: 12,
maxMinutesFirstDigit: 5,
maxMinutes: 60
};
}
return {
maxHourFirstDigit: 2,
maxHours: 23,
maxMinutesFirstDigit: 5,
maxMinutes: 60
};
},
getValidatedTime: function (value) {
var owner = this, result = '';
value = value.replace(/[^\d]/g, '');
var timeFormatOptions = owner.getTimeFormatOptions();
owner.blocks.forEach(function (length, index) {
if (value.length > 0) {
var sub = value.slice(0, length),
sub0 = sub.slice(0, 1),
rest = value.slice(length);
switch (owner.timePattern[index]) {
case 'h':
if (parseInt(sub0, 10) > timeFormatOptions.maxHourFirstDigit) {
sub = '0' + sub0;
} else if (parseInt(sub, 10) > timeFormatOptions.maxHours) {
sub = timeFormatOptions.maxHours + '';
}
break;
case 'm':
case 's':
if (parseInt(sub0, 10) > timeFormatOptions.maxMinutesFirstDigit) {
sub = '0' + sub0;
} else if (parseInt(sub, 10) > timeFormatOptions.maxMinutes) {
sub = timeFormatOptions.maxMinutes + '';
}
break;
}
result += sub;
// update remaining string
value = rest;
}
});
return this.getFixedTimeString(result);
},
getFixedTimeString: function (value) {
var owner = this, timePattern = owner.timePattern, time = [],
secondIndex = 0, minuteIndex = 0, hourIndex = 0,
secondStartIndex = 0, minuteStartIndex = 0, hourStartIndex = 0,
second, minute, hour;
if (value.length === 6) {
timePattern.forEach(function (type, index) {
switch (type) {
case 's':
secondIndex = index * 2;
break;
case 'm':
minuteIndex = index * 2;
break;
case 'h':
hourIndex = index * 2;
break;
}
});
hourStartIndex = hourIndex;
minuteStartIndex = minuteIndex;
secondStartIndex = secondIndex;
second = parseInt(value.slice(secondStartIndex, secondStartIndex + 2), 10);
minute = parseInt(value.slice(minuteStartIndex, minuteStartIndex + 2), 10);
hour = parseInt(value.slice(hourStartIndex, hourStartIndex + 2), 10);
time = this.getFixedTime(hour, minute, second);
}
if (value.length === 4 && owner.timePattern.indexOf('s') < 0) {
timePattern.forEach(function (type, index) {
switch (type) {
case 'm':
minuteIndex = index * 2;
break;
case 'h':
hourIndex = index * 2;
break;
}
});
hourStartIndex = hourIndex;
minuteStartIndex = minuteIndex;
second = 0;
minute = parseInt(value.slice(minuteStartIndex, minuteStartIndex + 2), 10);
hour = parseInt(value.slice(hourStartIndex, hourStartIndex + 2), 10);
time = this.getFixedTime(hour, minute, second);
}
owner.time = time;
return time.length === 0 ? value : timePattern.reduce(function (previous, current) {
switch (current) {
case 's':
return previous + owner.addLeadingZero(time[2]);
case 'm':
return previous + owner.addLeadingZero(time[1]);
case 'h':
return previous + owner.addLeadingZero(time[0]);
}
}, '');
},
getFixedTime: function (hour, minute, second) {
second = Math.min(parseInt(second || 0, 10), 60);
minute = Math.min(minute, 60);
hour = Math.min(hour, 60);
return [hour, minute, second];
},
addLeadingZero: function (number) {
return (number < 10 ? '0' : '') + number;
}
};
var TimeFormatter_1 = TimeFormatter;
var PhoneFormatter = function (formatter, delimiter) {
var owner = this;
owner.delimiter = (delimiter || delimiter === '') ? delimiter : ' ';
owner.delimiterRE = delimiter ? new RegExp('\\' + delimiter, 'g') : '';
owner.formatter = formatter;
};
PhoneFormatter.prototype = {
setFormatter: function (formatter) {
this.formatter = formatter;
},
format: function (phoneNumber) {
var owner = this;
owner.formatter.clear();
// only keep number and +
phoneNumber = phoneNumber.replace(/[^\d+]/g, '');
// strip non-leading +
phoneNumber = phoneNumber.replace(/^\+/, 'B').replace(/\+/g, '').replace('B', '+');
// strip delimiter
phoneNumber = phoneNumber.replace(owner.delimiterRE, '');
var result = '', current, validated = false;
for (var i = 0, iMax = phoneNumber.length; i < iMax; i++) {
current = owner.formatter.inputDigit(phoneNumber.charAt(i));
// has ()- or space inside
if (/[\s()-]/g.test(current)) {
result = current;
validated = true;
} else {
if (!validated) {
result = current;
}
// else: over length input
// it turns to invalid number again
}
}
// strip ()
// e.g. US: 7161234567 returns (716) 123-4567
result = result.replace(/[()]/g, '');
// replace library delimiter with user customized delimiter
result = result.replace(/[\s-]/g, owner.delimiter);
return result;
}
};
var PhoneFormatter_1 = PhoneFormatter;
var CreditCardDetector = {
blocks: {
uatp: [4, 5, 6],
amex: [4, 6, 5],
diners: [4, 6, 4],
discover: [4, 4, 4, 4],
mastercard: [4, 4, 4, 4],
dankort: [4, 4, 4, 4],
instapayment: [4, 4, 4, 4],
jcb15: [4, 6, 5],
jcb: [4, 4, 4, 4],
maestro: [4, 4, 4, 4],
visa: [4, 4, 4, 4],
mir: [4, 4, 4, 4],
unionPay: [4, 4, 4, 4],
general: [4, 4, 4, 4]
},
re: {
// starts with 1; 15 digits, not starts with 1800 (jcb card)
uatp: /^(?!1800)1\d{0,14}/,
// starts with 34/37; 15 digits
amex: /^3[47]\d{0,13}/,
// starts with 6011/65/644-649; 16 digits
discover: /^(?:6011|65\d{0,2}|64[4-9]\d?)\d{0,12}/,
// starts with 300-305/309 or 36/38/39; 14 digits
diners: /^3(?:0([0-5]|9)|[689]\d?)\d{0,11}/,
// starts with 51-55/2221–2720; 16 digits
mastercard: /^(5[1-5]\d{0,2}|22[2-9]\d{0,1}|2[3-7]\d{0,2})\d{0,12}/,
// starts with 5019/4175/4571; 16 digits
dankort: /^(5019|4175|4571)\d{0,12}/,
// starts with 637-639; 16 digits
instapayment: /^63[7-9]\d{0,13}/,
// starts with 2131/1800; 15 digits
jcb15: /^(?:2131|1800)\d{0,11}/,
// starts with 2131/1800/35; 16 digits
jcb: /^(?:35\d{0,2})\d{0,12}/,
// starts with 50/56-58/6304/67; 16 digits
maestro: /^(?:5[0678]\d{0,2}|6304|67\d{0,2})\d{0,12}/,
// starts with 22; 16 digits
mir: /^220[0-4]\d{0,12}/,
// starts with 4; 16 digits
visa: /^4\d{0,15}/,
// starts with 62/81; 16 digits
unionPay: /^(62|81)\d{0,14}/
},
getStrictBlocks: function (block) {
var total = block.reduce(function (prev, current) {
return prev + current;
}, 0);
return block.concat(19 - total);
},
getInfo: function (value, strictMode) {
var blocks = CreditCardDetector.blocks,
re = CreditCardDetector.re;
// Some credit card can have up to 19 digits number.
// Set strictMode to true will remove the 16 max-length restrain,
// however, I never found any website validate card number like
// this, hence probably you don't want to enable this option.
strictMode = !!strictMode;
for (var key in re) {
if (re[key].test(value)) {
var matchedBlocks = blocks[key];
return {
type: key,
blocks: strictMode ? this.getStrictBlocks(matchedBlocks) : matchedBlocks
};
}
}
return {
type: 'unknown',
blocks: strictMode ? this.getStrictBlocks(blocks.general) : blocks.general
};
}
};
var CreditCardDetector_1 = CreditCardDetector;
var Util = {
noop: function () {
},
strip: function (value, re) {
return value.replace(re, '');
},
getPostDelimiter: function (value, delimiter, delimiters) {
// single delimiter
if (delimiters.length === 0) {
return value.slice(-delimiter.length) === delimiter ? delimiter : '';
}
// multiple delimiters
var matchedDelimiter = '';
delimiters.forEach(function (current) {
if (value.slice(-current.length) === current) {
matchedDelimiter = current;
}
});
return matchedDelimiter;
},
getDelimiterREByDelimiter: function (delimiter) {
return new RegExp(delimiter.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'), 'g');
},
getNextCursorPosition: function (prevPos, oldValue, newValue, delimiter, delimiters) {
// If cursor was at the end of value, just place it back.
// Because new value could contain additional chars.
if (oldValue.length === prevPos) {
return newValue.length;
}
return prevPos + this.getPositionOffset(prevPos, oldValue, newValue, delimiter ,delimiters);
},
getPositionOffset: function (prevPos, oldValue, newValue, delimiter, delimiters) {
var oldRawValue, newRawValue, lengthOffset;
oldRawValue = this.stripDelimiters(oldValue.slice(0, prevPos), delimiter, delimiters);
newRawValue = this.stripDelimiters(newValue.slice(0, prevPos), delimiter, delimiters);
lengthOffset = oldRawValue.length - newRawValue.length;
return (lengthOffset !== 0) ? (lengthOffset / Math.abs(lengthOffset)) : 0;
},
stripDelimiters: function (value, delimiter, delimiters) {
var owner = this;
// single delimiter
if (delimiters.length === 0) {
var delimiterRE = delimiter ? owner.getDelimiterREByDelimiter(delimiter) : '';
return value.replace(delimiterRE, '');
}
// multiple delimiters
delimiters.forEach(function (current) {
current.split('').forEach(function (letter) {
value = value.replace(owner.getDelimiterREByDelimiter(letter), '');
});
});
return value;
},
headStr: function (str, length) {
return str.slice(0, length);
},
getMaxLength: function (blocks) {
return blocks.reduce(function (previous, current) {
return previous + current;
}, 0);
},
// strip prefix
// Before type | After type | Return value
// PEFIX-... | PEFIX-... | ''
// PREFIX-123 | PEFIX-123 | 123
// PREFIX-123 | PREFIX-23 | 23
// PREFIX-123 | PREFIX-1234 | 1234
getPrefixStrippedValue: function (value, prefix, prefixLength, prevResult, delimiter, delimiters, noImmediatePrefix, tailPrefix, signBeforePrefix) {
// No prefix
if (prefixLength === 0) {
return value;
}
// Value is prefix
if (value === prefix && value !== '') {
return '';
}
if (signBeforePrefix && (value.slice(0, 1) == '-')) {
var prev = (prevResult.slice(0, 1) == '-') ? prevResult.slice(1) : prevResult;
return '-' + this.getPrefixStrippedValue(value.slice(1), prefix, prefixLength, prev, delimiter, delimiters, noImmediatePrefix, tailPrefix, signBeforePrefix);
}
// Pre result prefix string does not match pre-defined prefix
if (prevResult.slice(0, prefixLength) !== prefix && !tailPrefix) {
// Check if the first time user entered something
if (noImmediatePrefix && !prevResult && value) return value;
return '';
} else if (prevResult.slice(-prefixLength) !== prefix && tailPrefix) {
// Check if the first time user entered something
if (noImmediatePrefix && !prevResult && value) return value;
return '';
}
var prevValue = this.stripDelimiters(prevResult, delimiter, delimiters);
// New value has issue, someone typed in between prefix letters
// Revert to pre value
if (value.slice(0, prefixLength) !== prefix && !tailPrefix) {
return prevValue.slice(prefixLength);
} else if (value.slice(-prefixLength) !== prefix && tailPrefix) {
return prevValue.slice(0, -prefixLength - 1);
}
// No issue, strip prefix for new value
return tailPrefix ? value.slice(0, -prefixLength) : value.slice(prefixLength);
},
getFirstDiffIndex: function (prev, current) {
var index = 0;
while (prev.charAt(index) === current.charAt(index)) {
if (prev.charAt(index++) === '') {
return -1;
}
}
return index;
},
getFormattedValue: function (value, blocks, blocksLength, delimiter, delimiters, delimiterLazyShow) {
var result = '',
multipleDelimiters = delimiters.length > 0,
currentDelimiter = '';
// no options, normal input
if (blocksLength === 0) {
return value;
}
blocks.forEach(function (length, index) {
if (value.length > 0) {
var sub = value.slice(0, length),
rest = value.slice(length);
if (multipleDelimiters) {
currentDelimiter = delimiters[delimiterLazyShow ? (index - 1) : index] || currentDelimiter;
} else {
currentDelimiter = delimiter;
}
if (delimiterLazyShow) {
if (index > 0) {
result += currentDelimiter;
}
result += sub;
} else {
result += sub;
if (sub.length === length && index < blocksLength - 1) {
result += currentDelimiter;
}
}
// update remaining string
value = rest;
}
});
return result;
},
// move cursor to the end
// the first time user focuses on an input with prefix
fixPrefixCursor: function (el, prefix, delimiter, delimiters) {
if (!el) {
return;
}
var val = el.value,
appendix = delimiter || (delimiters[0] || ' ');
if (!el.setSelectionRange || !prefix || (prefix.length + appendix.length) <= val.length) {
return;
}
var len = val.length * 2;
// set timeout to avoid blink
setTimeout(function () {
el.setSelectionRange(len, len);
}, 1);
},
// Check if input field is fully selected
checkFullSelection: function(value) {
try {
var selection = window.getSelection() || document.getSelection() || {};
return selection.toString().length === value.length;
} catch (ex) {
// Ignore
}
return false;
},
setSelection: function (element, position, doc) {
if (element !== this.getActiveElement(doc)) {
return;
}
// cursor is already in the end
if (element && element.value.length <= position) {
return;
}
if (element.createTextRange) {
var range = element.createTextRange();
range.move('character', position);
range.select();
} else {
try {
element.setSelectionRange(position, position);
} catch (e) {
// eslint-disable-next-line
console.warn('The input element type does not support selection');
}
}
},
getActiveElement: function(parent) {
var activeElement = parent.activeElement;
if (activeElement && activeElement.shadowRoot) {
return this.getActiveElement(activeElement.shadowRoot);
}
return activeElement;
},
isAndroid: function () {
return navigator && /android/i.test(navigator.userAgent);
},
// On Android chrome, the keyup and keydown events
// always return key code 229 as a composition that
// buffers the user’s keystrokes
// see https://github.com/nosir/cleave.js/issues/147
isAndroidBackspaceKeydown: function (lastInputValue, currentInputValue) {
if (!this.isAndroid() || !lastInputValue || !currentInputValue) {
return false;
}
return currentInputValue === lastInputValue.slice(0, -1);
}
};
var Util_1 = Util;
/**
* Props Assignment
*
* Separate this, so react module can share the usage
*/
var DefaultProperties = {
// Maybe change to object-assign
// for now just keep it as simple
assign: function (target, opts) {
target = target || {};
opts = opts || {};
// credit card
target.creditCard = !!opts.creditCard;
target.creditCardStrictMode = !!opts.creditCardStrictMode;
target.creditCardType = '';
target.onCreditCardTypeChanged = opts.onCreditCardTypeChanged || (function () {});
// phone
target.phone = !!opts.phone;
target.phoneRegionCode = opts.phoneRegionCode || 'AU';
target.phoneFormatter = {};
// time
target.time = !!opts.time;
target.timePattern = opts.timePattern || ['h', 'm', 's'];
target.timeFormat = opts.timeFormat || '24';
target.timeFormatter = {};
// date
target.date = !!opts.date;
target.datePattern = opts.datePattern || ['d', 'm', 'Y'];
target.dateMin = opts.dateMin || '';
target.dateMax = opts.dateMax || '';
target.dateFormatter = {};
// numeral
target.numeral = !!opts.numeral;
target.numeralIntegerScale = opts.numeralIntegerScale > 0 ? opts.numeralIntegerScale : 0;
target.numeralDecimalScale = opts.numeralDecimalScale >= 0 ? opts.numeralDecimalScale : 2;
target.numeralDecimalMark = opts.numeralDecimalMark || '.';
target.numeralThousandsGroupStyle = opts.numeralThousandsGroupStyle || 'thousand';
target.numeralPositiveOnly = !!opts.numeralPositiveOnly;
target.stripLeadingZeroes = opts.stripLeadingZeroes !== false;
target.signBeforePrefix = !!opts.signBeforePrefix;
target.tailPrefix = !!opts.tailPrefix;
// others
target.swapHiddenInput = !!opts.swapHiddenInput;
target.numericOnly = target.creditCard || target.date || !!opts.numericOnly;
target.uppercase = !!opts.uppercase;
target.lowercase = !!opts.lowercase;
target.prefix = (target.creditCard || target.date) ? '' : (opts.prefix || '');
target.noImmediatePrefix = !!opts.noImmediatePrefix;
target.prefixLength = target.prefix.length;
target.rawValueTrimPrefix = !!opts.rawValueTrimPrefix;
target.copyDelimiter = !!opts.copyDelimiter;
target.initValue = (opts.initValue !== undefined && opts.initValue !== null) ? opts.initValue.toString() : '';
target.delimiter =
(opts.delimiter || opts.delimiter === '') ? opts.delimiter :
(opts.date ? '/' :
(opts.time ? ':' :
(opts.numeral ? ',' :
(opts.phone ? ' ' :
' '))));
target.delimiterLength = target.delimiter.length;
target.delimiterLazyShow = !!opts.delimiterLazyShow;
target.delimiters = opts.delimiters || [];
target.blocks = opts.blocks || [];
target.blocksLength = target.blocks.length;
target.root = (typeof commonjsGlobal === 'object' && commonjsGlobal) ? commonjsGlobal : window;
target.document = opts.document || target.root.document;
target.maxLength = 0;
target.backspace = false;
target.result = '';
target.onValueChanged = opts.onValueChanged || (function () {});
return target;
}
};
var DefaultProperties_1 = DefaultProperties;
/**
* Construct a new Cleave instance by passing the configuration object
*
* @param {String | HTMLElement} element
* @param {Object} opts
*/
var Cleave = function (element, opts) {
var owner = this;
var hasMultipleElements = false;
if (typeof element === 'string') {
owner.element = document.querySelector(element);
hasMultipleElements = document.querySelectorAll(element).length > 1;
} else {
if (typeof element.length !== 'undefined' && element.length > 0) {
owner.element = element[0];
hasMultipleElements = element.length > 1;
} else {
owner.element = element;
}
}
if (!owner.element) {
throw new Error('[cleave.js] Please check the element');
}
if (hasMultipleElements) {
try {
// eslint-disable-next-line
console.warn('[cleave.js] Multiple input fields matched, cleave.js will only take the first one.');
} catch (e) {
// Old IE
}
}
opts.initValue = owner.element.value;
owner.properties = Cleave.DefaultProperties.assign({}, opts);
owner.init();
};
Cleave.prototype = {
init: function () {
var owner = this, pps = owner.properties;
// no need to use this lib
if (!pps.numeral && !pps.phone && !pps.creditCard && !pps.time && !pps.date && (pps.blocksLength === 0 && !pps.prefix)) {
owner.onInput(pps.initValue);
return;
}
pps.maxLength = Cleave.Util.getMaxLength(pps.blocks);
owner.isAndroid = Cleave.Util.isAndroid();
owner.lastInputValue = '';
owner.isBackward = '';
owner.onChangeListener = owner.onChange.bind(owner);
owner.onKeyDownListener = owner.onKeyDown.bind(owner);
owner.onFocusListener = owner.onFocus.bind(owner);
owner.onCutListener = owner.onCut.bind(owner);
owner.onCopyListener = owner.onCopy.bind(owner);
owner.initSwapHiddenInput();
owner.element.addEventListener('input', owner.onChangeListener);
owner.element.addEventListener('keydown', owner.onKeyDownListener);
owner.element.addEventListener('focus', owner.onFocusListener);
owner.element.addEventListener('cut', owner.onCutListener);
owner.element.addEventListener('copy', owner.onCopyListener);
owner.initPhoneFormatter();
owner.initDateFormatter();
owner.initTimeFormatter();
owner.initNumeralFormatter();
// avoid touch input field if value is null
// otherwise Firefox will add red box-shadow for <input required />
if (pps.initValue || (pps.prefix && !pps.noImmediatePrefix)) {
owner.onInput(pps.initValue);
}
},
initSwapHiddenInput: function () {
var owner = this, pps = owner.properties;
if (!pps.swapHiddenInput) return;
var inputFormatter = owner.element.cloneNode(true);
owner.element.parentNode.insertBefore(inputFormatter, owner.element);
owner.elementSwapHidden = owner.element;
owner.elementSwapHidden.type = 'hidden';
owner.element = inputFormatter;
owner.element.id = '';
},
initNumeralFormatter: function () {
var owner = this, pps = owner.properties;
if (!pps.numeral) {
return;
}
pps.numeralFormatter = new Cleave.NumeralFormatter(
pps.numeralDecimalMark,
pps.numeralIntegerScale,
pps.numeralDecimalScale,
pps.numeralThousandsGroupStyle,
pps.numeralPositiveOnly,
pps.stripLeadingZeroes,
pps.prefix,
pps.signBeforePrefix,
pps.tailPrefix,
pps.delimiter
);
},
initTimeFormatter: function() {
var owner = this, pps = owner.properties;
if (!pps.time) {
return;
}
pps.timeFormatter = new Cleave.TimeFormatter(pps.timePattern, pps.timeFormat);
pps.blocks = pps.timeFormatter.getBlocks();
pps.blocksLength = pps.blocks.length;
pps.maxLength = Cleave.Util.getMaxLength(pps.blocks);
},
initDateFormatter: function () {
var owner = this, pps = owner.properties;
if (!pps.date) {
return;
}
pps.dateFormatter = new Cleave.DateFormatter(pps.datePattern, pps.dateMin, pps.dateMax);
pps.blocks = pps.dateFormatter.getBlocks();
pps.blocksLength = pps.blocks.length;
pps.maxLength = Cleave.Util.getMaxLength(pps.blocks);
},
initPhoneFormatter: function () {
var owner = this, pps = owner.properties;
if (!pps.phone) {
return;
}
// Cleave.AsYouTypeFormatter should be provided by
// external google closure lib
try {
pps.phoneFormatter = new Cleave.PhoneFormatter(
new pps.root.Cleave.AsYouTypeFormatter(pps.phoneRegionCode),
pps.delimiter
);
} catch (ex) {
throw new Error('[cleave.js] Please include phone-type-formatter.{country}.js lib');
}
},
onKeyDown: function (event) {
var owner = this,
charCode = event.which || event.keyCode;
owner.lastInputValue = owner.element.value;
owner.isBackward = charCode === 8;
},
onChange: function (event) {
var owner = this, pps = owner.properties,
Util = Cleave.Util;
owner.isBackward = owner.isBackward || event.inputType === 'deleteContentBackward';
var postDelimiter = Util.getPostDelimiter(owner.lastInputValue, pps.delimiter, pps.delimiters);
if (owner.isBackward && postDelimiter) {
pps.postDelimiterBackspace = postDelimiter;
} else {
pps.postDelimiterBackspace = false;
}
this.onInput(this.element.value);
},
onFocus: function () {
var owner = this,
pps = owner.properties;
owner.lastInputValue = owner.element.value;
if (pps.prefix && pps.noImmediatePrefix && !owner.element.value) {
this.onInput(pps.prefix);
}
Cleave.Util.fixPrefixCursor(owner.element, pps.prefix, pps.delimiter, pps.delimiters);
},
onCut: function (e) {
if (!Cleave.Util.checkFullSelection(this.element.value)) return;
this.copyClipboardData(e);
this.onInput('');
},
onCopy: function (e) {
if (!Cleave.Util.checkFullSelection(this.element.value)) return;
this.copyClipboardData(e);
},
copyClipboardData: function (e) {
var owner = this,
pps = owner.properties,
Util = Cleave.Util,
inputValue = owner.element.value,
textToCopy = '';
if (!pps.copyDelimiter) {
textToCopy = Util.stripDelimiters(inputValue, pps.delimiter, pps.delimiters);
} else {
textToCopy = inputValue;
}
try {
if (e.clipboardData) {
e.clipboardData.setData('Text', textToCopy);
} else {
window.clipboardData.setData('Text', textToCopy);
}
e.preventDefault();
} catch (ex) {
// empty
}
},
onInput: function (value) {
var owner = this, pps = owner.properties,
Util = Cleave.Util;
// case 1: delete one more character "4"
// 1234*| -> hit backspace -> 123|
// case 2: last character is not delimiter which is:
// 12|34* -> hit backspace -> 1|34*
// note: no need to apply this for numeral mode
var postDelimiterAfter = Util.getPostDelimiter(value, pps.delimiter, pps.delimiters);
if (!pps.numeral && pps.postDelimiterBackspace && !postDelimiterAfter) {
value = Util.headStr(value, value.length - pps.postDelimiterBackspace.length);
}
// phone formatter
if (pps.phone) {
if (pps.prefix && (!pps.noImmediatePrefix || value.length)) {
pps.result = pps.prefix + pps.phoneFormatter.format(value).slice(pps.prefix.length);
} else {
pps.result = pps.phoneFormatter.format(value);
}
owner.updateValueState();
return;
}
// numeral formatter
if (pps.numeral) {
// Do not show prefix when noImmediatePrefix is specified
// This mostly because we need to show user the native input placeholder
if (pps.prefix && pps.noImmediatePrefix && value.length === 0) {
pps.result = '';
} else {
pps.result = pps.numeralFormatter.format(value);
}
owner.updateValueState();
return;
}
// date
if (pps.date) {
value = pps.dateFormatter.getValidatedDate(value);
}
// time
if (pps.time) {
value = pps.timeFormatter.getValidatedTime(value);
}
// strip delimiters
value = Util.stripDelimiters(value, pps.delimiter, pps.delimiters);
// strip prefix
value = Util.getPrefixStrippedValue(value, pps.prefix, pps.prefixLength, pps.result, pps.delimiter, pps.delimiters, pps.noImmediatePrefix, pps.tailPrefix, pps.signBeforePrefix);
// strip non-numeric characters
value = pps.numericOnly ? Util.strip(value, /[^\d]/g) : value;
// convert case
value = pps.uppercase ? value.toUpperCase() : value;
value = pps.lowercase ? value.toLowerCase() : value;
// prevent from showing prefix when no immediate option enabled with empty input value
if (pps.prefix) {
if (pps.tailPrefix) {
value = value + pps.prefix;
} else {
value = pps.prefix + value;
}
// no blocks specified, no need to do formatting
if (pps.blocksLength === 0) {
pps.result = value;
owner.updateValueState();
return;
}
}
// update credit card props
if (pps.creditCard) {
owner.updateCreditCardPropsByValue(value);
}
// strip over length characters
value = Util.headStr(value, pps.maxLength);
// apply blocks
pps.result = Util.getFormattedValue(
value,