Skip to content

Commit 88f5b99

Browse files
committed
v2.0.0
1 parent e4a0032 commit 88f5b99

File tree

3 files changed

+155
-11
lines changed

3 files changed

+155
-11
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
## 2.0.0 / 2015-04-07
2+
13
Updated to [inputmask-core@2.0.0](https://github.com/insin/inputmask-core/blob/master/CHANGES.md#200--2015-04-03)
24

35
Added undo/redo when Ctrl/Command + Z/Y are used.

dist/react-maskedinput.js

Lines changed: 151 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*!
2-
* react-maskedinput 1.1.0 - https://github.com/insin/react-maskedinput
2+
* react-maskedinput 2.0.0 - https://github.com/insin/react-maskedinput
33
* MIT Licensed
44
*/
55
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.MaskedInput = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
@@ -10,6 +10,17 @@ var $__0= require('react/lib/ReactInputSelection'),getSelection=$__0.getSelect
1010

1111
var InputMask = require('inputmask-core')
1212

13+
var KEYCODE_Z = 90
14+
var KEYCODE_Y = 89
15+
16+
function isUndo(e) {
17+
return (e.ctrlKey || e.metaKey) && e.keyCode === (e.shiftKey ? KEYCODE_Y : KEYCODE_Z)
18+
}
19+
20+
function isRedo(e) {
21+
return (e.ctrlKey || e.metaKey) && e.keyCode === (e.shiftKey ? KEYCODE_Z : KEYCODE_Y)
22+
}
23+
1324
var MaskedInput = React.createClass({displayName: "MaskedInput",
1425
propTypes: {
1526
pattern: React.PropTypes.string.isRequired,
@@ -65,6 +76,25 @@ var MaskedInput = React.createClass({displayName: "MaskedInput",
6576
_onKeyDown:function(e) {
6677
// console.log('onKeyDown', JSON.stringify(getSelection(this.getDOMNode())), e.key, e.target.value)
6778

79+
if (isUndo(e)) {
80+
e.preventDefault()
81+
if (this.mask.undo()) {
82+
e.target.value = this._getDisplayValue()
83+
this._updateInputSelection()
84+
this.props.onChange(e)
85+
}
86+
return
87+
}
88+
else if (isRedo(e)) {
89+
e.preventDefault()
90+
if (this.mask.redo()) {
91+
e.target.value = this._getDisplayValue()
92+
this._updateInputSelection()
93+
this.props.onChange(e)
94+
}
95+
return
96+
}
97+
6898
if (e.key == 'Backspace') {
6999
e.preventDefault()
70100
this._updateMaskSelection()
@@ -323,10 +353,14 @@ function InputMask(options) {
323353
}
324354

325355
this.formatCharacters = mergeFormatCharacters(options.formatCharacters)
326-
this.setPattern(options.pattern, options.value)
327-
this.setSelection(options.selection)
356+
this.setPattern(options.pattern, {
357+
value: options.value,
358+
selection: options.selection
359+
})
328360
}
329361

362+
// Editing
363+
330364
/**
331365
* Applies a single character of input based on the current selection.
332366
* @param {string} char
@@ -340,6 +374,9 @@ InputMask.prototype.input = function input(char) {
340374
return false
341375
}
342376

377+
var selectionBefore = copy(this.selection)
378+
var valueBefore = this.getValue()
379+
343380
var inputIndex = this.selection.start
344381

345382
// If a range of characters was selected and it includes the first editable
@@ -378,6 +415,21 @@ InputMask.prototype.input = function input(char) {
378415
this.selection.end++
379416
}
380417

418+
// History
419+
if (this._historyIndex != null) {
420+
// Took more input after undoing, so blow any subsequent history away
421+
console.log('splice(', this._historyIndex, this._history.length - this._historyIndex, ')')
422+
this._history.splice(this._historyIndex, this._history.length - this._historyIndex)
423+
this._historyIndex = null
424+
}
425+
if (this._lastOp != 'input' ||
426+
selectionBefore.start != selectionBefore.end ||
427+
this._lastSelection != null && selectionBefore.start != this._lastSelection.start) {
428+
this._history.push({value: valueBefore, selection: selectionBefore, lastOp: this._lastOp})
429+
}
430+
this._lastOp = 'input'
431+
this._lastSelection = copy(this.selection)
432+
381433
return true
382434
}
383435

@@ -393,6 +445,9 @@ InputMask.prototype.backspace = function backspace() {
393445
return false
394446
}
395447

448+
var selectionBefore = copy(this.selection)
449+
var valueBefore = this.getValue()
450+
396451
var format
397452

398453
// No range selected - work on the character preceding the cursor
@@ -415,6 +470,19 @@ InputMask.prototype.backspace = function backspace() {
415470
this.selection.end = this.selection.start
416471
}
417472

473+
// History
474+
if (this._historyIndex != null) {
475+
// Took more input after undoing, so blow any subsequent history away
476+
this._history.splice(this._historyIndex, this._history.length - this._historyIndex)
477+
}
478+
if (this._lastOp != 'backspace' ||
479+
selectionBefore.start != selectionBefore.end ||
480+
this._lastSelection != null && selectionBefore.start != this._lastSelection.start) {
481+
this._history.push({value: valueBefore, selection: selectionBefore, lastOp: this._lastOp})
482+
}
483+
this._lastOp = 'backspace'
484+
this._lastSelection = copy(this.selection)
485+
418486
return true
419487
}
420488

@@ -427,8 +495,16 @@ InputMask.prototype.backspace = function backspace() {
427495
* @return {boolean} true if the paste was successful, false otherwise.
428496
*/
429497
InputMask.prototype.paste = function paste(input) {
430-
var initialValue = this.value.slice()
431-
var initialSelection = copy(this.selection)
498+
// This is necessary because we're just calling input() with each character
499+
// and rolling back if any were invalid, rather than checking up-front.
500+
var initialState = {
501+
value: this.value.slice(),
502+
selection: copy(this.selection),
503+
_lastOp: this._lastOp,
504+
_history: this._history.slice(),
505+
_historyIndex: this._historyIndex,
506+
_lastSelection: copy(this._lastSelection)
507+
}
432508

433509
// If there are static characters at the start of the pattern and the cursor
434510
// or selection is within them, the static characters must match for a valid
@@ -462,18 +538,77 @@ InputMask.prototype.paste = function paste(input) {
462538
continue
463539
}
464540
}
465-
this.value = initialValue
466-
this.selection = initialSelection
541+
extend(this, initialState)
467542
return false
468543
}
469544
}
545+
470546
return true
471547
}
472548

473-
InputMask.prototype.setPattern = function setPattern(pattern, value) {
549+
// History
550+
551+
InputMask.prototype.undo = function undo() {
552+
// If there is no history, or nothing more on the history stack, we can't undo
553+
if (this._history.length === 0 || this._historyIndex === 0) {
554+
return false
555+
}
556+
557+
var historyItem
558+
if (this._historyIndex == null) {
559+
// Not currently undoing, set up the initial history index
560+
this._historyIndex = this._history.length - 1
561+
historyItem = this._history[this._historyIndex]
562+
// Add a new history entry if anything has changed since the last one, so we
563+
// can redo back to the initial state we started undoing from.
564+
var value = this.getValue()
565+
if (historyItem.value != value ||
566+
historyItem.selection.start != this.selection.start ||
567+
historyItem.selection.end != this.selection.end) {
568+
this._history.push({value: value, selection: copy(this.selection), lastOp: this._lastOp, startUndo: true})
569+
}
570+
}
571+
else {
572+
historyItem = this._history[--this._historyIndex]
573+
}
574+
575+
this.value = historyItem.value.split('')
576+
this.selection = historyItem.selection
577+
this._lastOp = historyItem.lastOp
578+
return true
579+
}
580+
581+
InputMask.prototype.redo = function redo() {
582+
if (this._history.length === 0 || this._historyIndex == null) {
583+
return false
584+
}
585+
var historyItem = this._history[++this._historyIndex]
586+
// If this is the last history item, we're done redoing
587+
if (this._historyIndex === this._history.length - 1) {
588+
this._historyIndex = null
589+
// If the last history item was only added to start undoing, remove it
590+
if (historyItem.startUndo) {
591+
this._history.pop()
592+
}
593+
}
594+
this.value = historyItem.value.split('')
595+
this.selection = historyItem.selection
596+
this._lastOp = historyItem.lastOp
597+
return true
598+
}
599+
600+
// Getters & setters
601+
602+
InputMask.prototype.setPattern = function setPattern(pattern, options) {
603+
options = extend({
604+
selection: {start: 0, end: 0},
605+
value: ''
606+
}, options)
474607
this.pattern = new Pattern(pattern, this.formatCharacters)
475-
this.setValue(value || '')
608+
this.setValue(options.value)
476609
this.emptyValue = this.pattern.formatValue([]).join('')
610+
this.selection = options.selection
611+
this._resetHistory()
477612
}
478613

479614
InputMask.prototype.setSelection = function setSelection(selection) {
@@ -499,6 +634,13 @@ InputMask.prototype.getValue = function getValue() {
499634
return this.value.join('')
500635
}
501636

637+
InputMask.prototype._resetHistory = function _resetHistory() {
638+
this._history = []
639+
this._historyIndex = null
640+
this._lastOp = null
641+
this._lastSelection = copy(this.selection)
642+
}
643+
502644
InputMask.Pattern = Pattern
503645

504646
module.exports = InputMask

0 commit comments

Comments
 (0)