Skip to content

Commit 474f54f

Browse files
authored
conformToMask: accept mask functions (#781)
* Add tests * Update tests * Move strFunction const to utilities * handle mask functions * Move test * Remove blank line * Update readme
1 parent 4e9d650 commit 474f54f

File tree

6 files changed

+95
-9
lines changed

6 files changed

+95
-9
lines changed

core/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ The `update` method should be called every time the `inputElement.value` changes
8989
This function takes three arguments:
9090

9191
* rawValue (string): the string value that you want to conform to the mask
92-
* mask (array): the mask to which you want the string to conform. You can find
92+
* mask (array or function): the mask to which you want the string to conform. You can find
9393
[mask documentation here](https://github.com/text-mask/text-mask/blob/master/componentDocumentation.md#readme).
9494
* config (object): config object. See below for details
9595

core/src/conformToMask.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
1-
import {convertMaskToPlaceholder, isArray} from './utilities'
2-
import {placeholderChar as defaultPlaceholderChar} from './constants'
1+
import {convertMaskToPlaceholder, isArray, processCaretTraps} from './utilities'
2+
import {placeholderChar as defaultPlaceholderChar, strFunction} from './constants'
33

44
const emptyArray = []
55
const emptyString = ''
66

77
export default function conformToMask(rawValue = emptyString, mask = emptyArray, config = {}) {
88
if (!isArray(mask)) {
9-
throw new Error(
10-
'Text-mask:conformToMask; The mask property must be an array.'
11-
)
9+
// If someone passes a function as the mask property, we should call the
10+
// function to get the mask array - Normally this is handled by the
11+
// `createTextMaskInputElement:update` function - this allows mask functions
12+
// to be used directly with `conformToMask`
13+
if (typeof mask === strFunction) {
14+
// call the mask function to get the mask array
15+
mask = mask(rawValue, config)
16+
17+
// mask functions can setup caret traps to have some control over how the caret moves. We need to process
18+
// the mask for any caret traps. `processCaretTraps` will remove the caret traps from the mask
19+
mask = processCaretTraps(mask).maskWithoutCaretTraps
20+
} else {
21+
throw new Error(
22+
'Text-mask:conformToMask; The mask property must be an array.'
23+
)
24+
}
1225
}
1326

1427
// These configurations tell us how to conform the mask

core/src/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export const placeholderChar = '_'
2+
export const strFunction = 'function'

core/src/createTextMaskInputElement.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import adjustCaretPosition from './adjustCaretPosition'
22
import conformToMask from './conformToMask'
33
import {convertMaskToPlaceholder, isString, isNumber, processCaretTraps} from './utilities'
4-
import {placeholderChar as defaultPlaceholderChar} from './constants'
4+
import {placeholderChar as defaultPlaceholderChar, strFunction} from './constants'
55

6-
const strFunction = 'function'
76
const emptyString = ''
87
const strNone = 'none'
98
const strObject = 'object'

core/test/conformToMask.spec.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ const conformToMask = (isVerify()) ?
1717
const testInputs = ['rawValue', 'mask', 'previousConformedValue', 'currentCaretPosition']
1818

1919
describe('conformToMask', () => {
20+
it('throws if mask is not an array or function', () => {
21+
const err = 'Text-mask:conformToMask; The mask property must be an array.'
22+
expect(() => conformToMask('', false)).to.throw(err)
23+
expect(() => conformToMask('', true)).to.throw(err)
24+
expect(() => conformToMask('', 'abc')).to.throw(err)
25+
expect(() => conformToMask('', 123)).to.throw(err)
26+
expect(() => conformToMask('', null)).to.throw(err)
27+
expect(() => conformToMask('', {})).to.throw(err)
28+
})
29+
2030
describe('Accepted character in mask', () => {
2131
dynamicTests(
2232
_.filter(acceptedCharInMask, test => !test.skip),
@@ -134,6 +144,57 @@ describe('conformToMask', () => {
134144
})
135145

136146
describe('Mask function', () => {
147+
it('works with mask functions', () => {
148+
const mask = () => [/\d/, /\d/, /\d/, /\d/]
149+
150+
expect(() => conformToMask('', mask)).to.not.throw()
151+
})
152+
153+
it('calls the mask function', () => {
154+
const maskSpy = sinon.spy(() => [/\d/, /\d/, /\d/, /\d/])
155+
const result = conformToMask('2', maskSpy)
156+
157+
expect(result.conformedValue).to.equal('2___')
158+
expect(maskSpy.callCount).to.equal(1)
159+
})
160+
161+
it('passes the rawValue to the mask function', () => {
162+
const mask = (value) => {
163+
expect(typeof value).to.equal('string')
164+
expect(value).to.equal('2')
165+
return [/\d/, /\d/, /\d/, /\d/]
166+
}
167+
const result = conformToMask('2', mask)
168+
169+
expect(result.conformedValue).to.equal('2___')
170+
})
171+
172+
it('passes the config to the mask function', () => {
173+
const mask = (value, config) => {
174+
expect(typeof config).to.equal('object')
175+
expect(config).to.deep.equal({
176+
currentCaretPosition: 2,
177+
previousConformedValue: '1',
178+
placeholderChar: '_'
179+
})
180+
return [/\d/, /\d/, /\d/, /\d/]
181+
}
182+
const result = conformToMask('12', mask, {
183+
currentCaretPosition: 2,
184+
previousConformedValue: '1',
185+
placeholderChar: '_'
186+
})
187+
188+
expect(result.conformedValue).to.equal('12__')
189+
})
190+
191+
it('processes the result of the mask function and removes caretTraps', () => {
192+
const mask = () => [/\d/, /\d/, '[]', '.', '[]', /\d/, /\d/]
193+
const result = conformToMask('2', mask)
194+
195+
expect(result.conformedValue).to.equal('2_.__')
196+
})
197+
137198
dynamicTests(
138199
maskFunctionTests,
139200

core/test/utilities.spec.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1-
import {processCaretTraps} from '../src/utilities'
1+
import {convertMaskToPlaceholder, processCaretTraps} from '../src/utilities'
22

3+
describe('convertMaskToPlaceholder', () => {
4+
it('throws if mask is not an array', () => {
5+
const err = 'Text-mask:convertMaskToPlaceholder; The mask property must be an array.'
6+
expect(() => convertMaskToPlaceholder(false)).to.throw(err)
7+
expect(() => convertMaskToPlaceholder(true)).to.throw(err)
8+
expect(() => convertMaskToPlaceholder('abc')).to.throw(err)
9+
expect(() => convertMaskToPlaceholder(123)).to.throw(err)
10+
expect(() => convertMaskToPlaceholder(null)).to.throw(err)
11+
expect(() => convertMaskToPlaceholder({})).to.throw(err)
12+
expect(() => convertMaskToPlaceholder(() => {})).to.throw(err)
13+
})
14+
})
315
describe('processCaretTraps', () => {
416
it('returns the mask without caret traps and the caret trap indexes', () => {
517
const mask = ['$', /\d/, /\d/, /\d/, /\d/, '.', '[]', /\d/, /\d/]

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy