@kigi/components 1.62.5 → 1.62.7-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as angular from 'angular'
|
|
2
|
-
import { mbgInputCpfCnpj } from './mbg-input-cpfcnpj'
|
|
2
|
+
import { mbgInputCpfCnpj, mbgAlphanumericCnpjMask } from './mbg-input-cpfcnpj'
|
|
3
3
|
|
|
4
4
|
const mbgInputCpfCnpjModule = angular
|
|
5
5
|
.module('mbg.components.mbgInputCpfCnpj', [])
|
|
6
6
|
.component('mbgInputCpfCnpj', mbgInputCpfCnpj)
|
|
7
|
+
.directive('mbgAlphanumericCnpjMask', mbgAlphanumericCnpjMask)
|
|
7
8
|
.name
|
|
8
9
|
|
|
9
10
|
export { mbgInputCpfCnpjModule }
|
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
<div class="mbg-input-wrapper mb-input-cpfcnpj-wrapper"
|
|
2
2
|
ng-if="$ctrl.props"
|
|
3
3
|
mbg-autocomplete-off>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
4
|
+
<input type="text"
|
|
5
|
+
ng-if="$ctrl.allowAlphanumeric"
|
|
6
|
+
ng-model="$ctrl.ngModel"
|
|
7
|
+
name="{{$ctrl.name}}"
|
|
8
|
+
ng-change="$ctrl.onChange()"
|
|
9
|
+
placeholder="{{ $ctrl.props.placeholder }}"
|
|
10
|
+
ng-required="$ctrl.ngRequired"
|
|
11
|
+
ng-disabled="$ctrl.ngDisabled"
|
|
12
|
+
ng-blur="$ctrl.ngBlur({ $event })"
|
|
13
|
+
ng-focus="$ctrl.ngFocus({ $event })"
|
|
14
|
+
ng-keyup="$ctrl.ngKeyup({ $event })"
|
|
15
|
+
ng-keypress="$ctrl.ngKeypress({ $event })"
|
|
16
|
+
ng-keydown="$ctrl.ngKeydown({ $event })"
|
|
17
|
+
mbg-alphanumeric-cnpj-mask />
|
|
18
|
+
<input type="text"
|
|
19
|
+
ng-if="!$ctrl.allowAlphanumeric"
|
|
20
|
+
ng-model="$ctrl.ngModel"
|
|
21
|
+
name="{{$ctrl.name}}"
|
|
22
|
+
ng-change="$ctrl.onChange()"
|
|
23
|
+
placeholder="{{ $ctrl.props.placeholder }}"
|
|
24
|
+
ng-required="$ctrl.ngRequired"
|
|
25
|
+
ng-disabled="$ctrl.ngDisabled"
|
|
26
|
+
ng-blur="$ctrl.ngBlur({ $event })"
|
|
27
|
+
ng-focus="$ctrl.ngFocus({ $event })"
|
|
28
|
+
ng-keyup="$ctrl.ngKeyup({ $event })"
|
|
29
|
+
ng-keypress="$ctrl.ngKeypress({ $event })"
|
|
30
|
+
ng-keydown="$ctrl.ngKeydown({ $event })"
|
|
31
|
+
ui-br-cpfcnpj-mask />
|
|
32
|
+
</div>
|
|
@@ -1,99 +1,307 @@
|
|
|
1
1
|
import './mbg-input-cpfcnpj.scss'
|
|
2
2
|
import template from './mbg-input-cpfcnpj.html'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Mask formatting helpers
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
const CPF_MASK = '###.###.###-##'
|
|
9
|
+
const CNPJ_MASK = '##.###.###/####-##'
|
|
10
|
+
|
|
11
|
+
function cleanValue(value: string): string {
|
|
12
|
+
return (value || '').replace(/[^A-Za-z0-9]/g, '').toUpperCase()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function hasLetters(value: string): boolean {
|
|
16
|
+
return /[A-Za-z]/.test(value)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function formatCpf(clean: string): string {
|
|
20
|
+
const digits = clean.replace(/[^0-9]/g, '').substring(0, 11)
|
|
21
|
+
const result: string[] = []
|
|
22
|
+
let digitIdx = 0
|
|
23
|
+
|
|
24
|
+
for (let i = 0; i < CPF_MASK.length && digitIdx < digits.length; i++) {
|
|
25
|
+
if (CPF_MASK[i] === '#') {
|
|
26
|
+
result.push(digits[digitIdx])
|
|
27
|
+
digitIdx++
|
|
28
|
+
} else {
|
|
29
|
+
result.push(CPF_MASK[i])
|
|
18
30
|
}
|
|
31
|
+
}
|
|
19
32
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
return result.join('')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function formatCnpj(clean: string): string {
|
|
37
|
+
const safe = clean.substring(0, 14)
|
|
38
|
+
const result: string[] = []
|
|
39
|
+
let cleanIndex = 0
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < CNPJ_MASK.length && cleanIndex < safe.length; i++) {
|
|
42
|
+
const maskChar = CNPJ_MASK[i]
|
|
43
|
+
|
|
44
|
+
if (maskChar === '#') {
|
|
45
|
+
const char = safe[cleanIndex]
|
|
46
|
+
const isCheckDigitPosition = cleanIndex >= 12
|
|
47
|
+
|
|
48
|
+
if (isCheckDigitPosition) {
|
|
49
|
+
if (/[0-9]/.test(char)) {
|
|
50
|
+
result.push(char)
|
|
26
51
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
52
|
+
cleanIndex++
|
|
53
|
+
} else {
|
|
54
|
+
if (/[A-Z0-9]/.test(char)) {
|
|
55
|
+
result.push(char)
|
|
31
56
|
}
|
|
57
|
+
cleanIndex++
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
result.push(maskChar)
|
|
32
61
|
}
|
|
62
|
+
}
|
|
33
63
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
return result.join('')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function smartFormat(value: string): string {
|
|
68
|
+
const clean = normalizeForModel(value)
|
|
69
|
+
if (clean.length === 0) return ''
|
|
70
|
+
if (hasLetters(clean)) return formatCnpj(clean)
|
|
71
|
+
if (clean.length <= 11) return formatCpf(clean)
|
|
72
|
+
return formatCnpj(clean)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function normalizeForModel(value: string): string {
|
|
76
|
+
const clean = cleanValue(value)
|
|
77
|
+
if (!clean) return ''
|
|
78
|
+
if (hasLetters(clean)) return clean.substring(0, 14)
|
|
79
|
+
if (clean.length <= 11) return clean
|
|
80
|
+
return clean.substring(0, 14)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isRepeatedNumeric(value: string): boolean {
|
|
84
|
+
return /^(\d)\1+$/.test(value)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getDigitValue(char: string): number {
|
|
88
|
+
return char.charCodeAt(0) - 48
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function calculateCpfDigit(base: string, startWeight: number): number {
|
|
92
|
+
let sum = 0
|
|
93
|
+
|
|
94
|
+
for (let i = 0; i < base.length; i++) {
|
|
95
|
+
sum += Number(base[i]) * (startWeight - i)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const remainder = sum % 11
|
|
99
|
+
return remainder < 2 ? 0 : 11 - remainder
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isValidCpf(value: string): boolean {
|
|
103
|
+
if (!/^\d{11}$/.test(value) || isRepeatedNumeric(value)) return false
|
|
104
|
+
|
|
105
|
+
const firstDigit = calculateCpfDigit(value.slice(0, 9), 10)
|
|
106
|
+
const secondDigit = calculateCpfDigit(`${value.slice(0, 9)}${firstDigit}`, 11)
|
|
107
|
+
return value === `${value.slice(0, 9)}${firstDigit}${secondDigit}`
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function calculateCnpjDigit(base: string, weights: number[]): number {
|
|
111
|
+
let sum = 0
|
|
112
|
+
|
|
113
|
+
for (let i = 0; i < base.length; i++) {
|
|
114
|
+
sum += getDigitValue(base[i]) * weights[i]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const remainder = sum % 11
|
|
118
|
+
return remainder < 2 ? 0 : 11 - remainder
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function isValidCnpj(value: string): boolean {
|
|
122
|
+
if (!/^[A-Z0-9]{12}[0-9]{2}$/.test(value)) return false
|
|
123
|
+
if (/^\d{14}$/.test(value) && isRepeatedNumeric(value)) return false
|
|
124
|
+
|
|
125
|
+
const base = value.slice(0, 12)
|
|
126
|
+
const firstDigit = calculateCnpjDigit(base, [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2])
|
|
127
|
+
const secondDigit = calculateCnpjDigit(
|
|
128
|
+
`${base}${firstDigit}`,
|
|
129
|
+
[6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2],
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
return value.slice(12) === `${firstDigit}${secondDigit}`
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function isCpfCandidate(value: string): boolean {
|
|
136
|
+
return /^\d*$/.test(value) && value.length <= 11
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function isCnpjCandidate(value: string): boolean {
|
|
140
|
+
return value.length > 11 || hasLetters(value)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function isDocumentValid(value: string): boolean {
|
|
144
|
+
if (!value) return true
|
|
145
|
+
if (isCpfCandidate(value)) {
|
|
146
|
+
if (value.length < 11) return true
|
|
147
|
+
return isValidCpf(value)
|
|
148
|
+
}
|
|
149
|
+
if (isCnpjCandidate(value)) {
|
|
150
|
+
if (value.length < 14) return true
|
|
151
|
+
if (value.length > 14) return false
|
|
152
|
+
return isValidCnpj(value)
|
|
153
|
+
}
|
|
154
|
+
return false
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// Directive: mbg-alphanumeric-cnpj-mask
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
|
|
161
|
+
class MbgAlphanumericCnpjMaskDirective {
|
|
162
|
+
static $inject = []
|
|
163
|
+
|
|
164
|
+
require = 'ngModel'
|
|
165
|
+
restrict = 'A'
|
|
166
|
+
|
|
167
|
+
link = (_scope, _element, _attrs, ngModel) => {
|
|
168
|
+
ngModel.$parsers.push((viewValue: string) => {
|
|
169
|
+
const clean = normalizeForModel(viewValue || '')
|
|
170
|
+
const formatted = smartFormat(clean)
|
|
171
|
+
|
|
172
|
+
if ((viewValue || '') !== formatted) {
|
|
173
|
+
ngModel.$setViewValue(formatted)
|
|
174
|
+
ngModel.$render()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return clean
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
ngModel.$formatters.push((modelValue: string) => {
|
|
181
|
+
return smartFormat(modelValue || '')
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
ngModel.$validators.cpf = (modelValue: string) => {
|
|
185
|
+
const clean = normalizeForModel(modelValue || '')
|
|
186
|
+
if (!clean || !isCpfCandidate(clean)) return true
|
|
187
|
+
if (clean.length < 11) return true
|
|
188
|
+
return isValidCpf(clean)
|
|
51
189
|
}
|
|
52
190
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
} else {
|
|
60
|
-
return false
|
|
61
|
-
}
|
|
191
|
+
ngModel.$validators.cnpj = (modelValue: string) => {
|
|
192
|
+
const clean = normalizeForModel(modelValue || '')
|
|
193
|
+
if (!clean || !isCnpjCandidate(clean)) return true
|
|
194
|
+
if (clean.length < 14) return true
|
|
195
|
+
if (clean.length > 14) return false
|
|
196
|
+
return isValidCnpj(clean)
|
|
62
197
|
}
|
|
63
198
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
let firstCalc = this.CalcDigits(firstNumbers, 5)
|
|
68
|
-
let secondCalc = this.CalcDigits(firstCalc, 6)
|
|
69
|
-
if (secondCalc === original) {
|
|
70
|
-
return true
|
|
71
|
-
}
|
|
72
|
-
return false
|
|
199
|
+
ngModel.$validators.cpfcnpj = (modelValue: string) => {
|
|
200
|
+
const clean = normalizeForModel(modelValue || '')
|
|
201
|
+
return isDocumentValid(clean)
|
|
73
202
|
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
74
205
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
206
|
+
const mbgAlphanumericCnpjMask = () => new MbgAlphanumericCnpjMaskDirective()
|
|
207
|
+
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
// Component: mbg-input-cpfcnpj
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
|
|
212
|
+
class MbgInputCpfCnpjController {
|
|
213
|
+
private ngChange
|
|
214
|
+
private ngModel
|
|
215
|
+
private ngRequired
|
|
216
|
+
private ngDisabled
|
|
217
|
+
private allowAlphanumeric: boolean
|
|
218
|
+
private name
|
|
219
|
+
private props
|
|
220
|
+
public valid
|
|
221
|
+
|
|
222
|
+
constructor(
|
|
223
|
+
public $scope,
|
|
224
|
+
public $element,
|
|
225
|
+
public $attrs,
|
|
226
|
+
) {
|
|
227
|
+
if ($attrs.ngRequired === '') {
|
|
228
|
+
this.ngRequired = true
|
|
229
|
+
}
|
|
230
|
+
if ($attrs.ngDisabled === '') {
|
|
231
|
+
this.ngDisabled = true
|
|
232
|
+
}
|
|
233
|
+
this.props = {
|
|
234
|
+
placeholder: $attrs.placeholder || '',
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
$onInit() {
|
|
239
|
+
this.allowAlphanumeric = this.allowAlphanumeric === true
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
ngBlur(evt) {
|
|
243
|
+
this.valid = evt.$event.target.value
|
|
244
|
+
this.valid = this.valid.toString()
|
|
245
|
+
this.valid = this.valid.replace(/[^0-9]/g, '')
|
|
246
|
+
if (this.valid.length === 11) {
|
|
247
|
+
this.validCpf(this.valid)
|
|
248
|
+
}
|
|
249
|
+
if (this.valid.length === 14) {
|
|
250
|
+
this.validCnpj(this.valid)
|
|
251
|
+
} else {
|
|
252
|
+
return false
|
|
79
253
|
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
CalcDigits(digits, positions = 10, sumDigits = 0) {
|
|
257
|
+
digits = digits.toString()
|
|
258
|
+
for (let i = 0; i < digits.length; i++) {
|
|
259
|
+
sumDigits += digits[i] * positions
|
|
260
|
+
positions--
|
|
261
|
+
if (positions < 2) positions = 9
|
|
262
|
+
}
|
|
263
|
+
sumDigits = sumDigits % 11
|
|
264
|
+
if (sumDigits < 2) sumDigits = 0
|
|
265
|
+
else sumDigits = 11 - sumDigits
|
|
266
|
+
return digits + sumDigits
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
validCpf(value) {
|
|
270
|
+
const digits = value.substr(0, 9)
|
|
271
|
+
const firstCalc = this.CalcDigits(digits)
|
|
272
|
+
const newCpf = this.CalcDigits(firstCalc, 11)
|
|
273
|
+
return newCpf === value
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
validCnpj(value) {
|
|
277
|
+
const firstNumbers = value.substr(0, 12)
|
|
278
|
+
const firstCalc = this.CalcDigits(firstNumbers, 5)
|
|
279
|
+
const secondCalc = this.CalcDigits(firstCalc, 6)
|
|
280
|
+
return secondCalc === value
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
onChange() {
|
|
284
|
+
if (this.ngChange) this.ngChange({})
|
|
285
|
+
}
|
|
80
286
|
}
|
|
81
287
|
MbgInputCpfCnpjController.$inject = ['$scope', '$element', '$attrs']
|
|
82
288
|
|
|
83
289
|
const mbgInputCpfCnpj = {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
290
|
+
bindings: {
|
|
291
|
+
ngModel: '=',
|
|
292
|
+
ngChange: '&?',
|
|
293
|
+
ngRequired: '=?',
|
|
294
|
+
ngDisabled: '=?',
|
|
295
|
+
ngBlur: '&?',
|
|
296
|
+
ngFocus: '&?',
|
|
297
|
+
ngKeyup: '&?',
|
|
298
|
+
ngKeypress: '&?',
|
|
299
|
+
ngKeydown: '&?',
|
|
300
|
+
allowAlphanumeric: '<?',
|
|
301
|
+
name: '@?',
|
|
302
|
+
},
|
|
303
|
+
template,
|
|
304
|
+
controller: MbgInputCpfCnpjController,
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export { mbgInputCpfCnpj, mbgAlphanumericCnpjMask }
|