ngx-mask 8.1.7 → 8.2.0

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![Build Status](https://img.shields.io/travis/JsDaddy/ngx-mask.svg?branch=develop)](https://travis-ci.org/JsDaddy/ngx-mask)
6
6
  [![npm](https://img.shields.io/npm/v/ngx-mask.svg)](https://www.npmjs.com/package/ngx-mask)
7
7
  <a href="https://npmjs.org/ngx-mask">
8
- <img src="https://img.shields.io/npm/dt/ngx-mask.svg" alt="npm downloads">
8
+ <img src="https://img.shields.io/npm/dt/ngx-mask.svg" alt="npm downloads">
9
9
  </a>
10
10
 
11
11
  [![npm](https://img.shields.io/npm/dm/ngx-mask.svg)](https://www.npmjs.com/package/ngx-mask)
@@ -30,7 +30,7 @@ $ npm install --save ngx-mask
30
30
  Import **ngx-mask** module in Angular app.
31
31
 
32
32
  ```typescript
33
- import { NgxMaskModule } from 'ngx-mask'
33
+ import { NgxMaskModule, IConfig } from 'ngx-mask'
34
34
 
35
35
  export const options: Partial<IConfig> | (() => Partial<IConfig>);
36
36
 
@@ -48,7 +48,13 @@ Then, just define masks in inputs.
48
48
  ### Usage
49
49
 
50
50
  ```html
51
- <input type="text" mask="{here comes your mask}" />
51
+ <input type="text" mask="<here goes your mask>" />
52
+ ```
53
+
54
+ or
55
+
56
+ ```html
57
+ <input type="text" [mask]="<here goes a reference to your component's mask property>" />
52
58
  ```
53
59
 
54
60
  Also, you can use mask pipe.
@@ -72,35 +78,35 @@ For separator you can add thousandSeparator
72
78
  | mask | example |
73
79
  | -------------- | -------------- |
74
80
  | 9999-99-99 | 2017-04-15 |
75
- | 0*.00 | 2017.22 |
81
+ | 0\*.00 | 2017.22 |
76
82
  | 000.000.000-99 | 048.457.987-98 |
77
83
  | AAAA | 0F6g |
78
84
  | SSSS | asDF |
79
85
 
80
86
  ## Mask Options
81
87
 
82
- You can define your custom options for all directives (as object in the mask module) or for each (as attributes for directive). If you override this parameter, you have to provide all the special characters (default one are not included).
88
+ You can define your custom options for all directives (as object in the mask module) or for each (as attributes for directive). If you override this parameter, you have to provide all the special characters (default one are not included).
83
89
 
84
90
  ### specialCharacters (string[ ])
85
91
 
86
92
  We have next default characters:
87
93
 
88
- | character |
89
- |-----------|
90
- | - |
91
- | / |
92
- | ( |
93
- | ) |
94
- | . |
95
- | : |
96
- | **space** |
97
- | + |
98
- | , |
99
- | @ |
100
- | [ |
101
- | ] |
102
- | " |
103
- | ' |
94
+ | character |
95
+ | --------- |
96
+ | - |
97
+ | / |
98
+ | ( |
99
+ | ) |
100
+ | . |
101
+ | : |
102
+ | **space** |
103
+ | + |
104
+ | , |
105
+ | @ |
106
+ | [ |
107
+ | ] |
108
+ | " |
109
+ | ' |
104
110
 
105
111
  #### Usage
106
112
 
@@ -121,12 +127,12 @@ patterns ({ [character: string]: { pattern: RegExp, optional?: boolean})
121
127
 
122
128
  We have next default patterns:
123
129
 
124
- | code | meaning |
125
- | ----- | ------------------------------------------- |
126
- | **0** | digits (like 0 to 9 numbers) |
127
- | **9** | digits (like 0 to 9 numbers), but optional |
128
- | **A** | letters (uppercase or lowercase) and digits |
129
- | **S** | only letters (uppercase or lowercase) |
130
+ | code | meaning |
131
+ | ----- | ------------------------------------------- |
132
+ | **0** | digits (like 0 to 9 numbers) |
133
+ | **9** | digits (like 0 to 9 numbers), but optional |
134
+ | **A** | letters (uppercase or lowercase) and digits |
135
+ | **S** | only letters (uppercase or lowercase) |
130
136
 
131
137
  ##### Usage
132
138
 
@@ -153,11 +159,11 @@ You can define custom pattern and specify symbol to be rendered in input field.
153
159
 
154
160
  ```typescript
155
161
  pattern = {
156
- 'B': {
162
+ B: {
157
163
  pattern: new RegExp('\\d'),
158
- symbol: 'X'
159
- }
160
- }
164
+ symbol: 'X',
165
+ },
166
+ };
161
167
  ```
162
168
 
163
169
  ### prefix (string)
@@ -204,7 +210,24 @@ You can choose if mask is shown while typing, or not, default value is `false`.
204
210
  #### Usage
205
211
 
206
212
  ```html
207
- <input mask="(000) 000-0000" prefix="+7" [showMaskTyped]="true" />
213
+ <input mask="(000) 000-0000" prefix="+7" [showMaskTyped]="true" />
214
+ ```
215
+
216
+ ### allowNegativeNumbers (boolean)
217
+
218
+ You can choose if mask will allow the use of negative numbers. The default value is `false`.
219
+
220
+ #### Usage
221
+
222
+ ```html
223
+ <input type="text" [allowNegativeNumbers]="true" mask="separator.2" />
224
+ ```
225
+
226
+ ##### Then
227
+
228
+ ```text
229
+ Input value: -10,000.45
230
+ Model value: -10000.45
208
231
  ```
209
232
 
210
233
  ### placeHolderCharacter (string)
@@ -214,7 +237,7 @@ If the `showMaskTyped` parameter is enabled, this setting customizes the charact
214
237
  #### Usage
215
238
 
216
239
  ```html
217
- <input mask="(000) 000-0000" prefix="+7" [showMaskTyped]="true" placeHolderCharacter="*" />
240
+ <input mask="(000) 000-0000" prefix="+7" [showMaskTyped]="true" placeHolderCharacter="*" />
218
241
  ```
219
242
 
220
243
  ### clearIfNotMatch (boolean)
@@ -224,7 +247,7 @@ You can choose clear the input if the input value **not match** the mask, defaul
224
247
  ### Pipe with mask expression and custom Pattern ([string, pattern])
225
248
 
226
249
  You can pass array of expression and custom Pattern to pipe.
227
-
250
+
228
251
  #### Usage
229
252
 
230
253
  ```html
@@ -237,22 +260,22 @@ and in your component
237
260
  customMask: [string, pattern];
238
261
 
239
262
  pattern = {
240
- 'P': {
263
+ P: {
241
264
  pattern: new RegExp('\\d'),
242
- }
265
+ },
243
266
  };
244
-
267
+
245
268
  this.customMask = ['PPP-PPP', this.pattern];
246
269
  ```
247
270
 
248
271
  ### Repeat mask
249
272
 
250
273
  You can pass into mask pattern with brackets.
251
-
274
+
252
275
  #### Usage
253
276
 
254
277
  ```html
255
- <input type="text" mask="A{4}" />
278
+ <input type="text" mask="A{4}" />
256
279
  ```
257
280
 
258
281
  ### Thousand separator
@@ -262,19 +285,19 @@ You can divide your input by thousands, by default will seperate with a space.
262
285
  #### Usage
263
286
 
264
287
  ```html
265
- <input type="text" mask="separator" />
288
+ <input type="text" mask="separator" />
266
289
  ```
267
290
 
268
291
  For separate input with dots.
269
292
 
270
293
  ```html
271
- <input type="text" mask="separator" thousandSeparator="." />
294
+ <input type="text" mask="separator" thousandSeparator="." />
272
295
  ```
273
296
 
274
297
  For using decimals enter `.` and how many decimals to the end of your input to `separator` mask.
275
298
 
276
299
  ```html
277
- <input type="text" mask="separator.2" />
300
+ <input type="text" mask="separator.2" />
278
301
  ```
279
302
 
280
303
  ```text
@@ -289,10 +312,10 @@ Masked value: 1,234.56
289
312
  ```
290
313
 
291
314
  ```html
292
- <input type="text" mask="separator.2" thousandSeparator="." />
293
- <input type="text" mask="separator.2" thousandSeparator="," />
294
- <input type="text" mask="separator.0" thousandSeparator="." />
295
- <input type="text" mask="separator.0" thousandSeparator="," />
315
+ <input type="text" mask="separator.2" thousandSeparator="." />
316
+ <input type="text" mask="separator.2" thousandSeparator="," />
317
+ <input type="text" mask="separator.0" thousandSeparator="." />
318
+ <input type="text" mask="separator.0" thousandSeparator="," />
296
319
  ```
297
320
 
298
321
  For limiting decimal precision add `.` and the precision you want to limit too on the input. **2** is useful for currency. **0** will prevent decimals completely.
@@ -312,7 +335,7 @@ Masked value: 1,234
312
335
  ```
313
336
 
314
337
  ```html
315
- <input type="text" mask="separator.2" separatorLimit="1000" />
338
+ <input type="text" mask="separator.2" separatorLimit="1000" />
316
339
  ```
317
340
 
318
341
  For limiting the number of digits before the decimal point you can set `separatorLimit` value to _10_, _100_, _1000_ etc.
@@ -329,7 +352,7 @@ You can validate your input as 24 hour format.
329
352
  #### Usage
330
353
 
331
354
  ```html
332
- <input type="text" mask="Hh:m0:s0" />
355
+ <input type="text" mask="Hh:m0:s0" />
333
356
  ```
334
357
 
335
358
  ### Percent validation
@@ -339,7 +362,7 @@ You can validate your input for percents.
339
362
  #### Usage
340
363
 
341
364
  ```html
342
- <input type="text" mask="percent" suffix="%" />
365
+ <input type="text" mask="percent" suffix="%" />
343
366
  ```
344
367
 
345
368
  ### FormControl validation
@@ -349,7 +372,7 @@ You can validate your `formControl`, default value is `true`.
349
372
  #### Usage
350
373
 
351
374
  ```html
352
- <input type="text" mask="00 00" [validation]="true" />
375
+ <input type="text" mask="00 00" [validation]="true" />
353
376
  ```
354
377
 
355
378
  ### Secure input
@@ -359,7 +382,7 @@ You can hide symbols in input field and get the actual value in `formcontrol`.
359
382
  #### Usage
360
383
 
361
384
  ```html
362
- <input placeholder="Secure input" [hiddenInput]="true" mask="XXX/X0/0000" />
385
+ <input placeholder="Secure input" [hiddenInput]="true" mask="XXX/X0/0000" />
363
386
  ```
364
387
 
365
388
  ### IP valid mask
@@ -367,5 +390,5 @@ You can hide symbols in input field and get the actual value in `formcontrol`.
367
390
  #### Usage
368
391
 
369
392
  ```html
370
- <input mask="IP" />
393
+ <input mask="IP" />
371
394
  ```
@@ -239,6 +239,8 @@
239
239
  /** @type {?} */
240
240
  IConfig.prototype.separatorLimit;
241
241
  /** @type {?} */
242
+ IConfig.prototype.allowNegativeNumbers;
243
+ /** @type {?} */
242
244
  IConfig.prototype.patterns;
243
245
  }
244
246
  /** @type {?} */
@@ -261,6 +263,7 @@
261
263
  hiddenInput: undefined,
262
264
  shownMaskExpression: '',
263
265
  separatorLimit: '',
266
+ allowNegativeNumbers: false,
264
267
  validation: true,
265
268
  // tslint:disable-next-line: quotemark
266
269
  specialCharacters: ['-', '/', '(', ')', '.', ':', ' ', '+', ',', '@', '[', ']', '"', "'"],
@@ -419,6 +422,7 @@
419
422
  this.placeHolderCharacter = this._config.placeHolderCharacter;
420
423
  this.validation = this._config.validation;
421
424
  this.separatorLimit = this._config.separatorLimit;
425
+ this.allowNegativeNumbers = this._config.allowNegativeNumbers;
422
426
  }
423
427
  /**
424
428
  * @param {?} inputValue
@@ -872,6 +876,8 @@
872
876
  MaskApplierService.prototype.validation;
873
877
  /** @type {?} */
874
878
  MaskApplierService.prototype.separatorLimit;
879
+ /** @type {?} */
880
+ MaskApplierService.prototype.allowNegativeNumbers;
875
881
  /**
876
882
  * @type {?}
877
883
  * @private
@@ -918,7 +924,6 @@
918
924
  _this._renderer = _renderer;
919
925
  _this.maskExpression = '';
920
926
  _this.isNumberValue = false;
921
- _this.showMaskTyped = false;
922
927
  _this.placeHolderCharacter = '_';
923
928
  _this.maskIsShown = '';
924
929
  _this.selStart = null;
@@ -1430,8 +1435,6 @@
1430
1435
  /** @type {?} */
1431
1436
  MaskService.prototype.isNumberValue;
1432
1437
  /** @type {?} */
1433
- MaskService.prototype.showMaskTyped;
1434
- /** @type {?} */
1435
1438
  MaskService.prototype.placeHolderCharacter;
1436
1439
  /** @type {?} */
1437
1440
  MaskService.prototype.maskIsShown;
@@ -1494,6 +1497,7 @@
1494
1497
  this.clearIfNotMatch = null;
1495
1498
  this.validation = null;
1496
1499
  this.separatorLimit = null;
1500
+ this.allowNegativeNumbers = null;
1497
1501
  this._maskValue = '';
1498
1502
  this._position = null;
1499
1503
  this.onChange = (/**
@@ -1515,7 +1519,7 @@
1515
1519
  * @return {?}
1516
1520
  */
1517
1521
  function (changes) {
1518
- var maskExpression = changes.maskExpression, specialCharacters = changes.specialCharacters, patterns = changes.patterns, prefix = changes.prefix, suffix = changes.suffix, thousandSeparator = changes.thousandSeparator, decimalMarker = changes.decimalMarker, dropSpecialCharacters = changes.dropSpecialCharacters, hiddenInput = changes.hiddenInput, showMaskTyped = changes.showMaskTyped, placeHolderCharacter = changes.placeHolderCharacter, shownMaskExpression = changes.shownMaskExpression, showTemplate = changes.showTemplate, clearIfNotMatch = changes.clearIfNotMatch, validation = changes.validation, separatorLimit = changes.separatorLimit;
1522
+ var maskExpression = changes.maskExpression, specialCharacters = changes.specialCharacters, patterns = changes.patterns, prefix = changes.prefix, suffix = changes.suffix, thousandSeparator = changes.thousandSeparator, decimalMarker = changes.decimalMarker, dropSpecialCharacters = changes.dropSpecialCharacters, hiddenInput = changes.hiddenInput, showMaskTyped = changes.showMaskTyped, placeHolderCharacter = changes.placeHolderCharacter, shownMaskExpression = changes.shownMaskExpression, showTemplate = changes.showTemplate, clearIfNotMatch = changes.clearIfNotMatch, validation = changes.validation, separatorLimit = changes.separatorLimit, allowNegativeNumbers = changes.allowNegativeNumbers;
1519
1523
  if (maskExpression) {
1520
1524
  this._maskValue = changes.maskExpression.currentValue || '';
1521
1525
  }
@@ -1570,6 +1574,13 @@
1570
1574
  if (separatorLimit) {
1571
1575
  this._maskService.separatorLimit = separatorLimit.currentValue;
1572
1576
  }
1577
+ if (allowNegativeNumbers) {
1578
+ this._maskService.maskSpecialCharacters = this._maskService.maskSpecialCharacters.filter((/**
1579
+ * @param {?} c
1580
+ * @return {?}
1581
+ */
1582
+ function (c) { return c !== '-'; }));
1583
+ }
1573
1584
  this._applyMask();
1574
1585
  };
1575
1586
  // tslint:disable-next-line: cyclomatic-complexity
@@ -1590,7 +1601,7 @@
1590
1601
  return null;
1591
1602
  }
1592
1603
  if (this._maskService.ipError) {
1593
- return { 'Mask error': true };
1604
+ return this._createValidationError(value);
1594
1605
  }
1595
1606
  if (this._maskValue.startsWith('separator')) {
1596
1607
  return null;
@@ -1649,7 +1660,7 @@
1649
1660
  else if ((this._maskValue.indexOf('*') > 1 && value.toString().length < this._maskValue.indexOf('*')) ||
1650
1661
  (this._maskValue.indexOf('?') > 1 && value.toString().length < this._maskValue.indexOf('?')) ||
1651
1662
  this._maskValue.indexOf('{') === 1) {
1652
- return { 'Mask error': true };
1663
+ return this._createValidationError(value);
1653
1664
  }
1654
1665
  if (this._maskValue.indexOf('*') === -1 || this._maskValue.indexOf('?') === -1) {
1655
1666
  /** @type {?} */
@@ -1657,7 +1668,7 @@
1657
1668
  ? this._maskValue.length - this._maskService.checkSpecialCharAmount(this._maskValue) - counterOfOpt
1658
1669
  : this._maskValue.length - counterOfOpt;
1659
1670
  if (value.toString().length < length_1) {
1660
- return { 'Mask error': true };
1671
+ return this._createValidationError(value);
1661
1672
  }
1662
1673
  }
1663
1674
  }
@@ -1705,6 +1716,9 @@
1705
1716
  var positionToApply = this._position
1706
1717
  ? this._inputValue.length + position + caretShift
1707
1718
  : position + (this._code === 'Backspace' && !backspaceShift ? 0 : caretShift);
1719
+ if (positionToApply > this._getActualInputLength()) {
1720
+ positionToApply = this._getActualInputLength();
1721
+ }
1708
1722
  el.setSelectionRange(positionToApply, positionToApply);
1709
1723
  if ((this.maskExpression.includes('H') || this.maskExpression.includes('M')) && caretShift === 0) {
1710
1724
  el.setSelectionRange(((/** @type {?} */ (el.selectionStart))) + 1, ((/** @type {?} */ (el.selectionStart))) + 1);
@@ -1771,6 +1785,10 @@
1771
1785
  el.selectionStart = this._maskService.prefix.length;
1772
1786
  return;
1773
1787
  }
1788
+ /** select only inserted text */
1789
+ if (((/** @type {?} */ (el.selectionEnd))) > this._getActualInputLength()) {
1790
+ el.selectionEnd = this._getActualInputLength();
1791
+ }
1774
1792
  };
1775
1793
  // tslint:disable-next-line: cyclomatic-complexity
1776
1794
  // tslint:disable-next-line: cyclomatic-complexity
@@ -1803,8 +1821,7 @@
1803
1821
  el.setSelectionRange(this.prefix.length, this.prefix.length);
1804
1822
  }
1805
1823
  else {
1806
- if (this._inputValue.length !== ((/** @type {?} */ (el.selectionStart))) &&
1807
- ((/** @type {?} */ (el.selectionStart))) !== 1) {
1824
+ if (this._inputValue.length !== ((/** @type {?} */ (el.selectionStart))) && ((/** @type {?} */ (el.selectionStart))) !== 1) {
1808
1825
  while (this.specialCharacters.includes(this._inputValue[((/** @type {?} */ (el.selectionStart))) - 1].toString()) &&
1809
1826
  ((this.prefix.length >= 1 && ((/** @type {?} */ (el.selectionStart))) > this.prefix.length) ||
1810
1827
  this.prefix.length === 0)) {
@@ -1837,6 +1854,12 @@
1837
1854
  this._inputValue.length - this.suffix.length < ((/** @type {?} */ (el.selectionStart)))) {
1838
1855
  el.setSelectionRange(this._inputValue.length - this.suffix.length, this._inputValue.length);
1839
1856
  }
1857
+ else if ((e.keyCode === 65 && e.ctrlKey === true) || // Ctrl+ A
1858
+ (e.keyCode === 65 && e.metaKey === true) // Cmd + A (Mac)
1859
+ ) {
1860
+ el.setSelectionRange(0, this._getActualInputLength());
1861
+ e.preventDefault();
1862
+ }
1840
1863
  this._maskService.selStart = el.selectionStart;
1841
1864
  this._maskService.selEnd = el.selectionEnd;
1842
1865
  };
@@ -1914,8 +1937,7 @@
1914
1937
  }
1915
1938
  }
1916
1939
  if (keyCode === 8) {
1917
- if (this.suffix.length > 1 &&
1918
- this._inputValue.length - this.suffix.length < ((/** @type {?} */ (el.selectionStart)))) {
1940
+ if (this.suffix.length > 1 && this._inputValue.length - this.suffix.length < ((/** @type {?} */ (el.selectionStart)))) {
1919
1941
  el.setSelectionRange(this._inputValue.length - this.suffix.length, this._inputValue.length);
1920
1942
  }
1921
1943
  if (this.suffix.length === 1 && this._inputValue.length === ((/** @type {?} */ (el.selectionStart)))) {
@@ -2019,14 +2041,43 @@
2019
2041
  * @return {?}
2020
2042
  */
2021
2043
  function (s) { return s !== ':'; })).length;
2022
- if (+value[value.length - 1] === 0 && value.length < rowMaskLen) {
2023
- return { 'Mask error': true };
2044
+ if (value === null || value.length === 0) {
2045
+ return null; // Don't validate empty values to allow for optional form control
2024
2046
  }
2025
- if (value.length <= rowMaskLen - 2) {
2026
- return { 'Mask error': true };
2047
+ if ((+value[value.length - 1] === 0 && value.length < rowMaskLen) || value.length <= rowMaskLen - 2) {
2048
+ return this._createValidationError(value);
2027
2049
  }
2028
2050
  return null;
2029
2051
  };
2052
+ /**
2053
+ * @private
2054
+ * @return {?}
2055
+ */
2056
+ MaskDirective.prototype._getActualInputLength = /**
2057
+ * @private
2058
+ * @return {?}
2059
+ */
2060
+ function () {
2061
+ return (this._maskService.actualValue.length || this._maskService.actualValue.length + this._maskService.prefix.length);
2062
+ };
2063
+ /**
2064
+ * @private
2065
+ * @param {?} actualValue
2066
+ * @return {?}
2067
+ */
2068
+ MaskDirective.prototype._createValidationError = /**
2069
+ * @private
2070
+ * @param {?} actualValue
2071
+ * @return {?}
2072
+ */
2073
+ function (actualValue) {
2074
+ return {
2075
+ mask: {
2076
+ requiredMask: this._maskValue,
2077
+ actualValue: actualValue,
2078
+ },
2079
+ };
2080
+ };
2030
2081
  MaskDirective.decorators = [
2031
2082
  { type: core.Directive, args: [{
2032
2083
  selector: '[mask]',
@@ -2074,6 +2125,7 @@
2074
2125
  clearIfNotMatch: [{ type: core.Input }],
2075
2126
  validation: [{ type: core.Input }],
2076
2127
  separatorLimit: [{ type: core.Input }],
2128
+ allowNegativeNumbers: [{ type: core.Input }],
2077
2129
  onInput: [{ type: core.HostListener, args: ['input', ['$event'],] }],
2078
2130
  onBlur: [{ type: core.HostListener, args: ['blur',] }],
2079
2131
  onFocus: [{ type: core.HostListener, args: ['click', ['$event'],] }],
@@ -2115,6 +2167,8 @@
2115
2167
  MaskDirective.prototype.validation;
2116
2168
  /** @type {?} */
2117
2169
  MaskDirective.prototype.separatorLimit;
2170
+ /** @type {?} */
2171
+ MaskDirective.prototype.allowNegativeNumbers;
2118
2172
  /**
2119
2173
  * @type {?}
2120
2174
  * @private