Last active
April 21, 2017 03:42
-
-
Save romgrk/9513d238e00bb5df60af7b2f661bbe17 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * MaskedInput.js | |
| * Shamelessly copied from: https://github.com/insin/react-maskedinput (MIT License) | |
| * | |
| * Usage: | |
| * <MaskedInput mask='11/11/1111' onChange={value => console.log(value)} value={myValue} /> | |
| */ | |
| import React from 'react'; | |
| import { connect } from 'react-redux'; | |
| import Input from 'react-toolbox/lib/input'; | |
| import InputMask from 'inputmask-core'; | |
| var KEYCODE_Z = 90 | |
| var KEYCODE_Y = 89 | |
| var MaskedInput = React.createClass({ | |
| propTypes: { | |
| mask: React.PropTypes.string.isRequired, | |
| formatCharacters: React.PropTypes.object, | |
| placeholderChar: React.PropTypes.string | |
| }, | |
| getDefaultProps() { | |
| return { | |
| value: '' | |
| } | |
| }, | |
| getInitialState() { | |
| return { | |
| value: '' | |
| } | |
| }, | |
| componentWillMount() { | |
| var options = { | |
| pattern: this.props.mask, | |
| value: this.props.value, | |
| formatCharacters: this.props.formatCharacters | |
| } | |
| if (this.props.placeholderChar) { | |
| options.placeholderChar = this.props.placeholderChar | |
| } | |
| this.mask = new InputMask(options) | |
| }, | |
| componentWillReceiveProps(nextProps) { | |
| if (this.props.mask !== nextProps.mask && this.props.value !== nextProps.mask) { | |
| // if we get a new value and a new mask at the same time | |
| // check if the mask.value is still the initial value | |
| // - if so use the nextProps value | |
| // - otherwise the `this.mask` has a value for us (most likely from paste action) | |
| if (this.mask.getValue() === this.mask.emptyValue) { | |
| this.mask.setPattern(nextProps.mask, {value: nextProps.value}) | |
| } | |
| else { | |
| this.mask.setPattern(nextProps.mask, {value: this.mask.getRawValue()}) | |
| } | |
| } | |
| else if (this.props.mask !== nextProps.mask) { | |
| this.mask.setPattern(nextProps.mask, {value: this.mask.getRawValue()}) | |
| } | |
| else if (this.props.value !== nextProps.value) { | |
| this.mask.setValue(nextProps.value) | |
| } | |
| }, | |
| componentWillUpdate(nextProps, nextState) { | |
| if (nextProps.mask !== this.props.mask) { | |
| this._updatePattern(nextProps) | |
| } | |
| }, | |
| componentDidUpdate(prevProps) { | |
| if (prevProps.mask !== this.props.mask && this.mask.selection.start) { | |
| this._updateInputSelection() | |
| } | |
| }, | |
| _updatePattern: function(props) { | |
| this.mask.setPattern(props.mask, { | |
| value: this.mask.getRawValue(), | |
| selection: getSelection(this.input) | |
| }) | |
| }, | |
| _updateMaskSelection() { | |
| this.mask.selection = getSelection(this.input) | |
| }, | |
| _updateInputSelection() { | |
| setSelection(this.input, this.mask.selection) | |
| }, | |
| _onChange(newValue) { | |
| // console.log('onChange', JSON.stringify(getSelection(this.input)), e.target.value) | |
| var value | |
| var maskValue = this.mask.getValue() | |
| if (newValue !== maskValue) { | |
| // Cut or delete operations will have shortened the value | |
| if (newValue.length < maskValue.length) { | |
| var sizeDiff = maskValue.length - newValue.length | |
| this._updateMaskSelection() | |
| this.mask.selection.end = this.mask.selection.start + sizeDiff | |
| this.mask.backspace() | |
| } | |
| value = this._getDisplayValue() | |
| this.setState({ value: value }) | |
| if (value) { | |
| this._updateInputSelection() | |
| } | |
| } | |
| if (this.props.onChange) { | |
| this.props.onChange(value) | |
| } | |
| }, | |
| _onKeyDown(e) { | |
| // console.log('onKeyDown', JSON.stringify(getSelection(this.input)), e.key, e.target.value) | |
| if (isUndo(e)) { | |
| e.preventDefault() | |
| if (this.mask.undo()) { | |
| e.target.value = this._getDisplayValue() | |
| this._updateInputSelection() | |
| if (this.props.onChange) { | |
| this.props.onChange(this._getDisplayValue()) | |
| } | |
| } | |
| return | |
| } | |
| else if (isRedo(e)) { | |
| e.preventDefault() | |
| if (this.mask.redo()) { | |
| e.target.value = this._getDisplayValue() | |
| this._updateInputSelection() | |
| if (this.props.onChange) { | |
| this.props.onChange(this._getDisplayValue()) | |
| } | |
| } | |
| return | |
| } | |
| if (e.key === 'Backspace') { | |
| e.preventDefault() | |
| this._updateMaskSelection() | |
| if (this.mask.backspace()) { | |
| var value = this._getDisplayValue() | |
| e.target.value = value | |
| if (value) { | |
| this._updateInputSelection() | |
| } | |
| if (this.props.onChange) { | |
| this.props.onChange(this._getDisplayValue()) | |
| } | |
| } | |
| } | |
| }, | |
| _onKeyPress(e) { | |
| // console.log('onKeyPress', JSON.stringify(getSelection(this.input)), e.key, e.target.value) | |
| // Ignore modified key presses | |
| // Ignore enter key to allow form submission | |
| if (e.metaKey || e.altKey || e.ctrlKey || e.key === 'Enter') { return } | |
| e.preventDefault() | |
| this._updateMaskSelection() | |
| if (this.mask.input((e.key || e.data))) { | |
| e.target.value = this.mask.getValue() | |
| this._updateInputSelection() | |
| if (this.props.onChange) { | |
| this.props.onChange(this.mask.getValue()) | |
| } | |
| } | |
| }, | |
| _onPaste(e) { | |
| // console.log('onPaste', JSON.stringify(getSelection(this.input)), e.clipboardData.getData('Text'), e.target.value) | |
| e.preventDefault() | |
| this._updateMaskSelection() | |
| // getData value needed for IE also works in FF & Chrome | |
| if (this.mask.paste(e.clipboardData.getData('Text'))) { | |
| e.target.value = this.mask.getValue() | |
| // Timeout needed for IE | |
| setTimeout(this._updateInputSelection, 0) | |
| if (this.props.onChange) { | |
| this.props.onChange(this.mask.getValue()) | |
| } | |
| } | |
| }, | |
| _getDisplayValue() { | |
| //var value = this.mask.getValue() | |
| //return value === this.mask.emptyValue ? '' : value | |
| return this.mask.getValue() | |
| }, | |
| _keyPressPropName() { | |
| if (typeof navigator !== 'undefined') { | |
| return navigator.userAgent.match(/Android/i) | |
| ? 'onBeforeInput' | |
| : 'onKeyPress' | |
| } | |
| return 'onKeyPress' | |
| }, | |
| _getEventHandlers() { | |
| return { | |
| onChange: this._onChange, | |
| onKeyDown: this._onKeyDown, | |
| onPaste: this._onPaste, | |
| [this._keyPressPropName()]: this._onKeyPress | |
| } | |
| }, | |
| focus() { | |
| this.input.focus() | |
| }, | |
| blur() { | |
| this.input.blur() | |
| }, | |
| render() { | |
| var ref = r => { if (r) this.input = r.refs.wrappedInstance.inputNode } | |
| var maxLength = this.mask.pattern.length | |
| var value = this._getDisplayValue() | |
| var eventHandlers = this._getEventHandlers() | |
| var { size = maxLength, placeholder = this.mask.emptyValue } = this.props | |
| var {placeholderChar, formatCharacters, ...cleanedProps} = this.props | |
| var inputProps = { ...cleanedProps, ...eventHandlers, ref, maxLength, value, size, placeholder } | |
| return <Input {...inputProps} /> | |
| } | |
| }) | |
| function isUndo(e) { | |
| return (e.ctrlKey || e.metaKey) && e.keyCode === (e.shiftKey ? KEYCODE_Y : KEYCODE_Z) | |
| } | |
| function isRedo(e) { | |
| return (e.ctrlKey || e.metaKey) && e.keyCode === (e.shiftKey ? KEYCODE_Z : KEYCODE_Y) | |
| } | |
| function getSelection (el) { | |
| var start, end, rangeEl, clone | |
| if (el.selectionStart !== undefined) { | |
| start = el.selectionStart | |
| end = el.selectionEnd | |
| } | |
| else { | |
| try { | |
| el.focus() | |
| rangeEl = el.createTextRange() | |
| clone = rangeEl.duplicate() | |
| rangeEl.moveToBookmark(document.selection.createRange().getBookmark()) | |
| clone.setEndPoint('EndToStart', rangeEl) | |
| start = clone.text.length | |
| end = start + rangeEl.text.length | |
| } | |
| catch (e) { /* not focused or not visible */ } | |
| } | |
| return { start, end } | |
| } | |
| function setSelection(el, selection) { | |
| var rangeEl | |
| try { | |
| if (el.selectionStart !== undefined) { | |
| el.focus() | |
| el.setSelectionRange(selection.start, selection.end) | |
| } | |
| else { | |
| el.focus() | |
| rangeEl = el.createTextRange() | |
| rangeEl.collapse(true) | |
| rangeEl.moveStart('character', selection.start) | |
| rangeEl.moveEnd('character', selection.end - selection.start) | |
| rangeEl.select() | |
| } | |
| } | |
| catch (e) { /* not focused or not visible */ } | |
| } | |
| export default connect( | |
| )(MaskedInput); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment