ax5ui-formatter
Version:
A formatter plugin that works with Bootstrap & jQuery
675 lines (600 loc) • 26.8 kB
JavaScript
"use strict";
// ax5.ui.formatter
(function () {
var UI = ax5.ui;
var U = ax5.util;
var FORMATTER = void 0;
UI.addClass({
className: "formatter"
}, function () {
var TODAY = new Date();
var setSelectionRange = function setSelectionRange(input, pos) {
if (typeof pos == "undefined") {
pos = input.value.length;
}
if (input.setSelectionRange) {
input.focus();
input.setSelectionRange(pos, pos);
} else if (input.createTextRange) {
var range = input.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
} else if (input.selectionStart) {
input.focus();
input.selectionStart = pos;
input.selectionEnd = pos;
}
};
/**
* @class ax5formatter
* @classdesc
* @author tom@axisj.com
* @example
* ```js
* $('#idInputTime').attr('data-ax5formatter', 'time').ax5formatter();
* $('#idInputMoney').attr('data-ax5formatter', 'money').ax5formatter();
* $('#idInputPhone').attr('data-ax5formatter', 'phone').ax5formatter();
* $('#idInputDate').attr('data-ax5formatter', 'date').ax5formatter();
*
* $('#ax5formatter-custom').ax5formatter({
* pattern: "custom",
* getEnterableKeyCodes: function(){
* return {
* '65':'a',
* '66':'b',
* '67':'c',
* '68':'d',
* '69':'e',
* '70':'f'
* };
* },
* getPatternValue: function(obj){
* return obj.value.replace(/./g, "*");
* }
* });
* ```
*/
return function () {
var self = this,
cfg;
this.instanceId = ax5.getGuid();
this.config = {
animateTime: 250
};
this.queue = [];
this.openTimer = null;
this.closeTimer = null;
cfg = this.config;
var formatterEvent = {
'focus': function focus(opts, optIdx, e) {
if (!opts.$input.data("__originValue__")) opts.$input.data("__originValue__", opts.$input.val());
},
/* 키 다운 이벤트에서 입력할 수 없는 키 입력을 방어 */
'keydown': function keydown(opts, optIdx, e) {
var isStop = false;
if (!opts.enterableKeyCodes) {} else if (e.which && opts.enterableKeyCodes[e.which]) {} else if (!e.metaKey && !e.ctrlKey && !e.shiftKey) {
//console.log(e.which, opts.enterableKeyCodes);
isStop = true;
}
if (isStop) ax5.util.stopEvent(e);
},
/* 키 업 이벤트에서 패턴을 적용 */
'keyup': function keyup(opts, optIdx, e) {
var elem = opts.$input.get(0),
elemFocusPosition,
beforeValue,
newValue,
selection,
selectionLength;
if ('selectionStart' in elem) {
// Standard-compliant browsers
elemFocusPosition = elem.selectionStart;
} else if (document.selection) {
// IE
//elem.focus();
selection = document.selection.createRange();
selectionLength = document.selection.createRange().text.length;
selection.moveStart('character', -elem.value.length);
elemFocusPosition = selection.text.length - selectionLength;
}
beforeValue = elem.value;
if (opts.pattern in FORMATTER.formatter) {
newValue = FORMATTER.formatter[opts.pattern].getPatternValue.call(this, opts, optIdx, e, elem.value);
} else {
newValue = beforeValue;
}
if (newValue != beforeValue) {
opts.$input.val(newValue).trigger("change");
setSelectionRange(elem, elemFocusPosition + newValue.length - beforeValue.length);
}
},
'blur': function blur(opts, optIdx, e, _force) {
var elem = opts.$input.get(0),
beforeValue,
newValue;
opts.$input.removeData("__originValue__");
beforeValue = elem.value;
if (opts.pattern in FORMATTER.formatter) {
newValue = FORMATTER.formatter[opts.pattern].getPatternValue.call(this, opts, optIdx, e, elem.value, 'blur');
} else {
newValue = beforeValue;
}
if (_force) {
opts.$input.val(newValue);
} else {
if (newValue != beforeValue) {
opts.$input.val(newValue).trigger("change");
}
}
}
};
var bindFormatterTarget = function bindFormatterTarget(opts, optIdx) {
if (!opts.pattern) {
if (opts.$target.get(0).tagName == "INPUT") {
opts.pattern = opts.$target.attr('data-ax5formatter');
} else {
opts.pattern = opts.$target.find('input[type="text"]').attr('data-ax5formatter');
}
if (!opts.pattern) {
console.log(ax5.info.getError("ax5formatter", "501", "bind"));
console.log(opts.target);
return this;
}
}
var re = /[^\(^\))]+/gi,
matched = opts.pattern.match(re);
opts.pattern = matched[0];
opts.patternArgument = matched[1] || "";
// 함수타입
if (opts.pattern in FORMATTER.formatter) {
opts.enterableKeyCodes = FORMATTER.formatter[opts.pattern].getEnterableKeyCodes.call(this, opts, optIdx);
}
opts.$input.unbind('focus.ax5formatter').bind('focus.ax5formatter', formatterEvent.focus.bind(this, this.queue[optIdx], optIdx));
opts.$input.unbind('keydown.ax5formatter').bind('keydown.ax5formatter', formatterEvent.keydown.bind(this, this.queue[optIdx], optIdx));
opts.$input.unbind('keyup.ax5formatter').bind('keyup.ax5formatter', formatterEvent.keyup.bind(this, this.queue[optIdx], optIdx));
opts.$input.unbind('blur.ax5formatter').bind('blur.ax5formatter', formatterEvent.blur.bind(this, this.queue[optIdx], optIdx));
formatterEvent.blur.call(this, this.queue[optIdx], optIdx);
return this;
};
var getQueIdx = function getQueIdx(boundID) {
if (!U.isString(boundID)) {
boundID = jQuery(boundID).data("data-formatter");
}
/*
if (!U.isString(boundID)) {
console.log(ax5.info.getError("ax5formatter", "402", "getQueIdx"));
return;
}
*/
return U.search(this.queue, function () {
return this.id == boundID;
});
};
/**
* Preferences of formatter UI
* @method ax5formatter.setConfig
* @param {Object} config - 클래스 속성값
* @returns {ax5.ui.formatter}
* @example
* ```
* ```
*/
this.init = function () {};
this.bind = function (opts) {
var formatterConfig = {},
optIdx = void 0;
jQuery.extend(true, formatterConfig, cfg);
if (opts) jQuery.extend(true, formatterConfig, opts);
opts = formatterConfig;
if (!opts.target) {
console.log(ax5.info.getError("ax5formatter", "401", "bind"));
return this;
}
opts.$target = jQuery(opts.target);
if (opts.$target.get(0).tagName == "INPUT") {
opts.$input = opts.$target;
} else {
opts.$input = opts.$target.find('input[type="text"]');
if (opts.$input.length > 1) {
opts.$input.each(function () {
opts.target = this;
self.bind(opts);
});
return this;
}
}
opts.$input = opts.$target.get(0).tagName == "INPUT" ? opts.$target : opts.$target.find('input[type="text"]');
if (!opts.id) opts.id = opts.$input.data("ax5-formatter");
if (!opts.id) {
opts.id = 'ax5-formatter-' + ax5.getGuid();
opts.$input.data("ax5-formatter", opts.id);
}
optIdx = U.search(this.queue, function () {
return this.id == opts.id;
});
if (optIdx === -1) {
this.queue.push(opts);
bindFormatterTarget.call(this, this.queue[this.queue.length - 1], this.queue.length - 1);
} else {
this.queue[optIdx] = opts;
bindFormatterTarget.call(this, this.queue[optIdx], optIdx);
}
return this;
};
/**
* formatter value 를 다시 적용합니다.
* @method ax5formatter.formatting
* @returns {ax5formatter}
* @example
* ```js
* $('[data-ax5formatter="time"]').ax5formatter("formatting"); // 하나만
* $('[data-ax5formatter]').ax5formatter("formatting"); // 모두
* ```
*/
this.formatting = function (boundID) {
var queIdx = U.isNumber(boundID) ? boundID : getQueIdx.call(this, boundID);
if (queIdx === -1) {
var i = this.queue.length;
while (i--) {
formatterEvent.blur.call(this, this.queue[i], i, null, true);
}
} else {
formatterEvent.blur.call(this, this.queue[queIdx], queIdx, null, true);
}
return this;
};
this.unbind = function () {
// 구현해야함.
};
// 클래스 생성자
this.main = function () {
if (arguments && U.isObject(arguments[0])) {
this.setConfig(arguments[0]);
}
}.apply(this, arguments);
};
}());
FORMATTER = ax5.ui.formatter;
})();
// ax5.ui.formatter.formatter
(function () {
var FORMATTER = ax5.ui.formatter;
var U = ax5.util;
var TODAY = new Date();
var ctrlKeys = {
"18": "KEY_ALT",
"8": "KEY_BACKSPACE",
"17": "KEY_CONTROL",
"46": "KEY_DELETE",
"40": "KEY_DOWN",
"35": "KEY_END",
"187": "KEY_EQUAL",
"27": "KEY_ESC",
"36": "KEY_HOME",
"45": "KEY_INSERT",
"37": "KEY_LEFT",
"189": "KEY_MINUS",
"34": "KEY_PAGEDOWN",
"33": "KEY_PAGEUP",
// "190": "KEY_PERIOD",
"13": "KEY_RETURN",
"39": "KEY_RIGHT",
"16": "KEY_SHIFT",
// "32": "KEY_SPACE",
"9": "KEY_TAB",
"38": "KEY_UP",
"91": "KEY_WINDOW"
//"107" : "NUMPAD_ADD",
//"194" : "NUMPAD_COMMA",
//"110" : "NUMPAD_DECIMAL",
//"111" : "NUMPAD_DIVIDE",
//"12" : "NUMPAD_EQUAL",
//"106" : "NUMPAD_MULTIPLY",
//"109" : "NUMPAD_SUBTRACT"
};
var numKeys = {
'48': 1, '49': 1, '50': 1, '51': 1, '52': 1, '53': 1, '54': 1, '55': 1, '56': 1, '57': 1,
'96': 1, '97': 1, '98': 1, '99': 1, '100': 1, '101': 1, '102': 1, '103': 1, '104': 1, '105': 1
};
var pattern_money = {
getEnterableKeyCodes: function getEnterableKeyCodes(_opts) {
var enterableKeyCodes = {
'188': ','
};
if (_opts.patternArgument == "int") {
// 소수점 입력 안됨
} else {
enterableKeyCodes['190'] = "."; // 소수점 입력 허용
}
return jQuery.extend(enterableKeyCodes, FORMATTER.formatter.ctrlKeys, FORMATTER.formatter.numKeys);
},
getPatternValue: function getPatternValue(_opts, optIdx, e, val, eType) {
val = val.replace(/[^0-9^\.^\-]/g, "");
var regExpPattern = new RegExp('([0-9])([0-9][0-9][0-9][,.])'),
arrNumber = val.split('.'),
returnValue;
arrNumber[0] += '.';
do {
arrNumber[0] = arrNumber[0].replace(regExpPattern, '$1,$2');
} while (regExpPattern.test(arrNumber[0]));
if (arrNumber.length > 1) {
if (U.isNumber(_opts.maxRound)) {
returnValue = arrNumber[0] + U.left(arrNumber[1], _opts.maxRound);
} else {
returnValue = arrNumber.join('');
}
} else {
returnValue = arrNumber[0].split('.')[0];
}
return returnValue;
}
};
var pattern_number = {
getEnterableKeyCodes: function getEnterableKeyCodes(_opts) {
var enterableKeyCodes = {
'190': '.',
'110': '.'
};
return jQuery.extend(enterableKeyCodes, FORMATTER.formatter.ctrlKeys, FORMATTER.formatter.numKeys);
},
getPatternValue: function getPatternValue(_opts, optIdx, e, val, eType) {
val = val.replace(/[^0-9^\.^\-]/g, "");
var arrNumber = val.split('.'),
returnValue;
arrNumber[0] += ".";
if (arrNumber.length > 1) {
if (U.isNumber(_opts.maxRound)) {
returnValue = arrNumber[0] + U.left(arrNumber[1], _opts.maxRound);
} else {
returnValue = arrNumber.join('');
}
} else {
returnValue = arrNumber[0].split('.')[0];
}
return returnValue;
}
};
var pattern_date = {
getEnterableKeyCodes: function getEnterableKeyCodes(_opts) {
var enterableKeyCodes = {
'189': '-', '191': '/'
};
return jQuery.extend(enterableKeyCodes, FORMATTER.formatter.ctrlKeys, FORMATTER.formatter.numKeys);
},
getPatternValue: function getPatternValue(_opts, optIdx, e, val, eType) {
val = val.replace(/\D/g, "");
if (val == "") return val;
var regExpPattern = /^([0-9]{4})\-?([0-9]{1,2})?\-?([0-9]{1,2})?.*$/;
if (_opts.patternArgument == "time") {
regExpPattern = /^([0-9]{4})\-?([0-9]{1,2})?\-?([0-9]{1,2})? ?([0-9]{1,2})?:?([0-9]{1,2})?:?([0-9]{1,2})?.*$/;
} else if (_opts.patternArgument == "year") {
regExpPattern = /^([0-9]{0,4})?.*$/;
} else if (_opts.patternArgument == "month") {
regExpPattern = /^([0-9]{4})\-?([0-9]{1,2})?.*$/;
}
var matchedPattern = val.match(regExpPattern),
returnValue = "",
inspectValue = function inspectValue(val, format, inspect, data) {
var _val = {
'Y': function Y(v) {
if (typeof v == "undefined") v = TODAY.getFullYear();
if (v == '' || v == '0000') v = TODAY.getFullYear();
return v.length < 4 ? U.setDigit(v, 4) : v;
},
'M': function M(v) {
if (typeof v == "undefined") v = TODAY.getMonth() + 1;
return v > 12 ? 12 : v == 0 ? '01' : U.setDigit(v, 2);
},
'D': function D(v) {
if (typeof v == "undefined") v = TODAY.getDate() + 1;
var dLen = U.daysOfMonth(data[1], data[2] - 1);
return v > dLen ? dLen : v == 0 ? '01' : U.setDigit(v, 2);
},
'h': function h(v) {
if (!v) v = 0;
return v > 23 ? 23 : U.setDigit(v, 2);
},
'm': function m(v) {
if (!v) v = 0;
return v > 59 ? 59 : U.setDigit(v, 2);
},
's': function s(v) {
if (!v) v = 0;
return v > 59 ? 59 : U.setDigit(v, 2);
}
};
return inspect ? _val[format](val) : val;
};
returnValue = val.replace(regExpPattern, function (a, b) {
var nval = [];
if (_opts.patternArgument == "year") {
nval.push(inspectValue(arguments[1], "Y", eType));
} else if (_opts.patternArgument == "month") {
nval.push(inspectValue(arguments[1], "Y", eType));
if (arguments[2] || eType) nval.push('-' + inspectValue(arguments[2], "M", eType));
} else if (_opts.patternArgument == "time") {
nval.push(inspectValue(arguments[1], "Y", eType));
if (arguments[2] || eType) nval.push('-' + inspectValue(arguments[2], "M", eType));
if (arguments[3] || eType) nval.push('-' + inspectValue(arguments[3], "D", eType, arguments));
if (arguments[4] || eType) nval.push(' ' + inspectValue(arguments[4], "h", eType));
if (arguments[5] || eType) nval.push(':' + inspectValue(arguments[5], "m", eType));
if (arguments[6] || eType) nval.push(':' + inspectValue(arguments[6], "s", eType));
} else {
nval.push(inspectValue(arguments[1], "Y", eType));
if (arguments[2] || eType) nval.push('-' + inspectValue(arguments[2], "M", eType));
if (arguments[3] || eType) nval.push('-' + inspectValue(arguments[3], "D", eType, arguments));
}
return nval.join('');
});
if (eType == 'blur' && !matchedPattern) {
returnValue = function () {
var nval = [];
if (_opts.patternArgument == "year") {
nval.push(inspectValue(0, "Y", eType));
} else if (_opts.patternArgument == "month") {
nval.push(inspectValue(0, "Y", eType));
nval.push('-' + inspectValue(0, "M", eType));
} else if (_opts.patternArgument == "time") {
nval.push(inspectValue(0, "Y", eType));
nval.push('-' + inspectValue(0, "M", eType));
nval.push('-' + inspectValue(0, "D", eType, arguments));
nval.push(' ' + inspectValue(0, "h", eType));
nval.push(':' + inspectValue(0, "m", eType));
nval.push(':' + inspectValue(0, "s", eType));
} else {
nval.push(inspectValue(0, "Y", eType));
nval.push('-' + inspectValue(0, "M", eType));
nval.push('-' + inspectValue(0, "D", eType, arguments));
}
return nval.join('');
}();
} else if (!matchedPattern) returnValue = returnValue.length > 4 ? U.left(returnValue, 4) : returnValue;
return returnValue;
}
};
var pattern_time = {
getEnterableKeyCodes: function getEnterableKeyCodes(_opts) {
var enterableKeyCodes = {
'186': ':'
};
return jQuery.extend(enterableKeyCodes, FORMATTER.formatter.ctrlKeys, FORMATTER.formatter.numKeys);
},
getPatternValue: function getPatternValue(_opts, optIdx, e, val, eType) {
val = val.replace(/\D/g, "");
var regExpPattern = /^([0-9]{1,2})?:?([0-9]{1,2})?:?([0-9]{1,2})?.*$/;
var matchedPattern = val.match(regExpPattern),
returnValue = val.replace(regExpPattern, function (a, b) {
var nval = [arguments[1]];
if (arguments[2]) nval.push(':' + arguments[2]);
if (arguments[3]) nval.push(':' + arguments[3]);
return nval.join('');
});
if (!matchedPattern) returnValue = returnValue.length > 2 ? U.left(returnValue, 2) : returnValue;
return returnValue;
}
};
var pattern_bizno = {
getEnterableKeyCodes: function getEnterableKeyCodes(_opts) {
var enterableKeyCodes = {
'189': '-'
};
return jQuery.extend(enterableKeyCodes, FORMATTER.formatter.ctrlKeys, FORMATTER.formatter.numKeys);
},
getPatternValue: function getPatternValue(_opts, optIdx, e, val, eType) {
val = val.replace(/\D/g, "");
var regExpPattern = /^([0-9]{3})\-?([0-9]{1,2})?\-?([0-9]{1,5})?.*$/,
returnValue = val.replace(regExpPattern, function (a, b) {
var nval = [arguments[1]];
if (arguments[2]) nval.push(arguments[2]);
if (arguments[3]) nval.push(arguments[3]);
return nval.join("-");
});
return returnValue;
}
};
var pattern_phone = {
getEnterableKeyCodes: function getEnterableKeyCodes(_opts) {
var enterableKeyCodes = {
'189': '-', '188': ','
};
return jQuery.extend(enterableKeyCodes, FORMATTER.formatter.ctrlKeys, FORMATTER.formatter.numKeys);
},
getPatternValue: function getPatternValue(_opts, optIdx, e, val, eType) {
val = val.replace(/\D/g, "");
var regExpPattern3 = /^([0-9]{3})\-?([0-9]{1,4})?\-?([0-9]{1,4})?\-?([0-9]{1,4})?\-?([0-9]{1,4})?/;
if (val.substr(0, 2) == "02") {
regExpPattern3 = /^([0-9]{2})\-?([0-9]{1,4})?\-?([0-9]{1,4})?\-?([0-9]{1,4})?\-?([0-9]{1,4})?/;
}
var returnValue = val.replace(regExpPattern3, function (a, b) {
var nval = [arguments[1]];
if (arguments[2]) nval.push(arguments[2]);
if (arguments[3]) nval.push(arguments[3]);
if (arguments[4]) nval.push(arguments[4]);
if (arguments[5]) nval.push(arguments[5]);
return nval.join("-");
});
return returnValue;
}
};
var pattern_credit = {
getEnterableKeyCodes: function getEnterableKeyCodes(_opts) {
var enterableKeyCodes = {
'189': '-'
};
return jQuery.extend(enterableKeyCodes, FORMATTER.formatter.ctrlKeys, FORMATTER.formatter.numKeys);
},
getPatternValue: function getPatternValue(_opts, optIdx, e, val, eType) {
val = val.replace(/\D/g, "").substring(0, 16);
var regExpPattern3 = /^([0-9]{4})\-?([0-9]{4})?\-?([0-9]{4})?\-?([0-9]{4})?/,
returnValue = val.replace(regExpPattern3, function (a, b) {
var nval = [arguments[1]];
if (arguments[2]) nval.push(arguments[2]);
if (arguments[3]) nval.push(arguments[3]);
if (arguments[4]) nval.push(arguments[4]);
return nval.join("-");
});
return returnValue;
}
};
var pattern_custom = {
getEnterableKeyCodes: function getEnterableKeyCodes(_opts) {
if (_opts.getEnterableKeyCodes) {
return _opts.getEnterableKeyCodes.call(_opts, { $input: _opts.$input });
} else {
return null;
}
},
getPatternValue: function getPatternValue(_opts, optIdx, e, val, eType) {
if (_opts.getPatternValue) {
return _opts.getPatternValue.call(_opts, { event: e, $input: _opts.$input, value: val });
}
}
};
FORMATTER.formatter = {
ctrlKeys: ctrlKeys,
numKeys: numKeys,
money: pattern_money,
number: pattern_number,
date: pattern_date,
time: pattern_time,
bizno: pattern_bizno,
phone: pattern_phone,
credit: pattern_credit,
custom: pattern_custom
};
})();
/*
* Copyright (c) 2017. tom@axisj.com
* - github.com/thomasjang
* - www.axisj.com
*/
ax5.ui.formatter_instance = new ax5.ui.formatter();
jQuery.fn.ax5formatter = function () {
return function (config) {
if (ax5.util.isString(arguments[0])) {
var methodName = arguments[0];
switch (methodName) {
case "formatting":
return ax5.ui.formatter_instance.formatting(this);
break;
case "unbind":
return ax5.ui.formatter_instance.unbind(this);
break;
default:
return this;
}
} else {
if (typeof config == "undefined") config = {};
jQuery.each(this, function () {
var defaultConfig = {
target: this
};
config = jQuery.extend({}, config, defaultConfig);
ax5.ui.formatter_instance.bind(config);
});
}
return this;
};
}();