From 518371c3e73dd803048097b3cdea731f6dbedf22 Mon Sep 17 00:00:00 2001 From: Thiago Contardi Date: Fri, 9 Feb 2024 16:47:42 -0300 Subject: [PATCH 01/50] feat: added new credit card form --- Helper/Data.php | 2 - view/frontend/requirejs-config.js | 9 + view/frontend/web/css/checkout.less | 286 ++ view/frontend/web/js/credit-card/card.js | 211 + view/frontend/web/js/credit-card/mask.js | 3511 +++++++++++++++++ .../web/js/view/payment/method-renderer/cc.js | 34 +- .../web/template/payment/form/cc.html | 173 +- 7 files changed, 4114 insertions(+), 112 deletions(-) create mode 100644 view/frontend/requirejs-config.js create mode 100644 view/frontend/web/js/credit-card/card.js create mode 100644 view/frontend/web/js/credit-card/mask.js diff --git a/Helper/Data.php b/Helper/Data.php index 121da57..e0b4940 100644 --- a/Helper/Data.php +++ b/Helper/Data.php @@ -47,8 +47,6 @@ class Data extends \Magento\Payment\Helper\Data { public const FINGERPRINT_URL = 'https://static.traycheckout.com.br/js/finger_print.js'; - public const DEFAULT_CURRENCY = 'BRL'; - protected array $methodNames = [ 'MC' => 'Mastercard', 'AU' => 'Aura', diff --git a/view/frontend/requirejs-config.js b/view/frontend/requirejs-config.js new file mode 100644 index 0000000..7689886 --- /dev/null +++ b/view/frontend/requirejs-config.js @@ -0,0 +1,9 @@ +var config = { + paths: { + 'vindi-cc-form': 'Vindi_VP/js/credit-card/card', + 'vindi-cc-mask': 'Vindi_VP/js/credit-card/mask', + }, + shim: { + 'vindi-cc-mask': {} + } +}; diff --git a/view/frontend/web/css/checkout.less b/view/frontend/web/css/checkout.less index ec137b1..fa9b6e5 100644 --- a/view/frontend/web/css/checkout.less +++ b/view/frontend/web/css/checkout.less @@ -52,4 +52,290 @@ } } +#payment_form_vindi_vp_cc { + max-width: 500px; +} + +.container-vindi_vp_cc .vindi-cc-exp-cvv { + display: flex; + justify-content: space-between; + span { + display: block; + width: 48%; + } +} + +/* CREDIT CARD IMAGE STYLING */ +.container-vindi_vp_cc .vind-cc-preload * { + -webkit-transition: none !important; + -moz-transition: none !important; + -ms-transition: none !important; + -o-transition: none !important; +} + +.container-vindi_vp_cc .vindi-vp-cc-container { + display: flex; + justify-content: center; + width: 100%; + max-height: 251px; + height: 54vw; + padding: 20px; +} + +.container-vindi_vp_cc #vindi-vp-cc-ccsingle { + position: absolute; + right: 15px; + top: 20px; +} + +.container-vindi_vp_cc #vindi-vp-cc-ccsingle svg { + width: 100px; + max-height: 60px; +} + +.container-vindi_vp_cc .vind-cc-creditcard svg#vindi-vp-cc-cardfront, +.container-vindi_vp_cc .vind-cc-creditcard svg#vindi-vp-cc-cardback { + width: 100%; + -webkit-box-shadow: 1px 5px 6px 0px black; + box-shadow: 1px 5px 6px 0px black; + border-radius: 22px; +} + +.container-vindi_vp_cc #generatecard{ + cursor: pointer; + float: right; + font-size: 12px; + color: #fff; + padding: 2px 4px; + background-color: #909090; + border-radius: 4px; + cursor: pointer; + float:right; +} + +/* CHANGEABLE CARD ELEMENTS */ +.container-vindi_vp_cc .vind-cc-creditcard .lightcolor, +.container-vindi_vp_cc .vind-cc-creditcard .darkcolor { + -webkit-transition: fill .5s; + transition: fill .5s; +} + +.container-vindi_vp_cc .vind-cc-creditcard .lightblue { + fill: #03A9F4; +} + +.container-vindi_vp_cc .vind-cc-creditcard .lightbluedark { + fill: #0288D1; +} + +.container-vindi_vp_cc .vind-cc-creditcard .red { + fill: #ef5350; +} + +.container-vindi_vp_cc .vind-cc-creditcard .reddark { + fill: #d32f2f; +} + +.container-vindi_vp_cc .vind-cc-creditcard .purple { + fill: #ab47bc; +} + +.container-vindi_vp_cc .vind-cc-creditcard .purpledark { + fill: #7b1fa2; +} + +.container-vindi_vp_cc .vind-cc-creditcard .cyan { + fill: #26c6da; +} + +.container-vindi_vp_cc .vind-cc-creditcard .cyandark { + fill: #0097a7; +} + +.container-vindi_vp_cc .vind-cc-creditcard .green { + fill: #66bb6a; +} + +.container-vindi_vp_cc .vind-cc-creditcard .greendark { + fill: #388e3c; +} + +.container-vindi_vp_cc .vind-cc-creditcard .lime { + fill: #d4e157; +} + +.container-vindi_vp_cc .vind-cc-creditcard .limedark { + fill: #afb42b; +} + +.container-vindi_vp_cc .vind-cc-creditcard .yellow { + fill: #ffeb3b; +} + +.container-vindi_vp_cc .vind-cc-creditcard .yellowdark { + fill: #f9a825; +} + +.container-vindi_vp_cc .vind-cc-creditcard .orange { + fill: #ff9800; +} + +.container-vindi_vp_cc .vind-cc-creditcard .orangedark { + fill: #ef6c00; +} + +.container-vindi_vp_cc .vind-cc-creditcard .grey { + fill: #3f3f3f; +} + +.container-vindi_vp_cc .vind-cc-creditcard .greydark { + fill: #1f1f1f; +} + +/* FRONT OF CARD */ +.container-vindi_vp_cc #svgname { + text-transform: uppercase; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardfront .st2 { + fill: #FFFFFF; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardfront .st3 { + font-family: 'Source Code Pro', monospace; + font-weight: 600; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardfront .st4 { + font-size: 54.7817px; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardfront .st5 { + font-family: 'Source Code Pro', monospace; + font-weight: 400; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardfront .st6 { + font-size: 33.1112px; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardfront .st7 { + opacity: 0.6; + fill: #FFFFFF; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardfront .st8 { + font-size: 24px; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardfront .st9 { + font-size: 36.5498px; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardfront .st10 { + font-family: 'Source Code Pro', monospace; + font-weight: 300; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardfront .st11 { + font-size: 16.1716px; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardfront .st12 { + fill: #4C4C4C; +} + +/* BACK OF CARD */ +.container-vindi_vp_cc #vindi-vp-cc-cardback .st0 { + fill: none; + stroke: #0F0F0F; + stroke-miterlimit: 10; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st2 { + fill: #111111; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st3 { + fill: #F2F2F2; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st4 { + fill: #D8D2DB; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st5 { + fill: #C4C4C4; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st6 { + font-family: 'Source Code Pro', monospace; + font-weight: 400; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st7 { + font-size: 27px; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st8 { + opacity: 0.6; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st9 { + fill: #FFFFFF; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st10 { + font-size: 24px; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st11 { + fill: #EAEAEA; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st12 { + font-family: 'Rock Salt', cursive; +} + +.container-vindi_vp_cc #vindi-vp-cc-cardback .st13 { + font-size: 37.769px; +} + +/* FLIP ANIMATION */ +.container-vindi_vp_cc .vindi-vp-cc-container { + perspective: 1000px; +} + +.container-vindi_vp_cc .vind-cc-creditcard { + width: 100%; + max-width: 400px; + -webkit-transform-style: preserve-3d; + transform-style: preserve-3d; + transition: -webkit-transform 0.6s; + -webkit-transition: -webkit-transform 0.6s; + transition: transform 0.6s; + transition: transform 0.6s, -webkit-transform 0.6s; + cursor: pointer; +} + +.container-vindi_vp_cc .vind-cc-creditcard .vindi-vp-cc-front, +.container-vindi_vp_cc .vind-cc-creditcard .vindi-vp-cc-back { + position: absolute; + width: 100%; + max-width: 400px; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-font-smoothing: antialiased; + color: #47525d; +} + +.container-vindi_vp_cc .vind-cc-creditcard .vindi-vp-cc-back { + -webkit-transform: rotateY(180deg); + transform: rotateY(180deg); +} + +.container-vindi_vp_cc .vind-cc-creditcard.flipped { + -webkit-transform: rotateY(180deg); + transform: rotateY(180deg); +} diff --git a/view/frontend/web/js/credit-card/card.js b/view/frontend/web/js/credit-card/card.js new file mode 100644 index 0000000..ac7b369 --- /dev/null +++ b/view/frontend/web/js/credit-card/card.js @@ -0,0 +1,211 @@ +define(['vindi-cc-mask'], function () { + 'use strict'; + + return async function (ccName, ccNumber, ccExpDate, ccCvv, ccsingle, ccFront, ccBack) { + + const currentYear = parseInt(new Date().getFullYear().toString().substring(2, 4)); + const nextYear = currentYear + 1; + + let cardFront = ' 0123 4567 8910 1112 JOÃO DOS SANTOS nome do titular validade número 12/23 VÁLIDO ATÉ '; + let cardBack = ' 985 cvv João da Silva '; + + ccFront.insertAdjacentHTML("beforeend", cardFront); + ccBack.innerHTML = cardBack; + + //Mask the Credit Card Number Input + var ccNumberMask = new VindiCCMask(ccNumber, { + mask: [ + { + mask: '000000000000000', + svgPattern: '0000 000000 00000', + regex: '^3[47]\\d{0,13}', + cardtype: 'american express' + }, + { + mask: '0000000000000000', + svgPattern: '0000 0000 0000 0000', + regex: '^(5[1-5]\\d{0,2}|22[2-9]\\d{0,1}|2[3-7]\\d{0,2})\\d{0,12}', + cardtype: 'mastercard' + }, + { + mask: '0000000000000000', + svgPattern: '0000 0000 0000 0000', + regex: '^(?:5[0678]\\d{0,2}|6304|67\\d{0,2})\\d{0,12}', + cardtype: 'maestro' + }, + { + mask: '0000000000000000', + svgPattern: '0000 0000 0000 0000', + regex: '^4\\d{0,15}', + cardtype: 'visa' + }, + { + mask: '0000000000000000', + svgPattern: '0000 0000 0000 0000', + cardtype: 'Unknown' + } + ], + dispatch: function (appended, dynamicMasked) { + var number = (dynamicMasked.value + appended).replace(/\D/g, ''); + + for (var i = 0; i < dynamicMasked.compiledMasks.length; i++) { + let re = new RegExp(dynamicMasked.compiledMasks[i].regex); + if (number.match(re) != null) { + return dynamicMasked.compiledMasks[i]; + } + } + } + }); + + //Mask the Expiration Date + var ccExpDateMask = new VindiCCMask(ccExpDate, { + mask: 'MM{/}YY', + groups: { + YY: new VindiCCMask.MaskedPattern.Group.Range([currentYear, 99]), + MM: new VindiCCMask.MaskedPattern.Group.Range([1, 12]), + } + }); + + //Mask the security code + var ccCvvMask = new VindiCCMask(ccCvv, { + mask: '0000', + }); + + let amex_single = `Slice 1Created with Sketch.`; + let visa_single = `Slice 1Created with Sketch.`; + let maestro_single = ` maestro `; + let mastercard_single = ` mastercard `; + + //pop in the appropriate card icon when detected + ccNumberMask.on("accept", function () { + switch (ccNumberMask.masked.currentMask.cardtype) { + case 'american express': + ccsingle.innerHTML = amex_single; + swapColor('green'); + break; + case 'visa': + ccsingle.innerHTML = visa_single; + swapColor('lime'); + break; + case 'maestro': + ccsingle.innerHTML = maestro_single; + swapColor('yellow'); + break; + case 'mastercard': + ccsingle.innerHTML = mastercard_single; + swapColor('lightblue'); + + break; + default: + ccsingle.innerHTML = ''; + swapColor('grey'); + break; + } + + }); + + + // CREDIT CARD IMAGE JS + document.querySelector('.vind-cc-preload').classList.remove('vind-cc-preload'); + document.getElementById('svgexpire').innerHTML = '01/' + nextYear; + document.querySelector('.vind-cc-creditcard').addEventListener('click', function () { + if (this.classList.contains('flipped')) { + this.classList.remove('flipped'); + } else { + this.classList.add('flipped'); + } + }) + + //On Input Change Events + ccName.addEventListener('input', function () { + if (ccName.value.length == 0) { + document.getElementById('svgname').innerHTML = 'João da Silva'; + document.getElementById('svgnameback').innerHTML = 'João da Silva'; + } else { + document.getElementById('svgname').innerHTML = this.value; + document.getElementById('svgnameback').innerHTML = this.value; + } + }); + + ccNumberMask.on('accept', function () { + if (ccNumberMask.value.length == 0) { + document.getElementById('svgnumber').innerHTML = '0123 4567 8910 1112'; + } else { + let pattern = ccNumberMask.masked.currentMask.svgPattern; + document.getElementById('svgnumber').innerHTML = applyPattern(ccNumberMask.value, pattern); + } + }); + + ccExpDateMask.on('accept', function () { + if (ccExpDateMask.value.length == 0) { + document.getElementById('svgexpire').innerHTML = '01/' + nextYear; + } else { + document.getElementById('svgexpire').innerHTML = ccExpDateMask.value; + } + }); + + ccCvvMask.on('accept', function () { + if (ccCvvMask.value.length == 0) { + document.getElementById('svgsecurity').innerHTML = '985'; + } else { + document.getElementById('svgsecurity').innerHTML = ccCvvMask.value; + } + }); + + //On Focus Events + ccCvv.addEventListener('focus', function () { + document.querySelector('.vind-cc-creditcard').classList.add('flipped'); + }); + + ccCvv.addEventListener('blur', function () { + document.querySelector('.vind-cc-creditcard').classList.remove('flipped'); + }); + + + //define the color swap function + const swapColor = function (basecolor) { + document.querySelectorAll('.lightcolor') + .forEach(function (input) { + input.setAttribute('class', ''); + input.setAttribute('class', 'lightcolor ' + basecolor); + }); + document.querySelectorAll('.darkcolor') + .forEach(function (input) { + input.setAttribute('class', ''); + input.setAttribute('class', 'darkcolor ' + basecolor + 'dark'); + }); + }; + + + const applyPattern = function(inputNumber, pattern) { + // Remove any non-digit characters from the input number + const cleanedNumber = String(inputNumber).replace(/\D/g, ''); + + // Initialize variables for the result and pattern index + let result = ''; + let patternIndex = 0; + + // Iterate through each character in the pattern + for (let i = 0; i < pattern.length; i++) { + // Check if the current character is a placeholder (0) or other character + if (pattern[i] === '0') { + // Check if there are still digits in the cleaned number + if (patternIndex < cleanedNumber.length) { + // Append the next digit from the cleaned number to the result + result += cleanedNumber[patternIndex]; + patternIndex++; + } else { + // If no more digits in the cleaned number, break the loop + break; + } + } else { + // If the current character is not a placeholder, append it to the result + result += pattern[i]; + } + } + + return result; + } + + } +}); diff --git a/view/frontend/web/js/credit-card/mask.js b/view/frontend/web/js/credit-card/mask.js new file mode 100644 index 0000000..3dd7b19 --- /dev/null +++ b/view/frontend/web/js/credit-card/mask.js @@ -0,0 +1,3511 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.VindiCCMask = factory()); +}(this, (function () { 'use strict'; + + // 7.2.1 RequireObjectCoercible(argument) + var _defined = function (it) { + if (it == undefined) throw TypeError("Can't call method on " + it); + return it; + }; + + // 7.1.13 ToObject(argument) + + var _toObject = function (it) { + return Object(_defined(it)); + }; + + var hasOwnProperty = {}.hasOwnProperty; + var _has = function (it, key) { + return hasOwnProperty.call(it, key); + }; + + var toString = {}.toString; + + var _cof = function (it) { + return toString.call(it).slice(8, -1); + }; + + // fallback for non-array-like ES3 and non-enumerable old V8 strings + + // eslint-disable-next-line no-prototype-builtins + var _iobject = Object('z').propertyIsEnumerable(0) ? Object : function (it) { + return _cof(it) == 'String' ? it.split('') : Object(it); + }; + + // to indexed object, toObject with fallback for non-array-like ES3 strings + + + var _toIobject = function (it) { + return _iobject(_defined(it)); + }; + + // 7.1.4 ToInteger + var ceil = Math.ceil; + var floor = Math.floor; + var _toInteger = function (it) { + return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it); + }; + + // 7.1.15 ToLength + + var min = Math.min; + var _toLength = function (it) { + return it > 0 ? min(_toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991 + }; + + var max = Math.max; + var min$1 = Math.min; + var _toAbsoluteIndex = function (index, length) { + index = _toInteger(index); + return index < 0 ? max(index + length, 0) : min$1(index, length); + }; + + // false -> Array#indexOf + // true -> Array#includes + + + + var _arrayIncludes = function (IS_INCLUDES) { + return function ($this, el, fromIndex) { + var O = _toIobject($this); + var length = _toLength(O.length); + var index = _toAbsoluteIndex(fromIndex, length); + var value; + // Array#includes uses SameValueZero equality algorithm + // eslint-disable-next-line no-self-compare + if (IS_INCLUDES && el != el) while (length > index) { + value = O[index++]; + // eslint-disable-next-line no-self-compare + if (value != value) return true; + // Array#indexOf ignores holes, Array#includes - not + } else for (;length > index; index++) if (IS_INCLUDES || index in O) { + if (O[index] === el) return IS_INCLUDES || index || 0; + } return !IS_INCLUDES && -1; + }; + }; + + function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; + } + + var _global = createCommonjsModule(function (module) { + // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 + var global = module.exports = typeof window != 'undefined' && window.Math == Math + ? window : typeof self != 'undefined' && self.Math == Math ? self + // eslint-disable-next-line no-new-func + : Function('return this')(); + if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef + }); + + var SHARED = '__core-js_shared__'; + var store = _global[SHARED] || (_global[SHARED] = {}); + var _shared = function (key) { + return store[key] || (store[key] = {}); + }; + + var id = 0; + var px = Math.random(); + var _uid = function (key) { + return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36)); + }; + + var shared = _shared('keys'); + + var _sharedKey = function (key) { + return shared[key] || (shared[key] = _uid(key)); + }; + + var arrayIndexOf = _arrayIncludes(false); + var IE_PROTO = _sharedKey('IE_PROTO'); + + var _objectKeysInternal = function (object, names) { + var O = _toIobject(object); + var i = 0; + var result = []; + var key; + for (key in O) if (key != IE_PROTO) _has(O, key) && result.push(key); + // Don't enum bug & hidden keys + while (names.length > i) if (_has(O, key = names[i++])) { + ~arrayIndexOf(result, key) || result.push(key); + } + return result; + }; + + // IE 8- don't enum bug keys + var _enumBugKeys = ( + 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf' + ).split(','); + + // 19.1.2.14 / 15.2.3.14 Object.keys(O) + + + + var _objectKeys = Object.keys || function keys(O) { + return _objectKeysInternal(O, _enumBugKeys); + }; + + var _core = createCommonjsModule(function (module) { + var core = module.exports = { version: '2.5.5' }; + if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef + }); + var _core_1 = _core.version; + + var _isObject = function (it) { + return typeof it === 'object' ? it !== null : typeof it === 'function'; + }; + + var _anObject = function (it) { + if (!_isObject(it)) throw TypeError(it + ' is not an object!'); + return it; + }; + + var _fails = function (exec) { + try { + return !!exec(); + } catch (e) { + return true; + } + }; + + // Thank's IE8 for his funny defineProperty + var _descriptors = !_fails(function () { + return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7; + }); + + var document$1 = _global.document; + // typeof document.createElement is 'object' in old IE + var is = _isObject(document$1) && _isObject(document$1.createElement); + var _domCreate = function (it) { + return is ? document$1.createElement(it) : {}; + }; + + var _ie8DomDefine = !_descriptors && !_fails(function () { + return Object.defineProperty(_domCreate('div'), 'a', { get: function () { return 7; } }).a != 7; + }); + + // 7.1.1 ToPrimitive(input [, PreferredType]) + + // instead of the ES6 spec version, we didn't implement @@toPrimitive case + // and the second argument - flag - preferred type is a string + var _toPrimitive = function (it, S) { + if (!_isObject(it)) return it; + var fn, val; + if (S && typeof (fn = it.toString) == 'function' && !_isObject(val = fn.call(it))) return val; + if (typeof (fn = it.valueOf) == 'function' && !_isObject(val = fn.call(it))) return val; + if (!S && typeof (fn = it.toString) == 'function' && !_isObject(val = fn.call(it))) return val; + throw TypeError("Can't convert object to primitive value"); + }; + + var dP = Object.defineProperty; + + var f = _descriptors ? Object.defineProperty : function defineProperty(O, P, Attributes) { + _anObject(O); + P = _toPrimitive(P, true); + _anObject(Attributes); + if (_ie8DomDefine) try { + return dP(O, P, Attributes); + } catch (e) { /* empty */ } + if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!'); + if ('value' in Attributes) O[P] = Attributes.value; + return O; + }; + + var _objectDp = { + f: f + }; + + var _propertyDesc = function (bitmap, value) { + return { + enumerable: !(bitmap & 1), + configurable: !(bitmap & 2), + writable: !(bitmap & 4), + value: value + }; + }; + + var _hide = _descriptors ? function (object, key, value) { + return _objectDp.f(object, key, _propertyDesc(1, value)); + } : function (object, key, value) { + object[key] = value; + return object; + }; + + var _redefine = createCommonjsModule(function (module) { + var SRC = _uid('src'); + var TO_STRING = 'toString'; + var $toString = Function[TO_STRING]; + var TPL = ('' + $toString).split(TO_STRING); + + _core.inspectSource = function (it) { + return $toString.call(it); + }; + + (module.exports = function (O, key, val, safe) { + var isFunction = typeof val == 'function'; + if (isFunction) _has(val, 'name') || _hide(val, 'name', key); + if (O[key] === val) return; + if (isFunction) _has(val, SRC) || _hide(val, SRC, O[key] ? '' + O[key] : TPL.join(String(key))); + if (O === _global) { + O[key] = val; + } else if (!safe) { + delete O[key]; + _hide(O, key, val); + } else if (O[key]) { + O[key] = val; + } else { + _hide(O, key, val); + } + // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative + })(Function.prototype, TO_STRING, function toString() { + return typeof this == 'function' && this[SRC] || $toString.call(this); + }); + }); + + var _aFunction = function (it) { + if (typeof it != 'function') throw TypeError(it + ' is not a function!'); + return it; + }; + + // optional / simple context binding + + var _ctx = function (fn, that, length) { + _aFunction(fn); + if (that === undefined) return fn; + switch (length) { + case 1: return function (a) { + return fn.call(that, a); + }; + case 2: return function (a, b) { + return fn.call(that, a, b); + }; + case 3: return function (a, b, c) { + return fn.call(that, a, b, c); + }; + } + return function (/* ...args */) { + return fn.apply(that, arguments); + }; + }; + + var PROTOTYPE = 'prototype'; + + var $export = function (type, name, source) { + var IS_FORCED = type & $export.F; + var IS_GLOBAL = type & $export.G; + var IS_STATIC = type & $export.S; + var IS_PROTO = type & $export.P; + var IS_BIND = type & $export.B; + var target = IS_GLOBAL ? _global : IS_STATIC ? _global[name] || (_global[name] = {}) : (_global[name] || {})[PROTOTYPE]; + var exports = IS_GLOBAL ? _core : _core[name] || (_core[name] = {}); + var expProto = exports[PROTOTYPE] || (exports[PROTOTYPE] = {}); + var key, own, out, exp; + if (IS_GLOBAL) source = name; + for (key in source) { + // contains in native + own = !IS_FORCED && target && target[key] !== undefined; + // export native or passed + out = (own ? target : source)[key]; + // bind timers to global for call from export context + exp = IS_BIND && own ? _ctx(out, _global) : IS_PROTO && typeof out == 'function' ? _ctx(Function.call, out) : out; + // extend global + if (target) _redefine(target, key, out, type & $export.U); + // export + if (exports[key] != out) _hide(exports, key, exp); + if (IS_PROTO && expProto[key] != out) expProto[key] = out; + } + }; + _global.core = _core; + // type bitmap + $export.F = 1; // forced + $export.G = 2; // global + $export.S = 4; // static + $export.P = 8; // proto + $export.B = 16; // bind + $export.W = 32; // wrap + $export.U = 64; // safe + $export.R = 128; // real proto method for `library` + var _export = $export; + + // most Object methods by ES6 should accept primitives + + + + var _objectSap = function (KEY, exec) { + var fn = (_core.Object || {})[KEY] || Object[KEY]; + var exp = {}; + exp[KEY] = exec(fn); + _export(_export.S + _export.F * _fails(function () { fn(1); }), 'Object', exp); + }; + + // 19.1.2.14 Object.keys(O) + + + + _objectSap('keys', function () { + return function keys(it) { + return _objectKeys(_toObject(it)); + }; + }); + + var keys = _core.Object.keys; + + var _stringRepeat = function repeat(count) { + var str = String(_defined(this)); + var res = ''; + var n = _toInteger(count); + if (n < 0 || n == Infinity) throw RangeError("Count can't be negative"); + for (;n > 0; (n >>>= 1) && (str += str)) if (n & 1) res += str; + return res; + }; + + _export(_export.P, 'String', { + // 21.1.3.13 String.prototype.repeat(count) + repeat: _stringRepeat + }); + + var repeat = _core.String.repeat; + + // https://github.com/tc39/proposal-string-pad-start-end + + + + + var _stringPad = function (that, maxLength, fillString, left) { + var S = String(_defined(that)); + var stringLength = S.length; + var fillStr = fillString === undefined ? ' ' : String(fillString); + var intMaxLength = _toLength(maxLength); + if (intMaxLength <= stringLength || fillStr == '') return S; + var fillLen = intMaxLength - stringLength; + var stringFiller = _stringRepeat.call(fillStr, Math.ceil(fillLen / fillStr.length)); + if (stringFiller.length > fillLen) stringFiller = stringFiller.slice(0, fillLen); + return left ? stringFiller + S : S + stringFiller; + }; + + var navigator = _global.navigator; + + var _userAgent = navigator && navigator.userAgent || ''; + + // https://github.com/tc39/proposal-string-pad-start-end + + + + + // https://github.com/zloirock/core-js/issues/280 + _export(_export.P + _export.F * /Version\/10\.\d+(\.\d+)? Safari\//.test(_userAgent), 'String', { + padStart: function padStart(maxLength /* , fillString = ' ' */) { + return _stringPad(this, maxLength, arguments.length > 1 ? arguments[1] : undefined, true); + } + }); + + var padStart = _core.String.padStart; + + // https://github.com/tc39/proposal-string-pad-start-end + + + + + // https://github.com/zloirock/core-js/issues/280 + _export(_export.P + _export.F * /Version\/10\.\d+(\.\d+)? Safari\//.test(_userAgent), 'String', { + padEnd: function padEnd(maxLength /* , fillString = ' ' */) { + return _stringPad(this, maxLength, arguments.length > 1 ? arguments[1] : undefined, false); + } + }); + + var padEnd = _core.String.padEnd; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + }; + + var createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + var get = function get(object, property, receiver) { + if (object === null) object = Function.prototype; + var desc = Object.getOwnPropertyDescriptor(object, property); + + if (desc === undefined) { + var parent = Object.getPrototypeOf(object); + + if (parent === null) { + return undefined; + } else { + return get(parent, property, receiver); + } + } else if ("value" in desc) { + return desc.value; + } else { + var getter = desc.get; + + if (getter === undefined) { + return undefined; + } + + return getter.call(receiver); + } + }; + + var inherits = function (subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; + }; + + var possibleConstructorReturn = function (self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && (typeof call === "object" || typeof call === "function") ? call : self; + }; + + var set = function set(object, property, value, receiver) { + var desc = Object.getOwnPropertyDescriptor(object, property); + + if (desc === undefined) { + var parent = Object.getPrototypeOf(object); + + if (parent !== null) { + set(parent, property, value, receiver); + } + } else if ("value" in desc && desc.writable) { + desc.value = value; + } else { + var setter = desc.set; + + if (setter !== undefined) { + setter.call(receiver, value); + } + } + + return value; + }; + + var slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; + }(); + + var toConsumableArray = function (arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } else { + return Array.from(arr); + } + }; + + /** Checks if value is string */ + function isString(str) { + return typeof str === 'string' || str instanceof String; + } + + /** Conforms string with fallback */ + function conform(res, str) { + var fallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; + + return isString(res) ? res : res ? str : fallback; + } + + /** + Direction + @prop {number} NONE + @prop {number} LEFT + @prop {number} RIGHT + */ + var DIRECTION = { + NONE: 0, + LEFT: -1, + RIGHT: 1 + /** + Direction + @enum {number} + */ + }; + + /** Returns next char position in direction */ + function indexInDirection(pos, direction) { + if (direction === DIRECTION.LEFT) --pos; + return pos; + } + + /** Escapes regular expression control chars */ + function escapeRegExp(str) { + return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1'); + } + + // cloned from https://github.com/epoberezkin/fast-deep-equal with small changes + function objectIncludes(b, a) { + if (a === b) return true; + + var arrA = Array.isArray(a), + arrB = Array.isArray(b), + i; + + if (arrA && arrB) { + if (a.length != b.length) return false; + for (i = 0; i < a.length; i++) { + if (!objectIncludes(a[i], b[i])) return false; + }return true; + } + + if (arrA != arrB) return false; + + if (a && b && (typeof a === 'undefined' ? 'undefined' : _typeof(a)) === 'object' && (typeof b === 'undefined' ? 'undefined' : _typeof(b)) === 'object') { + var keys = Object.keys(a); + // if (keys.length !== Object.keys(b).length) return false; + + var dateA = a instanceof Date, + dateB = b instanceof Date; + if (dateA && dateB) return a.getTime() == b.getTime(); + if (dateA != dateB) return false; + + var regexpA = a instanceof RegExp, + regexpB = b instanceof RegExp; + if (regexpA && regexpB) return a.toString() == b.toString(); + if (regexpA != regexpB) return false; + + for (i = 0; i < keys.length; i++) { + if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false; + }for (i = 0; i < keys.length; i++) { + if (!objectIncludes(a[keys[i]], b[keys[i]])) return false; + }return true; + } + + return false; + } + + /* eslint-disable no-undef */ + var g = typeof window !== 'undefined' && window || typeof global !== 'undefined' && global.global === global && global || typeof self !== 'undefined' && self.self === self && self || {}; + + /** Provides details of changing input */ + + var ActionDetails = function () { + /** Old input value */ + + /** Current input value */ + function ActionDetails(value, cursorPos, oldValue, oldSelection) { + classCallCheck(this, ActionDetails); + + this.value = value; + this.cursorPos = cursorPos; + this.oldValue = oldValue; + this.oldSelection = oldSelection; + + // double check if left part was changed (autofilling, other non-standard input triggers) + while (this.value.slice(0, this.startChangePos) !== this.oldValue.slice(0, this.startChangePos)) { + --this.oldSelection.start; + } + } + + /** + Start changing position + @readonly + */ + + /** Old selection */ + + /** Current cursor position */ + + + createClass(ActionDetails, [{ + key: 'startChangePos', + get: function get$$1() { + return Math.min(this.cursorPos, this.oldSelection.start); + } + + /** + Inserted symbols count + @readonly + */ + + }, { + key: 'insertedCount', + get: function get$$1() { + return this.cursorPos - this.startChangePos; + } + + /** + Inserted symbols + @readonly + */ + + }, { + key: 'inserted', + get: function get$$1() { + return this.value.substr(this.startChangePos, this.insertedCount); + } + + /** + Removed symbols count + @readonly + */ + + }, { + key: 'removedCount', + get: function get$$1() { + // Math.max for opposite operation + return Math.max(this.oldSelection.end - this.startChangePos || + // for Delete + this.oldValue.length - this.value.length, 0); + } + + /** + Removed symbols + @readonly + */ + + }, { + key: 'removed', + get: function get$$1() { + return this.oldValue.substr(this.startChangePos, this.removedCount); + } + + /** + Unchanged head symbols + @readonly + */ + + }, { + key: 'head', + get: function get$$1() { + return this.value.substring(0, this.startChangePos); + } + + /** + Unchanged tail symbols + @readonly + */ + + }, { + key: 'tail', + get: function get$$1() { + return this.value.substring(this.startChangePos + this.insertedCount); + } + + /** + Remove direction + @readonly + */ + + }, { + key: 'removeDirection', + get: function get$$1() { + if (!this.removedCount || this.insertedCount) return DIRECTION.NONE; + + // align right if delete at right or if range removed (event with backspace) + return this.oldSelection.end === this.cursorPos || this.oldSelection.start === this.cursorPos ? DIRECTION.RIGHT : DIRECTION.LEFT; + } + }]); + return ActionDetails; + }(); + + /** + Provides details of changing model value + @param {Object} [details] + @param {string} [details.inserted] - Inserted symbols + @param {boolean} [details.overflow] - Is overflowed + @param {number} [details.removeCount] - Removed symbols count + @param {number} [details.shift] - Additional offset if any changes occurred before current position + */ + var ChangeDetails = function () { + /** Additional offset if any changes occurred before current position */ + + /** Inserted symbols */ + function ChangeDetails(details) { + classCallCheck(this, ChangeDetails); + + _extends(this, { + inserted: '', + overflow: false, + shift: 0 + }, details); + } + + /** + Aggregate changes + @returns {ChangeDetails} `this` + */ + + /** Is overflowed */ + + + createClass(ChangeDetails, [{ + key: 'aggregate', + value: function aggregate(details) { + if (details.rawInserted) this.rawInserted += details.rawInserted; + this.inserted += details.inserted; + this.shift += details.shift; + this.overflow = this.overflow || details.overflow; + return this; + } + + /** Total offset considering all changes */ + + }, { + key: 'offset', + get: function get$$1() { + return this.shift + this.inserted.length; + } + + /** Raw inserted is used by dynamic mask */ + + }, { + key: 'rawInserted', + get: function get$$1() { + return this._rawInserted != null ? this._rawInserted : this.inserted; + }, + set: function set$$1(rawInserted) { + this._rawInserted = rawInserted; + } + }]); + return ChangeDetails; + }(); + + /** Supported mask type */ + + + /** Append flags */ + + + /** Extract flags */ + + /** Provides common masking stuff */ + var Masked = function () { + /** Does additional processing in the end of editing */ + + /** Transforms value before mask processing */ + function Masked(opts) { + classCallCheck(this, Masked); + + this._value = ''; + this._update(opts); + this.isInitialized = true; + } + + /** Sets and applies new options */ + + /** */ + + /** Validates if value is acceptable */ + // $Shape; TODO after fix https://github.com/facebook/flow/issues/4773 + + /** @type {Mask} */ + + + createClass(Masked, [{ + key: 'updateOptions', + value: function updateOptions(opts) { + this.withValueRefresh(this._update.bind(this, opts)); + } + + /** + Sets new options + @protected + */ + + }, { + key: '_update', + value: function _update(opts) { + _extends(this, opts); + } + + /** Clones masked with options and value */ + + }, { + key: 'clone', + value: function clone() { + var m = new Masked(this); + m._value = this.value.slice(); + return m; + } + + /** */ + + }, { + key: 'assign', + value: function assign(source) { + // $FlowFixMe + return _extends(this, source); + } + + /** Resets value */ + + }, { + key: 'reset', + value: function reset() { + this._value = ''; + } + + /** */ + + }, { + key: 'resolve', + + + /** Resolve new value */ + value: function resolve(value) { + this.reset(); + this._append(value, { input: true }); + this._appendTail(); + this.doCommit(); + return this.value; + } + + /** */ + + }, { + key: 'nearestInputPos', + + + /** Finds nearest input position in direction */ + value: function nearestInputPos(cursorPos, direction) { + return cursorPos; + } + + /** Extracts value in range considering flags */ + + }, { + key: 'extractInput', + value: function extractInput() { + var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length; + + return this.value.slice(fromPos, toPos); + } + + /** Extracts tail in range */ + + }, { + key: '_extractTail', + value: function _extractTail() { + var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length; + + return { + value: this.extractInput(fromPos, toPos), + fromPos: fromPos, + toPos: toPos + }; + } + + /** Appends tail */ + + }, { + key: '_appendTail', + value: function _appendTail(tail) { + return this._append(tail ? tail.value : '', { tail: true }); + } + + /** Appends symbols considering flags */ + + }, { + key: '_append', + value: function _append(str) { + var flags = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var oldValueLength = this.value.length; + var consistentValue = this.clone(); + var overflow = false; + + str = this.doPrepare(str, flags); + + for (var ci = 0; ci < str.length; ++ci) { + this._value += str[ci]; + if (this.doValidate(flags) === false) { + this.assign(consistentValue); + if (!flags.input) { + // in `input` mode dont skip invalid chars + overflow = true; + break; + } + } + + consistentValue = this.clone(); + } + + return new ChangeDetails({ + inserted: this.value.slice(oldValueLength), + overflow: overflow + }); + } + + /** Appends symbols considering tail */ + + }, { + key: 'appendWithTail', + value: function appendWithTail(str, tail) { + // TODO refactor + var aggregateDetails = new ChangeDetails(); + var consistentValue = this.clone(); + var consistentAppended = void 0; + + for (var ci = 0; ci < str.length; ++ci) { + var ch = str[ci]; + + var appendDetails = this._append(ch, { input: true }); + consistentAppended = this.clone(); + var tailAppended = !appendDetails.overflow && !this._appendTail(tail).overflow; + if (!tailAppended || this.doValidate({ tail: true }) === false) { + this.assign(consistentValue); + break; + } + + this.assign(consistentAppended); + consistentValue = this.clone(); + aggregateDetails.aggregate(appendDetails); + } + + // TODO needed for cases when + // 1) REMOVE ONLY AND NO LOOP AT ALL + // 2) last loop iteration removes tail + // 3) when breaks on tail insert + + // aggregate only shift from tail + aggregateDetails.shift += this._appendTail(tail).shift; + + return aggregateDetails; + } + + /** */ + + }, { + key: 'remove', + value: function remove() { + var from = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var count = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length - from; + + this._value = this.value.slice(0, from) + this.value.slice(from + count); + return new ChangeDetails(); + } + + /** Calls function and reapplies current value */ + + }, { + key: 'withValueRefresh', + value: function withValueRefresh(fn) { + if (this._refreshing || !this.isInitialized) return fn(); + this._refreshing = true; + + var unmasked = this.unmaskedValue; + var value = this.value; + + var ret = fn(); + + // try to update with raw value first to keep fixed chars + if (this.resolve(value) !== value) { + // or fallback to unmasked + this.unmaskedValue = unmasked; + } + + delete this._refreshing; + return ret; + } + + /** + Prepares string before mask processing + @protected + */ + + }, { + key: 'doPrepare', + value: function doPrepare(str) { + var flags = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + return this.prepare ? this.prepare(str, this, flags) : str; + } + + /** + Validates if value is acceptable + @protected + */ + + }, { + key: 'doValidate', + value: function doValidate(flags) { + return !this.validate || this.validate(this.value, this, flags); + } + + /** + Does additional processing in the end of editing + @protected + */ + + }, { + key: 'doCommit', + value: function doCommit() { + if (this.commit) this.commit(this.value, this); + } + + // TODO + // insert (str, fromPos, flags) + + /** */ + + }, { + key: 'splice', + value: function splice(start, deleteCount, inserted, removeDirection) { + var tailPos = start + deleteCount; + var tail = this._extractTail(tailPos); + + var startChangePos = this.nearestInputPos(start, removeDirection); + var changeDetails = new ChangeDetails({ + shift: startChangePos - start // adjust shift if start was aligned + }).aggregate(this.remove(startChangePos)).aggregate(this.appendWithTail(inserted, tail)); + + return changeDetails; + } + }, { + key: 'value', + get: function get$$1() { + return this._value; + }, + set: function set$$1(value) { + this.resolve(value); + } + }, { + key: 'unmaskedValue', + get: function get$$1() { + return this.value; + }, + set: function set$$1(value) { + this.reset(); + this._append(value); + this._appendTail(); + this.doCommit(); + } + + /** */ + + }, { + key: 'typedValue', + get: function get$$1() { + return this.unmaskedValue; + }, + set: function set$$1(value) { + this.unmaskedValue = value; + } + + /** Value that includes raw user input */ + + }, { + key: 'rawInputValue', + get: function get$$1() { + return this.extractInput(0, this.value.length, { raw: true }); + }, + set: function set$$1(value) { + this.reset(); + this._append(value, { raw: true }); + this._appendTail(); + this.doCommit(); + } + + /** */ + + }, { + key: 'isComplete', + get: function get$$1() { + return true; + } + }]); + return Masked; + }(); + + /** Get Masked class by mask type */ + function maskedClass(mask) { + if (mask == null) { + throw new Error('mask property should be defined'); + } + + if (mask instanceof RegExp) return g.VindiCCMask.MaskedRegExp; + if (isString(mask)) return g.VindiCCMask.MaskedPattern; + if (mask instanceof Date || mask === Date) return g.VindiCCMask.MaskedDate; + if (mask instanceof Number || typeof mask === 'number' || mask === Number) return g.VindiCCMask.MaskedNumber; + if (Array.isArray(mask) || mask === Array) return g.VindiCCMask.MaskedDynamic; + // $FlowFixMe + if (mask.prototype instanceof g.VindiCCMask.Masked) return mask; + // $FlowFixMe + if (mask instanceof Function) return g.VindiCCMask.MaskedFunction; + + console.warn('Mask not found for mask', mask); // eslint-disable-line no-console + return g.VindiCCMask.Masked; + } + + /** Creates new {@link Masked} depending on mask type */ + function createMask(opts) { + opts = _extends({}, opts); // clone + var mask = opts.mask; + + if (mask instanceof g.VindiCCMask.Masked) return mask; + + var MaskedClass = maskedClass(mask); + return new MaskedClass(opts); + } + + /** */ + + /** */ + var PatternDefinition = function () { + /** */ + + /** */ + + /** */ + + /** */ + function PatternDefinition(opts) { + classCallCheck(this, PatternDefinition); + // TODO flow + _extends(this, opts); + + if (this.mask) { + this._masked = createMask(opts); + } + } + + /** */ + + /** */ + + /** */ + + /** */ + + /** */ + + + /** */ + + + createClass(PatternDefinition, [{ + key: 'reset', + value: function reset() { + this.isHollow = false; + this.isRawInput = false; + if (this._masked) this._masked.reset(); + } + + /** */ + + }, { + key: 'resolve', + + + /** */ + value: function resolve(ch) { + if (!this._masked) return false; + return this._masked.resolve(ch); + } + }, { + key: 'isInput', + get: function get$$1() { + return this.type === PatternDefinition.TYPES.INPUT; + } + + /** */ + + }, { + key: 'isHiddenHollow', + get: function get$$1() { + return this.isHollow && this.optional; + } + }]); + return PatternDefinition; + }(); + + PatternDefinition.DEFAULTS = { + '0': /\d/, + 'a': /[\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/, // http://stackoverflow.com/a/22075070 + '*': /./ + }; + /** + @prop {string} INPUT + @prop {string} FIXED + */ + PatternDefinition.TYPES = { + INPUT: 'input', + FIXED: 'fixed' + }; + + /** */ + + + /** */ + + /** + Pattern group symbols from parent + @param {MaskedPattern} masked - Internal {@link masked} model + @param {Object} opts + @param {string} opts.name - Group name + @param {number} opts.offset - Group offset in masked definitions array + @param {string} opts.mask - Group mask + @param {Function} [opts.validate] - Custom group validator + */ + var PatternGroup = function () { + /** Group mask */ + + /** Group name */ + + /** */ + function PatternGroup(masked, _ref) { + var name = _ref.name, + offset = _ref.offset, + mask = _ref.mask, + validate = _ref.validate; + classCallCheck(this, PatternGroup); + + this.masked = masked; + this.name = name; + this.offset = offset; + this.mask = mask; + this.validate = validate || function () { + return true; + }; + } + + /** Slice of internal {@link masked} value */ + + /** Custom group validator */ + + /** Group offset in masked definitions array */ + + + /** Internal {@link masked} model */ + + /** */ + + + createClass(PatternGroup, [{ + key: 'doValidate', + + + /** Validates if current value is acceptable */ + value: function doValidate(flags) { + return this.validate(this.value, this, flags); + } + }, { + key: 'value', + get: function get$$1() { + return this.masked.value.slice(this.masked.mapDefIndexToPos(this.offset), this.masked.mapDefIndexToPos(this.offset + this.mask.length)); + } + + /** Unmasked slice of internal {@link masked} value */ + + }, { + key: 'unmaskedValue', + get: function get$$1() { + return this.masked.extractInput(this.masked.mapDefIndexToPos(this.offset), this.masked.mapDefIndexToPos(this.offset + this.mask.length)); + } + }]); + return PatternGroup; + }(); + var RangeGroup = function () { + /** @type {Function} */ + function RangeGroup(_ref2) { + var _ref3 = slicedToArray(_ref2, 2), + from = _ref3[0], + to = _ref3[1]; + + var maxlen = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : String(to).length; + classCallCheck(this, RangeGroup); + + this._from = from; + this._to = to; + this._maxLength = maxlen; + this.validate = this.validate.bind(this); + + this._update(); + } + /** @type {string} */ + + + createClass(RangeGroup, [{ + key: '_update', + value: function _update() { + this._maxLength = Math.max(this._maxLength, String(this.to).length); + this.mask = '0'.repeat(this._maxLength); + } + }, { + key: 'validate', + value: function validate(str) { + var minstr = ''; + var maxstr = ''; + + var _ref4 = str.match(/^(\D*)(\d*)(\D*)/) || [], + _ref5 = slicedToArray(_ref4, 3), + placeholder = _ref5[1], + num = _ref5[2]; + + if (num) { + minstr = '0'.repeat(placeholder.length) + num; + maxstr = '9'.repeat(placeholder.length) + num; + } + + var firstNonZero = str.search(/[^0]/); + if (firstNonZero === -1 && str.length <= this._matchFrom) return true; + + minstr = minstr.padEnd(this._maxLength, '0'); + maxstr = maxstr.padEnd(this._maxLength, '9'); + + return this.from <= Number(maxstr) && Number(minstr) <= this.to; + } + }, { + key: 'to', + get: function get$$1() { + return this._to; + }, + set: function set$$1(to) { + this._to = to; + this._update(); + } + }, { + key: 'from', + get: function get$$1() { + return this._from; + }, + set: function set$$1(from) { + this._from = from; + this._update(); + } + }, { + key: 'maxLength', + get: function get$$1() { + return this._maxLength; + }, + set: function set$$1(maxLength) { + this._maxLength = maxLength; + this._update(); + } + }, { + key: '_matchFrom', + get: function get$$1() { + return this.maxLength - String(this.from).length; + } + }]); + return RangeGroup; + }(); + + /** Pattern group that validates enum values */ + function EnumGroup(enums) { + return { + mask: '*'.repeat(enums[0].length), + validate: function validate(value, group, flags) { + return enums.some(function (e) { + return e.indexOf(group.unmaskedValue) >= 0; + }); + } + }; + } + + PatternGroup.Range = RangeGroup; + PatternGroup.Enum = EnumGroup; + + var ChunksTailDetails = function () { + function ChunksTailDetails(chunks) { + classCallCheck(this, ChunksTailDetails); + + this.chunks = chunks; + } + + createClass(ChunksTailDetails, [{ + key: 'value', + get: function get$$1() { + return this.chunks.map(function (c) { + return c.value; + }).join(''); + } + }, { + key: 'fromPos', + get: function get$$1() { + var firstChunk = this.chunks[0]; + return firstChunk && firstChunk.stop; + } + }, { + key: 'toPos', + get: function get$$1() { + var lastChunk = this.chunks[this.chunks.length - 1]; + return lastChunk && lastChunk.stop; + } + }]); + return ChunksTailDetails; + }(); + + /** + Pattern mask + @param {Object} opts + @param {Object} opts.groups + @param {Object} opts.definitions + @param {string} opts.placeholderChar + @param {boolean} opts.lazy + */ + var MaskedPattern = function (_Masked) { + inherits(MaskedPattern, _Masked); + + // TODO mask type + /** Single char for empty input */ + + + /** */ + function MaskedPattern() { + var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + classCallCheck(this, MaskedPattern); + // TODO type $Shape={} does not work + opts.definitions = _extends({}, PatternDefinition.DEFAULTS, opts.definitions); + return possibleConstructorReturn(this, (MaskedPattern.__proto__ || Object.getPrototypeOf(MaskedPattern)).call(this, _extends({}, MaskedPattern.DEFAULTS, opts))); + } + + /** + @override + @param {Object} opts + */ + + /** Show placeholder only when needed */ + + /** */ + + + createClass(MaskedPattern, [{ + key: '_update', + value: function _update() { + var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + opts.definitions = _extends({}, this.definitions, opts.definitions); + get(MaskedPattern.prototype.__proto__ || Object.getPrototypeOf(MaskedPattern.prototype), '_update', this).call(this, opts); + this._rebuildMask(); + } + + /** */ + + }, { + key: '_rebuildMask', + value: function _rebuildMask() { + var _this2 = this; + + var defs = this.definitions; + this._charDefs = []; + this._groupDefs = []; + + var pattern = this.mask; + if (!pattern || !defs) return; + + var unmaskingBlock = false; + var optionalBlock = false; + var stopAlign = false; + + var _loop = function _loop(_i) { + if (_this2.groups) { + var p = pattern.slice(_i); + var gNames = Object.keys(_this2.groups).filter(function (gName) { + return p.indexOf(gName) === 0; + }); + // order by key length + gNames.sort(function (a, b) { + return b.length - a.length; + }); + // use group name with max length + var gName = gNames[0]; + if (gName) { + var group = _this2.groups[gName]; + _this2._groupDefs.push(new PatternGroup(_this2, { + name: gName, + offset: _this2._charDefs.length, + mask: group.mask, + validate: group.validate + })); + pattern = pattern.replace(gName, group.mask); + } + } + + var char = pattern[_i]; + var type = char in defs ? PatternDefinition.TYPES.INPUT : PatternDefinition.TYPES.FIXED; + var unmasking = type === PatternDefinition.TYPES.INPUT || unmaskingBlock; + var optional = type === PatternDefinition.TYPES.INPUT && optionalBlock; + + if (char === MaskedPattern.STOP_CHAR) { + stopAlign = true; + return 'continue'; + } + + if (char === '{' || char === '}') { + unmaskingBlock = !unmaskingBlock; + return 'continue'; + } + + if (char === '[' || char === ']') { + optionalBlock = !optionalBlock; + return 'continue'; + } + + if (char === MaskedPattern.ESCAPE_CHAR) { + ++_i; + char = pattern[_i]; + if (!char) return 'break'; + type = PatternDefinition.TYPES.FIXED; + } + + _this2._charDefs.push(new PatternDefinition({ + char: char, + type: type, + optional: optional, + stopAlign: stopAlign, + unmasking: unmasking, + mask: type === PatternDefinition.TYPES.INPUT ? defs[char] : function (value) { + return value === char; + } + })); + + stopAlign = false; + i = _i; + }; + + _loop2: for (var i = 0; i < pattern.length; ++i) { + var _ret = _loop(i); + + switch (_ret) { + case 'continue': + continue; + + case 'break': + break _loop2;} + } + } + + /** + @override + */ + + }, { + key: 'doValidate', + value: function doValidate() { + var _babelHelpers$get; + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return this._groupDefs.every(function (g$$1) { + return g$$1.doValidate.apply(g$$1, toConsumableArray(args)); + }) && (_babelHelpers$get = get(MaskedPattern.prototype.__proto__ || Object.getPrototypeOf(MaskedPattern.prototype), 'doValidate', this)).call.apply(_babelHelpers$get, [this].concat(toConsumableArray(args))); + } + + /** + @override + */ + + }, { + key: 'clone', + value: function clone() { + var _this3 = this; + + var m = new MaskedPattern(this); + m._value = this.value; + // $FlowFixMe + m._charDefs.forEach(function (d, i) { + return _extends(d, _this3._charDefs[i]); + }); + // $FlowFixMe + m._groupDefs.forEach(function (d, i) { + return _extends(d, _this3._groupDefs[i]); + }); + return m; + } + + /** + @override + */ + + }, { + key: 'reset', + value: function reset() { + get(MaskedPattern.prototype.__proto__ || Object.getPrototypeOf(MaskedPattern.prototype), 'reset', this).call(this); + this._charDefs.forEach(function (d) { + delete d.isHollow; + }); + } + + /** + @override + */ + + }, { + key: 'hiddenHollowsBefore', + + + /** */ + value: function hiddenHollowsBefore(defIndex) { + return this._charDefs.slice(0, defIndex).filter(function (d) { + return d.isHiddenHollow; + }).length; + } + + /** Map definition index to position on view */ + + }, { + key: 'mapDefIndexToPos', + value: function mapDefIndexToPos(defIndex) { + return defIndex - this.hiddenHollowsBefore(defIndex); + } + + /** Map position on view to definition index */ + + }, { + key: 'mapPosToDefIndex', + value: function mapPosToDefIndex(pos) { + var defIndex = pos; + for (var di = 0; di < this._charDefs.length; ++di) { + var def = this._charDefs[di]; + if (di >= defIndex) break; + if (def.isHiddenHollow) ++defIndex; + } + return defIndex; + } + + /** + @override + */ + + }, { + key: '_appendTail', + + + /** + @override + */ + value: function _appendTail(tail) { + var details = new ChangeDetails(); + if (tail) { + details.aggregate(tail instanceof ChunksTailDetails ? this._appendChunks(tail.chunks, { tail: true }) : get(MaskedPattern.prototype.__proto__ || Object.getPrototypeOf(MaskedPattern.prototype), '_appendTail', this).call(this, tail)); + } + return details.aggregate(this._appendPlaceholder()); + } + + /** + @override + */ + + }, { + key: '_append', + value: function _append(str) { + var flags = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var oldValueLength = this.value.length; + var rawInserted = ''; + var overflow = false; + + str = this.doPrepare(str, flags); + + for (var ci = 0, di = this.mapPosToDefIndex(this.value.length); ci < str.length;) { + var ch = str[ci]; + var def = this._charDefs[di]; + + // check overflow + if (def == null) { + overflow = true; + break; + } + + // reset + def.isHollow = false; + + var resolved = void 0, + skipped = void 0; + var chres = conform(def.resolve(ch), ch); + + if (def.type === PatternDefinition.TYPES.INPUT) { + if (chres) { + this._value += chres; + if (!this.doValidate()) { + chres = ''; + this._value = this.value.slice(0, -1); + } + } + + resolved = !!chres; + skipped = !chres && !def.optional; + + if (!chres) { + if (!def.optional && !flags.input && !this.lazy) { + this._value += this.placeholderChar; + skipped = false; + } + if (!skipped) def.isHollow = true; + } else { + rawInserted += chres; + } + } else { + this._value += def.char; + resolved = chres && (def.unmasking || flags.input || flags.raw) && !flags.tail; + def.isRawInput = resolved && (flags.raw || flags.input); + if (def.isRawInput) rawInserted += def.char; + } + + if (!skipped) ++di; + if (resolved || skipped) ++ci; + } + + return new ChangeDetails({ + inserted: this.value.slice(oldValueLength), + rawInserted: rawInserted, + overflow: overflow + }); + } + + /** Appends chunks splitted by stop chars */ + + }, { + key: '_appendChunks', + value: function _appendChunks(chunks) { + var details = new ChangeDetails(); + + for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } + + for (var ci = 0; ci < chunks.length; ++ci) { + var _chunks$ci = chunks[ci], + stop = _chunks$ci.stop, + value = _chunks$ci.value; + + var fromDef = stop != null && this._charDefs[stop]; + // lets double check if stopAlign is here + if (fromDef && fromDef.stopAlign) details.aggregate(this._appendPlaceholder(stop)); + if (details.aggregate(this._append.apply(this, [value].concat(toConsumableArray(args)))).overflow) break; + } + return details; + } + + /** + @override + */ + + }, { + key: '_extractTail', + value: function _extractTail() { + var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length; + + return new ChunksTailDetails(this._extractInputChunks(fromPos, toPos)); + } + + /** + @override + */ + + }, { + key: 'extractInput', + value: function extractInput() { + var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length; + var flags = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + if (fromPos === toPos) return ''; + + var str = this.value; + var input = ''; + + var toDefIndex = this.mapPosToDefIndex(toPos); + for (var ci = fromPos, di = this.mapPosToDefIndex(fromPos); ci < toPos && ci < str.length && di < toDefIndex; ++di) { + var ch = str[ci]; + var def = this._charDefs[di]; + + if (!def) break; + if (def.isHiddenHollow) continue; + + if (def.isInput && !def.isHollow || flags.raw && !def.isInput && def.isRawInput) input += ch; + ++ci; + } + return input; + } + + /** Extracts chunks from input splitted by stop chars */ + + }, { + key: '_extractInputChunks', + value: function _extractInputChunks() { + var _this4 = this; + + var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length; + + if (fromPos === toPos) return []; + + var fromDefIndex = this.mapPosToDefIndex(fromPos); + var toDefIndex = this.mapPosToDefIndex(toPos); + var stopDefIndices = this._charDefs.map(function (d, i) { + return [d, i]; + }).slice(fromDefIndex, toDefIndex).filter(function (_ref) { + var _ref2 = slicedToArray(_ref, 1), + d = _ref2[0]; + + return d.stopAlign; + }).map(function (_ref3) { + var _ref4 = slicedToArray(_ref3, 2), + i = _ref4[1]; + + return i; + }); + + var stops = [fromDefIndex].concat(toConsumableArray(stopDefIndices), [toDefIndex]); + + return stops.map(function (s, i) { + return { + stop: stopDefIndices.indexOf(s) >= 0 ? s : null, + + value: _this4.extractInput(_this4.mapDefIndexToPos(s), _this4.mapDefIndexToPos(stops[++i])) + }; + }).filter(function (_ref5) { + var stop = _ref5.stop, + value = _ref5.value; + return stop != null || value; + }); + } + + /** Appends placeholder depending on laziness */ + + }, { + key: '_appendPlaceholder', + value: function _appendPlaceholder(toDefIndex) { + var oldValueLength = this.value.length; + var maxDefIndex = toDefIndex || this._charDefs.length; + for (var di = this.mapPosToDefIndex(this.value.length); di < maxDefIndex; ++di) { + var def = this._charDefs[di]; + if (def.isInput) def.isHollow = true; + + if (!this.lazy || toDefIndex) { + this._value += !def.isInput && def.char != null ? def.char : !def.optional ? this.placeholderChar : ''; + } + } + return new ChangeDetails({ + inserted: this.value.slice(oldValueLength) + }); + } + + /** + @override + */ + + }, { + key: 'remove', + value: function remove() { + var from = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var count = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length - from; + + var fromDefIndex = this.mapPosToDefIndex(from); + var toDefIndex = this.mapPosToDefIndex(from + count); + this._charDefs.slice(fromDefIndex, toDefIndex).forEach(function (d) { + return d.reset(); + }); + + return get(MaskedPattern.prototype.__proto__ || Object.getPrototypeOf(MaskedPattern.prototype), 'remove', this).call(this, from, count); + } + + /** + @override + */ + + }, { + key: 'nearestInputPos', + value: function nearestInputPos(cursorPos) { + var direction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DIRECTION.NONE; + + var step = direction || DIRECTION.RIGHT; + + var initialDefIndex = this.mapPosToDefIndex(cursorPos); + var initialDef = this._charDefs[initialDefIndex]; + var di = initialDefIndex; + + var firstInputIndex = void 0, + firstFilledInputIndex = void 0, + firstVisibleHollowIndex = void 0, + nextdi = void 0; + + // check if chars at right is acceptable for LEFT and NONE directions + if (direction !== DIRECTION.RIGHT && (initialDef && initialDef.isInput || + // in none direction latest position is acceptable also + direction === DIRECTION.NONE && cursorPos === this.value.length)) { + firstInputIndex = initialDefIndex; + if (initialDef && !initialDef.isHollow) firstFilledInputIndex = initialDefIndex; + } + + if (firstFilledInputIndex == null && direction == DIRECTION.LEFT || firstInputIndex == null) { + // search forward + for (nextdi = indexInDirection(di, step); 0 <= nextdi && nextdi < this._charDefs.length; di += step, nextdi += step) { + var nextDef = this._charDefs[nextdi]; + if (firstInputIndex == null && nextDef.isInput) { + firstInputIndex = di; + if (direction === DIRECTION.NONE) break; + } + if (firstVisibleHollowIndex == null && nextDef.isHollow && !nextDef.isHiddenHollow) firstVisibleHollowIndex = di; + if (nextDef.isInput && !nextDef.isHollow) { + firstFilledInputIndex = di; + break; + } + } + } + + // for lazy if has aligned left inside fixed and has came to the start - use start position + if (direction === DIRECTION.LEFT && di === 0 && this.lazy && !this.extractInput() && (!initialDef || !initialDef.isInput)) firstInputIndex = 0; + + if (direction === DIRECTION.LEFT || firstInputIndex == null) { + // search backward + step = -step; + var overflow = false; + + // find hollows only before initial pos + for (nextdi = indexInDirection(di, step); 0 <= nextdi && nextdi < this._charDefs.length; di += step, nextdi += step) { + var _nextDef = this._charDefs[nextdi]; + if (_nextDef.isInput) { + firstInputIndex = di; + if (_nextDef.isHollow && !_nextDef.isHiddenHollow) break; + } + + // if hollow not found before start position - set `overflow` + // and try to find just any input + if (di === initialDefIndex) overflow = true; + + // first input found + if (overflow && firstInputIndex != null) break; + } + + // process overflow + overflow = overflow || nextdi >= this._charDefs.length; + if (overflow && firstInputIndex != null) di = firstInputIndex; + } else if (firstFilledInputIndex == null) { + // adjust index if delete at right and filled input not found at right + di = firstVisibleHollowIndex != null ? firstVisibleHollowIndex : firstInputIndex; + } + + return this.mapDefIndexToPos(di); + } + + /** Get group by name */ + + }, { + key: 'group', + value: function group(name) { + return this.groupsByName(name)[0]; + } + + /** Get all groups by name */ + + }, { + key: 'groupsByName', + value: function groupsByName(name) { + return this._groupDefs.filter(function (g$$1) { + return g$$1.name === name; + }); + } + }, { + key: 'isComplete', + get: function get$$1() { + var _this5 = this; + + return !this._charDefs.some(function (d, i) { + return d.isInput && !d.optional && (d.isHollow || !_this5.extractInput(i, i + 1)); + }); + } + }, { + key: 'unmaskedValue', + get: function get$$1() { + var str = this.value; + var unmasked = ''; + + for (var ci = 0, di = 0; ci < str.length && di < this._charDefs.length; ++di) { + var ch = str[ci]; + var def = this._charDefs[di]; + + if (def.isHiddenHollow) continue; + if (def.unmasking && !def.isHollow) unmasked += ch; + ++ci; + } + + return unmasked; + }, + set: function set$$1(unmaskedValue) { + set(MaskedPattern.prototype.__proto__ || Object.getPrototypeOf(MaskedPattern.prototype), 'unmaskedValue', unmaskedValue, this); + } + }]); + return MaskedPattern; + }(Masked); + + MaskedPattern.DEFAULTS = { + lazy: true, + placeholderChar: '_' + }; + MaskedPattern.STOP_CHAR = '`'; + MaskedPattern.ESCAPE_CHAR = '\\'; + MaskedPattern.Definition = PatternDefinition; + MaskedPattern.Group = PatternGroup; + + /** Date mask */ + + var MaskedDate = function (_MaskedPattern) { + inherits(MaskedDate, _MaskedPattern); + + /** + @param {Object} opts + */ + + /** Start date */ + + /** Format Date to string */ + function MaskedDate(opts) { + classCallCheck(this, MaskedDate); + return possibleConstructorReturn(this, (MaskedDate.__proto__ || Object.getPrototypeOf(MaskedDate)).call(this, _extends({}, MaskedDate.DEFAULTS, opts))); + } + + /** + @override + */ + + /** End date */ + + /** Pattern mask for date according to {@link MaskedDate#format} */ + + + /** Parse string to Date */ + + + createClass(MaskedDate, [{ + key: '_update', + value: function _update(opts) { + if (opts.mask === Date) delete opts.mask; + if (opts.pattern) { + opts.mask = opts.pattern; + delete opts.pattern; + } + + var groups = opts.groups; + opts.groups = _extends({}, MaskedDate.GET_DEFAULT_GROUPS()); + // adjust year group + if (opts.min) opts.groups.Y.from = opts.min.getFullYear(); + if (opts.max) opts.groups.Y.to = opts.max.getFullYear(); + _extends(opts.groups, groups); + + get(MaskedDate.prototype.__proto__ || Object.getPrototypeOf(MaskedDate.prototype), '_update', this).call(this, opts); + } + + /** + @override + */ + + }, { + key: 'doValidate', + value: function doValidate() { + var _babelHelpers$get; + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + var valid = (_babelHelpers$get = get(MaskedDate.prototype.__proto__ || Object.getPrototypeOf(MaskedDate.prototype), 'doValidate', this)).call.apply(_babelHelpers$get, [this].concat(toConsumableArray(args))); + var date = this.date; + + return valid && (!this.isComplete || this.isDateExist(this.value) && date && (this.min == null || this.min <= date) && (this.max == null || date <= this.max)); + } + + /** Checks if date is exists */ + + }, { + key: 'isDateExist', + value: function isDateExist(str) { + return this.format(this.parse(str)) === str; + } + + /** Parsed Date */ + + }, { + key: 'date', + get: function get$$1() { + return this.isComplete ? this.parse(this.value) : null; + }, + set: function set$$1(date) { + this.value = this.format(date); + } + + /** + @override + */ + + }, { + key: 'typedValue', + get: function get$$1() { + return this.date; + }, + set: function set$$1(value) { + this.date = value; + } + }]); + return MaskedDate; + }(MaskedPattern); + + MaskedDate.DEFAULTS = { + pattern: 'd{.}`m{.}`Y', + format: function format(date) { + var day = String(date.getDate()).padStart(2, '0'); + var month = String(date.getMonth() + 1).padStart(2, '0'); + var year = date.getFullYear(); + + return [day, month, year].join('.'); + }, + parse: function parse(str) { + var _str$split = str.split('.'), + _str$split2 = slicedToArray(_str$split, 3), + day = _str$split2[0], + month = _str$split2[1], + year = _str$split2[2]; + + return new Date(year, month - 1, day); + } + }; + MaskedDate.GET_DEFAULT_GROUPS = function () { + return { + d: new PatternGroup.Range([1, 31]), + m: new PatternGroup.Range([1, 12]), + Y: new PatternGroup.Range([1900, 9999]) + }; + }; + + /** + Generic element API to use with mask + @interface + */ + var MaskElement = function () { + function MaskElement() { + classCallCheck(this, MaskElement); + } + + createClass(MaskElement, [{ + key: 'select', + value: function select(start, end) { + if (start == null || end == null || start === this.selectionStart && end === this.selectionEnd) return; + + try { + this._unsafeSelect(start, end); + } catch (e) {} + } + }, { + key: '_unsafeSelect', + value: function _unsafeSelect(start, end) {} + }, { + key: 'isActive', + value: function isActive() { + return false; + } + }, { + key: 'bindEvents', + value: function bindEvents(handlers) {} + }, { + key: 'unbindEvents', + value: function unbindEvents() {} + }, { + key: 'selectionStart', + get: function get$$1() { + var start = void 0; + try { + start = this._unsafeSelectionStart; + } catch (e) {} + + return start != null ? start : this.value.length; + } + }, { + key: 'selectionEnd', + get: function get$$1() { + var end = void 0; + try { + end = this._unsafeSelectionEnd; + } catch (e) {} + + return end != null ? end : this.value.length; + } + }]); + return MaskElement; + }(); + + var HTMLMaskElement = function (_MaskElement) { + inherits(HTMLMaskElement, _MaskElement); + + function HTMLMaskElement(input) { + classCallCheck(this, HTMLMaskElement); + + var _this = possibleConstructorReturn(this, (HTMLMaskElement.__proto__ || Object.getPrototypeOf(HTMLMaskElement)).call(this)); + + _this.input = input; + _this._handlers = {}; + return _this; + } + + createClass(HTMLMaskElement, [{ + key: 'isActive', + value: function isActive() { + return this.input === document.activeElement; + } + }, { + key: '_unsafeSelect', + value: function _unsafeSelect(start, end) { + this.input.setSelectionRange(start, end); + } + }, { + key: 'bindEvents', + value: function bindEvents(handlers) { + var _this2 = this; + + Object.keys(handlers).forEach(function (event) { + return _this2._toggleEventHandler(HTMLMaskElement.EVENTS_MAP[event], handlers[event]); + }); + } + }, { + key: 'unbindEvents', + value: function unbindEvents() { + var _this3 = this; + + Object.keys(this._handlers).forEach(function (event) { + return _this3._toggleEventHandler(event); + }); + } + }, { + key: '_toggleEventHandler', + value: function _toggleEventHandler(event, handler) { + if (this._handlers[event]) { + this.input.removeEventListener(event, this._handlers[event]); + delete this._handlers[event]; + } + + if (handler) { + this.input.addEventListener(event, handler); + this._handlers[event] = handler; + } + } + }, { + key: '_unsafeSelectionStart', + get: function get$$1() { + return this.input.selectionStart; + } + }, { + key: '_unsafeSelectionEnd', + get: function get$$1() { + return this.input.selectionEnd; + } + }, { + key: 'value', + get: function get$$1() { + return this.input.value; + }, + set: function set$$1(value) { + this.input.value = value; + } + }]); + return HTMLMaskElement; + }(MaskElement); + + HTMLMaskElement.EVENTS_MAP = { + selectionChange: 'keydown', + input: 'input', + drop: 'drop', + click: 'click', + focus: 'focus', + commit: 'change' + }; + + /** Listens to element events and controls changes between element and {@link Masked} */ + + var InputMask = function () { + + /** + @param {MaskElement|HTMLInputElement|HTMLTextAreaElement} el + @param {Object} opts + */ + + /** + View element + @readonly + */ + function InputMask(el, opts) { + classCallCheck(this, InputMask); + + this.el = el instanceof MaskElement ? el : new HTMLMaskElement(el); + this.masked = createMask(opts); + + this._listeners = {}; + this._value = ''; + this._unmaskedValue = ''; + + this._saveSelection = this._saveSelection.bind(this); + this._onInput = this._onInput.bind(this); + this._onChange = this._onChange.bind(this); + this._onDrop = this._onDrop.bind(this); + this.alignCursor = this.alignCursor.bind(this); + this.alignCursorFriendly = this.alignCursorFriendly.bind(this); + + this._bindEvents(); + + // refresh + this.updateValue(); + this._onChange(); + } + + /** Read or update mask */ + + + /** + Internal {@link Masked} model + @readonly + */ + + + createClass(InputMask, [{ + key: '_bindEvents', + + + /** + Starts listening to element events + @protected + */ + value: function _bindEvents() { + this.el.bindEvents({ + selectionChange: this._saveSelection, + input: this._onInput, + drop: this._onDrop, + click: this.alignCursorFriendly, + focus: this.alignCursorFriendly, + commit: this._onChange + }); + } + + /** + Stops listening to element events + @protected + */ + + }, { + key: '_unbindEvents', + value: function _unbindEvents() { + this.el.unbindEvents(); + } + + /** + Fires custom event + @protected + */ + + }, { + key: '_fireEvent', + value: function _fireEvent(ev) { + var listeners = this._listeners[ev]; + if (!listeners) return; + + listeners.forEach(function (l) { + return l(); + }); + } + + /** + Current selection start + @readonly + */ + + }, { + key: '_saveSelection', + + + /** + Stores current selection + @protected + */ + value: function _saveSelection() /* ev */{ + if (this.value !== this.el.value) { + console.warn('Uncontrolled input change, refresh mask manually!'); // eslint-disable-line no-console + } + this._selection = { + start: this.selectionStart, + end: this.cursorPos + }; + } + + /** Syncronizes model value from view */ + + }, { + key: 'updateValue', + value: function updateValue() { + this.masked.value = this.el.value; + } + + /** Syncronizes view from model value, fires change events */ + + }, { + key: 'updateControl', + value: function updateControl() { + var newUnmaskedValue = this.masked.unmaskedValue; + var newValue = this.masked.value; + var isChanged = this.unmaskedValue !== newUnmaskedValue || this.value !== newValue; + + this._unmaskedValue = newUnmaskedValue; + this._value = newValue; + + if (this.el.value !== newValue) this.el.value = newValue; + if (isChanged) this._fireChangeEvents(); + } + + /** Updates options with deep equal check, recreates @{link Masked} model if mask type changes */ + + }, { + key: 'updateOptions', + value: function updateOptions(opts) { + opts = _extends({}, opts); + + this.mask = opts.mask; + delete opts.mask; + + // check if changed + if (objectIncludes(this.masked, opts)) return; + + this.masked.updateOptions(opts); + this.updateControl(); + } + + /** Updates cursor */ + + }, { + key: 'updateCursor', + value: function updateCursor(cursorPos) { + if (cursorPos == null) return; + this.cursorPos = cursorPos; + + // also queue change cursor for mobile browsers + this._delayUpdateCursor(cursorPos); + } + + /** + Delays cursor update to support mobile browsers + @private + */ + + }, { + key: '_delayUpdateCursor', + value: function _delayUpdateCursor(cursorPos) { + var _this = this; + + this._abortUpdateCursor(); + this._changingCursorPos = cursorPos; + this._cursorChanging = setTimeout(function () { + if (!_this.el) return; // if was destroyed + _this.cursorPos = _this._changingCursorPos; + _this._abortUpdateCursor(); + }, 10); + } + + /** + Fires custom events + @protected + */ + + }, { + key: '_fireChangeEvents', + value: function _fireChangeEvents() { + this._fireEvent('accept'); + if (this.masked.isComplete) this._fireEvent('complete'); + } + + /** + Aborts delayed cursor update + @private + */ + + }, { + key: '_abortUpdateCursor', + value: function _abortUpdateCursor() { + if (this._cursorChanging) { + clearTimeout(this._cursorChanging); + delete this._cursorChanging; + } + } + + /** Aligns cursor to nearest available position */ + + }, { + key: 'alignCursor', + value: function alignCursor() { + this.cursorPos = this.masked.nearestInputPos(this.cursorPos, DIRECTION.LEFT); + } + + /** Aligns cursor only if selection is empty */ + + }, { + key: 'alignCursorFriendly', + value: function alignCursorFriendly() { + if (this.selectionStart !== this.cursorPos) return; + this.alignCursor(); + } + + /** Adds listener on custom event */ + + }, { + key: 'on', + value: function on(ev, handler) { + if (!this._listeners[ev]) this._listeners[ev] = []; + this._listeners[ev].push(handler); + return this; + } + + /** Removes custom event listener */ + + }, { + key: 'off', + value: function off(ev, handler) { + if (!this._listeners[ev]) return; + if (!handler) { + delete this._listeners[ev]; + return; + } + var hIndex = this._listeners[ev].indexOf(handler); + if (hIndex >= 0) this._listeners[ev].splice(hIndex, 1); + return this; + } + + /** Handles view input event */ + + }, { + key: '_onInput', + value: function _onInput() { + this._abortUpdateCursor(); + + // fix strange IE behavior + if (!this._selection) return this.updateValue(); + + var details = new ActionDetails( + // new state + this.el.value, this.cursorPos, + // old state + this.value, this._selection); + + var offset = this.masked.splice(details.startChangePos, details.removed.length, details.inserted, details.removeDirection).offset; + + var cursorPos = this.masked.nearestInputPos(details.startChangePos + offset, details.removeDirection); + + this.updateControl(); + this.updateCursor(cursorPos); + } + + /** Handles view change event and commits model value */ + + }, { + key: '_onChange', + value: function _onChange() { + if (this.value !== this.el.value) { + this.updateValue(); + } + this.masked.doCommit(); + this.updateControl(); + } + + /** Handles view drop event, prevents by default */ + + }, { + key: '_onDrop', + value: function _onDrop(ev) { + ev.preventDefault(); + ev.stopPropagation(); + } + + /** Unbind view events and removes element reference */ + + }, { + key: 'destroy', + value: function destroy() { + this._unbindEvents(); + // $FlowFixMe why not do so? + this._listeners.length = 0; + delete this.el; + } + }, { + key: 'mask', + get: function get$$1() { + return this.masked.mask; + }, + set: function set$$1(mask) { + if (mask == null || mask === this.masked.mask || mask === Date && this.masked instanceof MaskedDate) return; + + if (this.masked.constructor === maskedClass(mask)) { + this.masked.mask = mask; + return; + } + + var masked = createMask({ mask: mask }); + masked.unmaskedValue = this.masked.unmaskedValue; + this.masked = masked; + } + + /** Raw value */ + + }, { + key: 'value', + get: function get$$1() { + return this._value; + }, + set: function set$$1(str) { + this.masked.value = str; + this.updateControl(); + this.alignCursor(); + } + + /** Unmasked value */ + + }, { + key: 'unmaskedValue', + get: function get$$1() { + return this._unmaskedValue; + }, + set: function set$$1(str) { + this.masked.unmaskedValue = str; + this.updateControl(); + this.alignCursor(); + } + + /** Typed unmasked value */ + + }, { + key: 'typedValue', + get: function get$$1() { + return this.masked.typedValue; + }, + set: function set$$1(val) { + this.masked.typedValue = val; + this.updateControl(); + this.alignCursor(); + } + }, { + key: 'selectionStart', + get: function get$$1() { + return this._cursorChanging ? this._changingCursorPos : this.el.selectionStart; + } + + /** Current cursor position */ + + }, { + key: 'cursorPos', + get: function get$$1() { + return this._cursorChanging ? this._changingCursorPos : this.el.selectionEnd; + }, + set: function set$$1(pos) { + if (!this.el.isActive) return; + + this.el.select(pos, pos); + this._saveSelection(); + } + }]); + return InputMask; + }(); + + /** + Number mask + @param {Object} opts + @param {string} opts.radix - Single char + @param {string} opts.thousandsSeparator - Single char + @param {Array} opts.mapToRadix - Array of single chars + @param {number} opts.min + @param {number} opts.max + @param {number} opts.scale - Digits after point + @param {boolean} opts.signed - Allow negative + @param {boolean} opts.normalizeZeros - Flag to remove leading and trailing zeros in the end of editing + @param {boolean} opts.padFractionalZeros - Flag to pad trailing zeros after point in the end of editing + */ + var MaskedNumber = function (_Masked) { + inherits(MaskedNumber, _Masked); + + /** Flag to remove leading and trailing zeros in the end of editing */ + + /** Digits after point */ + + /** */ + + /** Single char */ + function MaskedNumber(opts) { + classCallCheck(this, MaskedNumber); + return possibleConstructorReturn(this, (MaskedNumber.__proto__ || Object.getPrototypeOf(MaskedNumber)).call(this, _extends({}, MaskedNumber.DEFAULTS, opts))); + } + + /** + @override + */ + + /** Flag to pad trailing zeros after point in the end of editing */ + + /** */ + + /** */ + + /** Array of single chars */ + + + /** Single char */ + + + createClass(MaskedNumber, [{ + key: '_update', + value: function _update(opts) { + get(MaskedNumber.prototype.__proto__ || Object.getPrototypeOf(MaskedNumber.prototype), '_update', this).call(this, opts); + this._updateRegExps(); + } + + /** */ + + }, { + key: '_updateRegExps', + value: function _updateRegExps() { + // use different regexp to process user input (more strict, input suffix) and tail shifting + var start = '^'; + + var midInput = ''; + var mid = ''; + if (this.allowNegative) { + midInput += '([+|\\-]?|([+|\\-]?(0|([1-9]+\\d*))))'; + mid += '[+|\\-]?'; + } else { + midInput += '(0|([1-9]+\\d*))'; + } + mid += '\\d*'; + + var end = (this.scale ? '(' + this.radix + '\\d{0,' + this.scale + '})?' : '') + '$'; + + this._numberRegExpInput = new RegExp(start + midInput + end); + this._numberRegExp = new RegExp(start + mid + end); + this._mapToRadixRegExp = new RegExp('[' + this.mapToRadix.map(escapeRegExp).join('') + ']', 'g'); + this._thousandsSeparatorRegExp = new RegExp(escapeRegExp(this.thousandsSeparator), 'g'); + } + + /** + @override + */ + + }, { + key: '_extractTail', + value: function _extractTail() { + var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length; + + var tail = get(MaskedNumber.prototype.__proto__ || Object.getPrototypeOf(MaskedNumber.prototype), '_extractTail', this).call(this, fromPos, toPos); + + return _extends({}, tail, { + value: this._removeThousandsSeparators(tail.value) + }); + } + + /** */ + + }, { + key: '_removeThousandsSeparators', + value: function _removeThousandsSeparators(value) { + return value.replace(this._thousandsSeparatorRegExp, ''); + } + + /** */ + + }, { + key: '_insertThousandsSeparators', + value: function _insertThousandsSeparators(value) { + // https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript + var parts = value.split(this.radix); + parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.thousandsSeparator); + return parts.join(this.radix); + } + + /** + @override + */ + + }, { + key: 'doPrepare', + value: function doPrepare(str) { + var _babelHelpers$get; + + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + return (_babelHelpers$get = get(MaskedNumber.prototype.__proto__ || Object.getPrototypeOf(MaskedNumber.prototype), 'doPrepare', this)).call.apply(_babelHelpers$get, [this, this._removeThousandsSeparators(str.replace(this._mapToRadixRegExp, this.radix))].concat(toConsumableArray(args))); + } + + /** + @override + */ + + }, { + key: 'appendWithTail', + value: function appendWithTail() { + var _babelHelpers$get2; + + var previousValue = this.value; + this._value = this._removeThousandsSeparators(this.value); + var startChangePos = this.value.length; + + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + var appendDetails = (_babelHelpers$get2 = get(MaskedNumber.prototype.__proto__ || Object.getPrototypeOf(MaskedNumber.prototype), 'appendWithTail', this)).call.apply(_babelHelpers$get2, [this].concat(toConsumableArray(args))); + this._value = this._insertThousandsSeparators(this.value); + + // calculate offsets after insert separators + var beforeTailPos = startChangePos + appendDetails.inserted.length; + for (var pos = 0; pos <= beforeTailPos; ++pos) { + if (this.value[pos] === this.thousandsSeparator) { + if (pos < startChangePos || + // check high bound + // if separator is still there - consider it also + pos === startChangePos && previousValue[pos] === this.thousandsSeparator) { + ++startChangePos; + } + if (pos < beforeTailPos) ++beforeTailPos; + } + } + + // adjust details with separators + appendDetails.rawInserted = appendDetails.inserted; + appendDetails.inserted = this.value.slice(startChangePos, beforeTailPos); + appendDetails.shift += startChangePos - previousValue.length; + + return appendDetails; + } + + /** + @override + */ + + }, { + key: 'nearestInputPos', + value: function nearestInputPos(cursorPos, direction) { + if (!direction) return cursorPos; + + var nextPos = indexInDirection(cursorPos, direction); + if (this.value[nextPos] === this.thousandsSeparator) cursorPos += direction; + return cursorPos; + } + + /** + @override + */ + + }, { + key: 'doValidate', + value: function doValidate(flags) { + var regexp = flags.input ? this._numberRegExpInput : this._numberRegExp; + + // validate as string + var valid = regexp.test(this._removeThousandsSeparators(this.value)); + + if (valid) { + // validate as number + var number = this.number; + valid = valid && !isNaN(number) && ( + // check min bound for negative values + this.min == null || this.min >= 0 || this.min <= this.number) && ( + // check max bound for positive values + this.max == null || this.max <= 0 || this.number <= this.max); + } + + return valid && get(MaskedNumber.prototype.__proto__ || Object.getPrototypeOf(MaskedNumber.prototype), 'doValidate', this).call(this, flags); + } + + /** + @override + */ + + }, { + key: 'doCommit', + value: function doCommit() { + var number = this.number; + var validnum = number; + + // check bounds + if (this.min != null) validnum = Math.max(validnum, this.min); + if (this.max != null) validnum = Math.min(validnum, this.max); + + if (validnum !== number) this.unmaskedValue = String(validnum); + + var formatted = this.value; + + if (this.normalizeZeros) formatted = this._normalizeZeros(formatted); + if (this.padFractionalZeros) formatted = this._padFractionalZeros(formatted); + + this._value = this._insertThousandsSeparators(formatted); + get(MaskedNumber.prototype.__proto__ || Object.getPrototypeOf(MaskedNumber.prototype), 'doCommit', this).call(this); + } + + /** */ + + }, { + key: '_normalizeZeros', + value: function _normalizeZeros(value) { + var parts = this._removeThousandsSeparators(value).split(this.radix); + + // remove leading zeros + parts[0] = parts[0].replace(/^(\D*)(0*)(\d*)/, function (match, sign, zeros, num) { + return sign + num; + }); + // add leading zero + if (value.length && !/\d$/.test(parts[0])) parts[0] = parts[0] + '0'; + + if (parts.length > 1) { + parts[1] = parts[1].replace(/0*$/, ''); // remove trailing zeros + if (!parts[1].length) parts.length = 1; // remove fractional + } + + return this._insertThousandsSeparators(parts.join(this.radix)); + } + + /** */ + + }, { + key: '_padFractionalZeros', + value: function _padFractionalZeros(value) { + if (!value) return value; + + var parts = value.split(this.radix); + if (parts.length < 2) parts.push(''); + parts[1] = parts[1].padEnd(this.scale, '0'); + return parts.join(this.radix); + } + + /** + @override + */ + + }, { + key: 'unmaskedValue', + get: function get$$1() { + return this._removeThousandsSeparators(this._normalizeZeros(this.value)).replace(this.radix, '.'); + }, + set: function set$$1(unmaskedValue) { + set(MaskedNumber.prototype.__proto__ || Object.getPrototypeOf(MaskedNumber.prototype), 'unmaskedValue', unmaskedValue.replace('.', this.radix), this); + } + + /** Parsed Number */ + + }, { + key: 'number', + get: function get$$1() { + return Number(this.unmaskedValue); + }, + set: function set$$1(number) { + this.unmaskedValue = String(number); + } + + /** + @override + */ + + }, { + key: 'typedValue', + get: function get$$1() { + return this.number; + }, + set: function set$$1(value) { + this.number = value; + } + + /** + Is negative allowed + @readonly + */ + + }, { + key: 'allowNegative', + get: function get$$1() { + return this.signed || this.min != null && this.min < 0 || this.max != null && this.max < 0; + } + }]); + return MaskedNumber; + }(Masked); + + MaskedNumber.DEFAULTS = { + radix: ',', + thousandsSeparator: '', + mapToRadix: ['.'], + scale: 2, + signed: false, + normalizeZeros: true, + padFractionalZeros: false + }; + + /** Masking by RegExp */ + + var MaskedRegExp = function (_Masked) { + inherits(MaskedRegExp, _Masked); + + function MaskedRegExp() { + classCallCheck(this, MaskedRegExp); + return possibleConstructorReturn(this, (MaskedRegExp.__proto__ || Object.getPrototypeOf(MaskedRegExp)).apply(this, arguments)); + } + + createClass(MaskedRegExp, [{ + key: '_update', + + /** + @override + @param {Object} opts + */ + value: function _update(opts) { + opts.validate = function (value) { + return value.search(opts.mask) >= 0; + }; + get(MaskedRegExp.prototype.__proto__ || Object.getPrototypeOf(MaskedRegExp.prototype), '_update', this).call(this, opts); + } + }]); + return MaskedRegExp; + }(Masked); + + /** Masking by custom Function */ + + var MaskedFunction = function (_Masked) { + inherits(MaskedFunction, _Masked); + + function MaskedFunction() { + classCallCheck(this, MaskedFunction); + return possibleConstructorReturn(this, (MaskedFunction.__proto__ || Object.getPrototypeOf(MaskedFunction)).apply(this, arguments)); + } + + createClass(MaskedFunction, [{ + key: '_update', + + /** + @override + @param {Object} opts + */ + value: function _update(opts) { + opts.validate = opts.mask; + get(MaskedFunction.prototype.__proto__ || Object.getPrototypeOf(MaskedFunction.prototype), '_update', this).call(this, opts); + } + }]); + return MaskedFunction; + }(Masked); + + /** Dynamic mask for choosing apropriate mask in run-time */ + var MaskedDynamic = function (_Masked) { + inherits(MaskedDynamic, _Masked); + + /** + @param {Object} opts + */ + + /** Compliled {@link Masked} options */ + function MaskedDynamic(opts) { + classCallCheck(this, MaskedDynamic); + + var _this = possibleConstructorReturn(this, (MaskedDynamic.__proto__ || Object.getPrototypeOf(MaskedDynamic)).call(this, _extends({}, MaskedDynamic.DEFAULTS, opts))); + + _this.currentMask = null; + return _this; + } + + /** + @override + */ + + /** Chooses {@link Masked} depending on input value */ + + /** Currently chosen mask */ + + + createClass(MaskedDynamic, [{ + key: '_update', + value: function _update(opts) { + get(MaskedDynamic.prototype.__proto__ || Object.getPrototypeOf(MaskedDynamic.prototype), '_update', this).call(this, opts); + // mask could be totally dynamic with only `dispatch` option + this.compiledMasks = Array.isArray(opts.mask) ? opts.mask.map(function (m) { + return createMask(m); + }) : []; + } + + /** + @override + */ + + }, { + key: '_append', + value: function _append(str) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + str = this.doPrepare.apply(this, [str].concat(toConsumableArray(args))); + + var details = this._applyDispatch.apply(this, [str].concat(toConsumableArray(args))); + + if (this.currentMask) { + var _currentMask; + + details.aggregate((_currentMask = this.currentMask)._append.apply(_currentMask, [str].concat(toConsumableArray(args)))); + } + + return details; + } + }, { + key: '_applyDispatch', + value: function _applyDispatch() { + var appended = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + + var oldValueLength = this.value.length; + var inputValue = this.rawInputValue; + var oldMask = this.currentMask; + var details = new ChangeDetails(); + + // dispatch SHOULD NOT modify mask + + for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } + + this.currentMask = this.doDispatch.apply(this, [appended].concat(toConsumableArray(args))); + + // restore state after dispatch + if (this.currentMask && this.currentMask !== oldMask) { + // if mask changed reapply input + this.currentMask.reset(); + // $FlowFixMe - it's ok, we don't change current mask + this.currentMask._append(inputValue, { raw: true }); + details.shift = this.value.length - oldValueLength; + } + + return details; + } + + /** + @override + */ + + }, { + key: 'doDispatch', + value: function doDispatch(appended) { + var flags = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + return this.dispatch(appended, this, flags); + } + + /** + @override + */ + + }, { + key: 'clone', + value: function clone() { + var m = new MaskedDynamic(this); + m._value = this.value; + + // try to keep reference to compiled masks + var currentMaskIndex = this.compiledMasks.indexOf(this.currentMask); + if (this.currentMask) { + m.currentMask = currentMaskIndex >= 0 ? m.compiledMasks[currentMaskIndex].assign(this.currentMask) : this.currentMask.clone(); + } + + return m; + } + + /** + @override + */ + + }, { + key: 'reset', + value: function reset() { + if (this.currentMask) this.currentMask.reset(); + this.compiledMasks.forEach(function (cm) { + return cm.reset(); + }); + } + + /** + @override + */ + + }, { + key: 'remove', + + + /** + @override + */ + value: function remove() { + var details = new ChangeDetails(); + if (this.currentMask) { + var _currentMask2; + + details.aggregate((_currentMask2 = this.currentMask).remove.apply(_currentMask2, arguments)) + // update with dispatch + .aggregate(this._applyDispatch()); + } + + return details; + } + + /** + @override + */ + + }, { + key: 'extractInput', + value: function extractInput() { + var _currentMask3; + + return this.currentMask ? (_currentMask3 = this.currentMask).extractInput.apply(_currentMask3, arguments) : ''; + } + + /** + @override + */ + + }, { + key: '_extractTail', + value: function _extractTail() { + var _currentMask4, _babelHelpers$get; + + for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args[_key3] = arguments[_key3]; + } + + return this.currentMask ? (_currentMask4 = this.currentMask)._extractTail.apply(_currentMask4, toConsumableArray(args)) : (_babelHelpers$get = get(MaskedDynamic.prototype.__proto__ || Object.getPrototypeOf(MaskedDynamic.prototype), '_extractTail', this)).call.apply(_babelHelpers$get, [this].concat(toConsumableArray(args))); + } + + /** + @override + */ + + }, { + key: '_appendTail', + value: function _appendTail(tail) { + var details = new ChangeDetails(); + if (tail) details.aggregate(this._applyDispatch(tail.value)); + + return details.aggregate(this.currentMask ? this.currentMask._appendTail(tail) : get(MaskedDynamic.prototype.__proto__ || Object.getPrototypeOf(MaskedDynamic.prototype), '_appendTail', this).call(this, tail)); + } + + /** + @override + */ + + }, { + key: 'doCommit', + value: function doCommit() { + if (this.currentMask) this.currentMask.doCommit(); + get(MaskedDynamic.prototype.__proto__ || Object.getPrototypeOf(MaskedDynamic.prototype), 'doCommit', this).call(this); + } + + /** + @override + */ + + }, { + key: 'nearestInputPos', + value: function nearestInputPos() { + var _currentMask5, _babelHelpers$get2; + + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + return this.currentMask ? (_currentMask5 = this.currentMask).nearestInputPos.apply(_currentMask5, toConsumableArray(args)) : (_babelHelpers$get2 = get(MaskedDynamic.prototype.__proto__ || Object.getPrototypeOf(MaskedDynamic.prototype), 'nearestInputPos', this)).call.apply(_babelHelpers$get2, [this].concat(toConsumableArray(args))); + } + }, { + key: 'value', + get: function get$$1() { + return this.currentMask ? this.currentMask.value : ''; + }, + set: function set$$1(value) { + set(MaskedDynamic.prototype.__proto__ || Object.getPrototypeOf(MaskedDynamic.prototype), 'value', value, this); + } + + /** + @override + */ + + }, { + key: 'unmaskedValue', + get: function get$$1() { + return this.currentMask ? this.currentMask.unmaskedValue : ''; + }, + set: function set$$1(unmaskedValue) { + set(MaskedDynamic.prototype.__proto__ || Object.getPrototypeOf(MaskedDynamic.prototype), 'unmaskedValue', unmaskedValue, this); + } + + /** + @override + */ + + }, { + key: 'typedValue', + get: function get$$1() { + return this.currentMask ? this.currentMask.typedValue : ''; + }, + set: function set$$1(value) { + var unmaskedValue = String(value); + if (this.currentMask) { + this.currentMask.typedValue = value; + unmaskedValue = this.currentMask.unmaskedValue; + } + this.unmaskedValue = unmaskedValue; + } + + /** + @override + */ + + }, { + key: 'isComplete', + get: function get$$1() { + return !!this.currentMask && this.currentMask.isComplete; + } + }]); + return MaskedDynamic; + }(Masked); + + + MaskedDynamic.DEFAULTS = { + dispatch: function dispatch(appended, masked, flags) { + if (!masked.compiledMasks.length) return; + + var inputValue = masked.rawInputValue; + + // simulate input + var inputs = masked.compiledMasks.map(function (cm, index) { + var m = cm.clone(); + m.rawInputValue = inputValue; + m._append(appended, flags); + + return { value: m.rawInputValue.length, index: index }; + }); + + // pop masks with longer values first + inputs.sort(function (i1, i2) { + return i2.value - i1.value; + }); + + return masked.compiledMasks[inputs[0].index]; + } + }; + + /** + * Applies mask on element. + * @constructor + * @param {HTMLInputElement|HTMLTextAreaElement|MaskElement} el - Element to apply mask + * @param {Object} opts - Custom mask options + * @return {InputMask} + */ + function VindiCCMask(el) { + var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + // currently available only for input-like elements + return new InputMask(el, opts); + } + + /** {@link InputMask} */ + VindiCCMask.InputMask = InputMask; + + /** {@link Masked} */ + VindiCCMask.Masked = Masked; + /** {@link MaskedPattern} */ + VindiCCMask.MaskedPattern = MaskedPattern; + /** {@link MaskedNumber} */ + VindiCCMask.MaskedNumber = MaskedNumber; + /** {@link MaskedDate} */ + VindiCCMask.MaskedDate = MaskedDate; + /** {@link MaskedRegExp} */ + VindiCCMask.MaskedRegExp = MaskedRegExp; + /** {@link MaskedFunction} */ + VindiCCMask.MaskedFunction = MaskedFunction; + /** {@link MaskedDynamic} */ + VindiCCMask.MaskedDynamic = MaskedDynamic; + /** {@link createMask} */ + VindiCCMask.createMask = createMask; + /** {@link MaskElement} */ + VindiCCMask.MaskElement = MaskElement; + /** {@link HTMLMaskElement} */ + VindiCCMask.HTMLMaskElement = HTMLMaskElement; + + g.VindiCCMask = VindiCCMask; + + return VindiCCMask; + +}))); diff --git a/view/frontend/web/js/view/payment/method-renderer/cc.js b/view/frontend/web/js/view/payment/method-renderer/cc.js index 78873af..6236f7c 100644 --- a/view/frontend/web/js/view/payment/method-renderer/cc.js +++ b/view/frontend/web/js/view/payment/method-renderer/cc.js @@ -31,11 +31,12 @@ define( 'Vindi_VP/js/model/credit-card-validation/credit-card-number-validator', 'Magento_Payment/js/model/credit-card-validation/credit-card-data', 'Vindi_VP/js/fingerprint', + 'vindi-cc-form', 'Magento_Payment/js/model/credit-card-validation/validator', 'Magento_Checkout/js/model/payment/additional-validators', 'mage/mage', 'mage/validation', - 'vindi_vp/validation' + 'vindi_vp/validation', ], function ( _, @@ -48,7 +49,8 @@ define( Component, cardNumberValidator, creditCardData, - fingerprint + fingerprint, + creditCardForm ) { 'use strict'; @@ -75,6 +77,7 @@ define( .observe([ 'taxvat', 'creditCardType', + 'creditCardExpDate', 'creditCardExpYear', 'creditCardExpMonth', 'vindiCreditCardNumber', @@ -126,9 +129,22 @@ define( self.updateInstallmentsValues(); }); + return this; }, + loadCard: function () { + let ccName = document.getElementById(this.getCode() + '_cc_owner'); + let ccNumber = document.getElementById(this.getCode() + '_cc_number'); + let ccExpDate = document.getElementById(this.getCode() + '_cc_exp_date'); + let ccCvv = document.getElementById(this.getCode() + '_cc_cid'); + let ccSingle = document.getElementById('vindi-vp-cc-ccsingle'); + let ccFront = document.getElementById('vindi-vp-cc-front'); + let ccBack = document.getElementById('vindi-vp-cc-back'); + + creditCardForm(ccName, ccNumber, ccExpDate, ccCvv, ccSingle, ccFront, ccBack); + }, + getCode: function () { return this.item.method; }, @@ -138,15 +154,25 @@ define( * @returns {Object} */ getData: function () { + fingerprint(window.checkoutConfig.payment[this.getCode()].sandbox); + let ccExpMonth = ''; + let ccExpYear = ''; + let ccExpDate = this.creditCardExpDate(); + + if (typeof ccExpDate !== "undefined" && ccExpDate !== null) { + let ccExpDateFull = ccExpDate.split('/'); + ccExpMonth = ccExpDateFull[0]; + ccExpYear = '20' + ccExpDateFull[1]; + } return { 'method': this.item.method, 'additional_data': { 'taxvat': this.taxvat(), 'cc_cid': this.creditCardVerificationNumber(), 'cc_type': this.creditCardType(), - 'cc_exp_year': this.creditCardExpYear(), - 'cc_exp_month': this.creditCardExpMonth(), + 'cc_exp_month': ccExpMonth, + 'cc_exp_year': '20' + ccExpYear, 'cc_number': this.vindiCreditCardNumber(), 'cc_owner': this.creditCardOwner(), 'installments': this.creditCardInstallments(), diff --git a/view/frontend/web/template/payment/form/cc.html b/view/frontend/web/template/payment/form/cc.html index 475d5b4..f5f91d5 100644 --- a/view/frontend/web/template/payment/form/cc.html +++ b/view/frontend/web/template/payment/form/cc.html @@ -33,14 +33,14 @@
-
+

-
+
    @@ -61,23 +61,21 @@
-
- +
- -
-
-
-
- -
-
-
-
- -
-
-
-
-
- -
- -
+ +
+ + + + -
- - - -
-
+ id: getCode() + '_cc_cid', + title: $t('Card Verification Number'), + placeholder: $t('CVV'), + maxlength: 4, + 'data-container': getCode() + '-cc-cvv', + 'data-validate': JSON.stringify({'required-number':true, 'validate-number':'#' + getCode() + '_cc_type'}) + }, + enable: isActive($parents), + value: creditCardVerificationNumber" /> +
+
+ +
+
+
-
-
+
+
+
+
+
+
@@ -248,6 +207,7 @@
+
@@ -264,3 +224,4 @@
+ From 4b3752a5dbb3cc729cc6580c7d6d45cd07a39ae7 Mon Sep 17 00:00:00 2001 From: Thiago Contardi Date: Thu, 15 Feb 2024 21:14:32 +0000 Subject: [PATCH 02/50] feat: added setup for old settings and minor bugfixes --- Setup/Patch/Data/ImportSettings.php | 81 ++++++++++++++++++++++++++ composer.json | 2 +- etc/adminhtml/system/bank_slip.xml | 8 ++- etc/adminhtml/system/bank_slip_pix.xml | 8 ++- etc/adminhtml/system/credit_card.xml | 14 +++++ etc/adminhtml/system/general.xml | 22 +++---- etc/adminhtml/system/pix.xml | 16 ++--- etc/config.xml | 8 +-- etc/module.xml | 2 +- i18n/en_US.csv | 6 +- i18n/pt_BR.csv | 6 +- 11 files changed, 134 insertions(+), 39 deletions(-) create mode 100644 Setup/Patch/Data/ImportSettings.php diff --git a/Setup/Patch/Data/ImportSettings.php b/Setup/Patch/Data/ImportSettings.php new file mode 100644 index 0000000..2a666d3 --- /dev/null +++ b/Setup/Patch/Data/ImportSettings.php @@ -0,0 +1,81 @@ +moduleDataSetup = $moduleDataSetup; + $this->configResource = $configResource; + $this->configWriter = $configWriter; + $this->logger = $logger; + } + + public function apply() + { + try { + $this->moduleDataSetup->startSetup(); + + $configMapping = [ + 'payment/yapay_configuration/environment_configuration_yapay' => 'vindi_vp/general/use_sandbox', + 'payment/yapay_configuration/token_configuration_yapay' => 'vindi_vp/general/token', + 'payment/yapay_configuration/email_configuration_yapay' => 'vindi_vp/general/email' + ]; + + foreach ($configMapping as $oldPath => $newPath) { + if (!$this->configResource->getValue($newPath)) { + $oldValue = $this->configResource->getValue($oldPath); + $this->configWriter->save($newPath, $oldValue); + } + } + + $this->moduleDataSetup->endSetup(); + } catch (\Exception $e) { + $this->logger->critical($e); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + public function getAliases() + { + return []; + } +} diff --git a/composer.json b/composer.json index dcdbd06..36e066e 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "vindi/magento2-payments", "description": "Vindi VP Payment Method for Magento 2.3+", "type": "magento2-module", - "version": "1.0.0", + "version": "1.0.1", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/etc/adminhtml/system/bank_slip.xml b/etc/adminhtml/system/bank_slip.xml index 7f4f0fa..16369c3 100755 --- a/etc/adminhtml/system/bank_slip.xml +++ b/etc/adminhtml/system/bank_slip.xml @@ -85,14 +85,16 @@ payment/vindi_vp_bankslip/min_order_total - + validate-number validate-zero-or-greater + Only orders with an amount higher than this will show this method - + payment/vindi_vp_bankslip/max_order_total - + validate-number validate-zero-or-greater + Only orders with an amount lower than this will show this method diff --git a/etc/adminhtml/system/bank_slip_pix.xml b/etc/adminhtml/system/bank_slip_pix.xml index 5ae2dff..be6a412 100755 --- a/etc/adminhtml/system/bank_slip_pix.xml +++ b/etc/adminhtml/system/bank_slip_pix.xml @@ -85,14 +85,16 @@ payment/vindi_vp_bankslippix/min_order_total - + validate-number validate-zero-or-greater + Only orders with an amount higher than this will show this method - + payment/vindi_vp_bankslippix/max_order_total - + validate-number validate-zero-or-greater + Only orders with an amount lower than this will show this method diff --git a/etc/adminhtml/system/credit_card.xml b/etc/adminhtml/system/credit_card.xml index 1786cc6..f9b2356 100755 --- a/etc/adminhtml/system/credit_card.xml +++ b/etc/adminhtml/system/credit_card.xml @@ -75,5 +75,19 @@ + + payment/vindi_vp_cc/min_order_total + + validate-number validate-zero-or-greater + Only orders with an amount higher than this will show this method + + + + payment/vindi_vp_cc/max_order_total + + validate-number validate-zero-or-greater + Only orders with an amount lower than this will show this method + + diff --git a/etc/adminhtml/system/general.xml b/etc/adminhtml/system/general.xml index b2c3885..b5c6e6c 100755 --- a/etc/adminhtml/system/general.xml +++ b/etc/adminhtml/system/general.xml @@ -41,18 +41,18 @@ - - - Magento\Config\Model\Config\Source\Yesno - vindi_vp/general/refund_on_cancel - + + + + + - - - Magento\Config\Model\Config\Source\Yesno - payment/general/cancel_unapproved_orders - - + + + + + + diff --git a/etc/adminhtml/system/pix.xml b/etc/adminhtml/system/pix.xml index c66196c..755c0d7 100644 --- a/etc/adminhtml/system/pix.xml +++ b/etc/adminhtml/system/pix.xml @@ -35,12 +35,6 @@ - - - payment/vindi_vp_pix/expiration_time - - - Magento\Sales\Model\Config\Source\Order\Status\Newprocessing @@ -92,16 +86,18 @@ - + payment/vindi_vp_pix/min_order_total - + validate-number validate-zero-or-greater + Only orders with an amount higher than this will show this method - + payment/vindi_vp_pix/max_order_total - + validate-number validate-zero-or-greater + Only orders with an amount lower than this will show this method diff --git a/etc/config.xml b/etc/config.xml index 2d3a9b2..f3cc1b3 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -17,14 +17,10 @@ - 1 + 0 0 - 1 + 0 - - - adobe -
0 1 diff --git a/etc/module.xml b/etc/module.xml index 11e1f8c..38fb874 100755 --- a/etc/module.xml +++ b/etc/module.xml @@ -13,7 +13,7 @@ */ --> - + diff --git a/i18n/en_US.csv b/i18n/en_US.csv index 9eaefaa..6b01175 100644 --- a/i18n/en_US.csv +++ b/i18n/en_US.csv @@ -69,8 +69,10 @@ Title,Title "Sort Order","Sort Order" "Payment From Applicable Countries","Payment From Applicable Countries" "Payment From Specific Countries","Payment From Specific Countries" -"Minimum Order Total","Minimum Order Total" -"Maximum Order Total","Maximum Order Total" +"Minimum Order Total.","Minimum Order Total" +"Maximum Order Total.","Maximum Order Total" +"Only orders with an amount higher than this will show this method","Only orders with an amount higher than this will show this method" +"Only orders with an amount lower than this will show this method","Only orders with an amount lower than this will show this method" "Credit Card","Credit Card" "Auto Capture","Auto Capture" "Credit Card Types","Credit Card Types" diff --git a/i18n/pt_BR.csv b/i18n/pt_BR.csv index a5648a1..64cc9e3 100644 --- a/i18n/pt_BR.csv +++ b/i18n/pt_BR.csv @@ -63,8 +63,10 @@ Title,Título "Sort Order","Ordem de Exibição" "Payment From Applicable Countries","Pagamento de Países Aplicáveis" "Payment From Specific Countries","Pagamento de Países Específicos" -"Minimum Order Total","Total Mínimo do Pedido" -"Maximum Order Total","Total Máximo do Pedido" +"Minimum Order Total.","Valor Mínimo do Pedido" +"Maximum Order Total.","Valor Máximo do Pedido" +"Only orders with an amount higher than this will show this method","Somente pedidos com o valor maior que o informado mostrarão este método" +"Only orders with an amount lower than this will show this method","Somente pedidos com o valor menor que o informado mostrarão este método" "Credit Card","Cartão de Crédito" "Auto Capture","Captura Automática" "Credit Card Types","Tipos de Cartão de Crédito" From 7ea0433985f4222e70d6769e3273b44efe5ec82f Mon Sep 17 00:00:00 2001 From: Thiago Contardi Date: Fri, 16 Feb 2024 14:19:49 -0300 Subject: [PATCH 03/50] fix: error with 1i18n on setting's page --- etc/adminhtml/system/bank_slip.xml | 38 +++++++++++------------ etc/adminhtml/system/bank_slip_pix.xml | 38 +++++++++++------------ etc/adminhtml/system/credit_card.xml | 22 +++++++------- etc/adminhtml/system/general.xml | 20 ++++++------ etc/adminhtml/system/pix.xml | 42 +++++++++++++------------- 5 files changed, 80 insertions(+), 80 deletions(-) diff --git a/etc/adminhtml/system/bank_slip.xml b/etc/adminhtml/system/bank_slip.xml index 16369c3..e970c87 100755 --- a/etc/adminhtml/system/bank_slip.xml +++ b/etc/adminhtml/system/bank_slip.xml @@ -14,16 +14,16 @@ --> - + - + Magento\Config\Model\Config\Source\Yesno payment/vindi_vp_bankslip/active - + payment/vindi_vp_bankslip/title Title of the payment method to be shown on checkout's page @@ -35,46 +35,46 @@ - + Magento\Sales\Model\Config\Source\Order\Status\Newprocessing payment/vindi_vp_bankslip/order_status -