Skip to content

Instantly share code, notes, and snippets.

@sepulchered
Created January 24, 2013 11:18
Show Gist options
  • Save sepulchered/4620207 to your computer and use it in GitHub Desktop.
Save sepulchered/4620207 to your computer and use it in GitHub Desktop.
/*
* Original source is taken from http://www.sencha.com/forum/showthread.php?136002-Mask-for-TextField
* This code was created by sencha forum user http://www.sencha.com/forum/member.php?257343-FrankXP
* all rights to this code belong to him.
*
* Usage example:
* {
* xtype: 'textfield',
* mask: { text: '(999) 999-9999', placeholder:'#', includeInValue: false }
* }
*
* includeInValue will include/exclude the mask when getValue() is called. (default: true)
*/
Ext.form.MaskDefinitions = {
'9': '[0-9]',
'a': '[A-Za-z]',
'*': '[A-Za-z0-9]'
};
Ext.applyIf(Array.prototype, {
map: function (fn, scope) {
var r = [],
i = 0,
len = this.length,
v;
for (; i < len; i++) {
v = fn.call(scope, this[i], i, this);
if (v != null)
r.push(v);
}
return r;
}
});
(function () {
var _initComponent = Ext.form.TextField.prototype.initComponent,
_initEvents = Ext.form.TextField.prototype.initEvents,
_getValue = Ext.form.TextField.prototype.getValue,
_setValue = Ext.form.TextField.prototype.setValue,
_preFocus = Ext.form.TextField.prototype.preFocus;
Ext.override(Ext.form.TextField, {
initComponent: function () {
if (this.initMask()) {
Ext.apply(this, {
disableKeyFilter: true,
maskRe: null
});
this.addEvents('maskComplete');
}
_initComponent.apply(this);
},
initEvents: function () {
_initEvents.apply(this);
if (this.mask) {
if (!this.enableKeyEvents && this.mask) {
this.mon(this.el, {
scope: this,
keydown: this.onKeyDown,
keypress: this.onKeyPress
});
}
this.mon(this.el, 'paste', this.onPaste, this);
}
},
initMask: function () {
if (!Ext.isDefined(this.mask)) {
return false;
}
this.mask = Ext.isString(this.mask) ? { text: this.mask} : this.mask;
Ext.applyIf(this.mask, { placeholder: '_', includeInValue: true });
if (!this.mask.text) {
return false;
}
Ext.apply(this.mask, {
regexp: [],
partialPosition: this.mask.text.length,
firstNonMaskPos: null,
length: this.mask.text.length,
buffer: this.mask.text.split('').map(function (c) {
return (c === '?') ? null : Ext.form.MaskDefinitions[c] ? this.mask.placeholder : c;
}, this),
seekNext: function (pos) {
while (++pos <= this.length && !this.regexp[pos]);
return pos;
},
seekPrev: function (pos) {
while (--pos >= 0 && !this.regexp[pos]);
return pos;
},
shiftL: function (start, end) {
if (start < 0) {
return;
}
for (var i = start, j = this.seekNext(end); i < this.length; i++) {
if (this.regexp[i]) {
if (j < this.length && this.regexp[i].test(this.buffer[j])) {
this.buffer[i] = this.buffer[j];
this.buffer[j] = this.placeholder;
} else {
break;
}
j = this.seekNext(j);
}
}
},
shiftR: function (pos) {
for (var i = pos, c = this.placeholder; i < this.length; i++) {
if (this.regexp[i]) {
var j = this.seekNext(i);
var t = this.buffer[i];
this.buffer[i] = c;
if (j < this.length && this.regexp[j].test(t)) {
c = t;
}
else {
break;
}
}
}
},
clearBuffer: function (start, end) {
for (var i = start; i < end && i < this.length; i++) {
if (this.regexp[i]) {
this.buffer[i] = this.placeholder;
}
}
},
getBufferValue: function (removeMask) {
return removeMask ?
this.buffer.map(function (c, i) {
return (this.regexp[i] && c != this.placeholder) ? c : null;
}, this).join('') :
this.buffer.join('');
}
});
Ext.each(this.mask.text.split(''), function (c, i) {
if (c === '?') {
this.mask.length--;
this.mask.partialPosition = i;
} else if (Ext.form.MaskDefinitions[c]) {
this.mask.regexp.push(new RegExp(Ext.form.MaskDefinitions[c]));
if (this.mask.firstNonMaskPos == null) {
this.mask.firstNonMaskPos = this.mask.regexp.length - 1;
}
} else {
this.mask.regexp.push(null);
}
}, this);
return true;
},
//private
_cursor: function (start, end) {
var s, e, r, d = this.el.dom;
if (typeof start == 'number') {
end = (typeof end == 'number') ? end : start;
if (d.setSelectionRange) {
d.setSelectionRange(start, end);
} else if (d.createTextRange) {
r = d.createTextRange();
r.collapse(true);
r.moveEnd('character', end);
r.moveStart('character', start);
r.select();
}
}
else {
if (d.setSelectionRange) {
s = d.selectionStart;
e = d.selectionEnd;
}
else if (document.selection && document.selection.createRange) {
r = document.selection.createRange();
s = 0 - r.duplicate().moveStart('character', -d.value.length);
e = s + r.text.length;
}
return { start: isNaN(s) ? 0 : s, end: isNaN(e) ? 0 : e };
}
},
_checkValueMask: function (allow) {
var test = this.getRawValue();
var lastMatch = -1;
for (var i = 0, pos = 0; i < this.mask.length; i++) {
if (this.mask.regexp[i]) {
this.mask.buffer[i] = this.mask.placeholder;
while (pos++ < test.length) {
var c = test.charAt(pos - 1);
if (this.mask.regexp[i].test(c)) {
this.mask.buffer[i] = c;
lastMatch = i;
break;
}
}
if (pos > test.length)
break;
} else if (this.mask.buffer[i] == test.charAt(pos) && i != this.mask.partialPosition) {
pos++;
lastMatch = i;
}
}
if (!allow && lastMatch + 1 < this.mask.partialPosition) {
this.setRawValue('');
this.mask.clearBuffer(0, this.mask.length);
} else if (allow || lastMatch + 1 >= this.mask.partialPosition) {
this._writeMaskBuffer();
if (!allow) this.setRawValue(this.getRawValue().substring(0, lastMatch + 1));
}
return (this.mask.partialPosition ? i : this.mask.firstNonMaskPos);
},
_writeMaskBuffer: function () {
this.setRawValue(this.mask.getBufferValue());
},
//public
getValue: function () {
var v = _getValue.apply(this);
if (this.mask && !Ext.isEmpty(v)) {
v = this.mask.includeInValue ? v.replace(this.mask.placeholder,'') : this.mask.getBufferValue(true);
}
return v;
},
setValue: function (v) {
_setValue.call(this, v);
if (this.mask && !Ext.isEmpty(v)) {
this._checkValueMask();
}
},
//protected
preFocus: function () {
_preFocus.apply(this);
if (this.mask && !this.hasFocus) {
this.startValue = this.getValue();
var pos = this._checkValueMask();
this._writeMaskBuffer();
(function () {
if (pos == this.mask.length) {
this._cursor(0, pos);
}
else {
this._cursor(pos);
}
}).defer(0, this);
}
},
beforeBlur: function () {
if (this.mask && !this.readOnly) {
this._checkValueMask();
}
},
onKeyDown: function (e) {
this.fireEvent('keydown', this, e);
if (this.mask && !this.readOnly) {
var k = e.getKey();
if (k == e.BACKSPACE || k == e.DELETE) {
var pos = this._cursor(),
start = pos.start,
end = pos.end;
if (end - start == 0) {
start = k != e.DELETE ? this.mask.seekPrev(start) : (end = this.mask.seekNext(start - 1));
end = k == e.DELETE ? this.mask.seekNext(end) : end;
}
this.mask.clearBuffer(start, end);
this.mask.shiftL(start, end - 1);
this._writeMaskBuffer();
this._cursor(Math.max(this.mask.firstNonMaskPos, start));
e.stopEvent();
} else if (k == e.ESC) {
this.setValue(this.startValue);
this._cursor(0, this._checkValueMask());
e.stopEvent();
}
}
},
onKeyPress: function (e) {
this.fireEvent('keypress', this, e);
if (this.mask && !this.readOnly) {
var k = e.getKey(),
pos = this._cursor(),
start = pos.start,
end = pos.end;
if (!e.ctrlKey && !e.altKey && !e.isNavKeyPress() && k != e.CONTEXT_MENU && k >= 32) {
if (end - start != 0) {
this.mask.clearBuffer(start, end);
this.mask.shiftL(start, end - 1);
this._writeMaskBuffer();
this._cursor(Math.max(this.mask.firstNonMaskPos, start));
}
var p = this.mask.seekNext(start - 1);
if (p < this.mask.length) {
var c = String.fromCharCode(e.getCharCode());
if (this.mask.regexp[p].test(c)) {
this.mask.shiftR(p);
this.mask.buffer[p] = c;
this._writeMaskBuffer();
var next = this.mask.seekNext(p);
this._cursor(next);
if (next >= this.mask.length) {
this.fireEvent('maskComplete', this, this.mask);
}
}
}
e.stopEvent();
}
}
},
onPaste: function (e) {
if (this.mask && !this.readOnly) {
(function () { this._cursor(this._checkValueMask(true)); }).defer(10, this);
}
}
});
})();
@sepulchered
Copy link
Author

You can apply this code to triggerfield, but modifications needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment