vanilla-masker.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. (function(root, factory) {
  2. if (typeof define === 'function' && define.amd) {
  3. define(factory);
  4. } else if (typeof exports === 'object') {
  5. module.exports = factory();
  6. } else {
  7. root.VMasker = factory();
  8. }
  9. }(this, function() {
  10. var DIGIT = "9",
  11. ALPHA = "A",
  12. ALPHANUM = "S",
  13. BY_PASS_KEYS = [9, 16, 17, 18, 36, 37, 38, 39, 40, 91, 92, 93],
  14. isAllowedKeyCode = function(keyCode) {
  15. for (var i = 0, len = BY_PASS_KEYS.length; i < len; i++) {
  16. if (keyCode == BY_PASS_KEYS[i]) {
  17. return false;
  18. }
  19. }
  20. return true;
  21. },
  22. mergeMoneyOptions = function(opts) {
  23. opts = opts || {};
  24. opts = {
  25. delimiter: opts.delimiter || ".",
  26. lastOutput: opts.lastOutput,
  27. precision: opts.hasOwnProperty("precision") ? opts.precision : 2,
  28. separator: opts.separator || ",",
  29. showSignal: opts.showSignal,
  30. suffixUnit: opts.suffixUnit && (" " + opts.suffixUnit.replace(/[\s]/g,'')) || "",
  31. unit: opts.unit && (opts.unit.replace(/[\s]/g,'') + " ") || "",
  32. zeroCents: opts.zeroCents
  33. };
  34. opts.moneyPrecision = opts.zeroCents ? 0 : opts.precision;
  35. return opts;
  36. },
  37. // Fill wildcards past index in output with placeholder
  38. addPlaceholdersToOutput = function(output, index, placeholder) {
  39. for (; index < output.length; index++) {
  40. if(output[index] === DIGIT || output[index] === ALPHA || output[index] === ALPHANUM) {
  41. output[index] = placeholder;
  42. }
  43. }
  44. return output;
  45. }
  46. ;
  47. var VanillaMasker = function(elements) {
  48. this.elements = elements;
  49. };
  50. VanillaMasker.prototype.unbindElementToMask = function() {
  51. for (var i = 0, len = this.elements.length; i < len; i++) {
  52. this.elements[i].lastOutput = "";
  53. this.elements[i].onkeyup = false;
  54. this.elements[i].onkeydown = false;
  55. if (this.elements[i].value.length) {
  56. this.elements[i].value = this.elements[i].value.replace(/\D/g, '');
  57. }
  58. }
  59. };
  60. VanillaMasker.prototype.bindElementToMask = function(maskFunction) {
  61. var that = this,
  62. onType = function(e) {
  63. e = e || window.event;
  64. var source = e.target || e.srcElement;
  65. if (isAllowedKeyCode(e.keyCode)) {
  66. setTimeout(function() {
  67. that.opts.lastOutput = source.lastOutput;
  68. source.value = VMasker[maskFunction](source.value, that.opts);
  69. source.lastOutput = source.value;
  70. if (source.setSelectionRange && that.opts.suffixUnit) {
  71. source.setSelectionRange(source.value.length, (source.value.length - that.opts.suffixUnit.length));
  72. }
  73. }, 0);
  74. }
  75. }
  76. ;
  77. for (var i = 0, len = this.elements.length; i < len; i++) {
  78. this.elements[i].lastOutput = "";
  79. this.elements[i].onkeyup = onType;
  80. if (this.elements[i].value.length) {
  81. this.elements[i].value = VMasker[maskFunction](this.elements[i].value, this.opts);
  82. }
  83. }
  84. };
  85. VanillaMasker.prototype.maskMoney = function(opts) {
  86. this.opts = mergeMoneyOptions(opts);
  87. this.bindElementToMask("toMoney");
  88. };
  89. VanillaMasker.prototype.maskNumber = function() {
  90. this.opts = {};
  91. this.bindElementToMask("toNumber");
  92. };
  93. VanillaMasker.prototype.maskAlphaNum = function() {
  94. this.opts = {};
  95. this.bindElementToMask("toAlphaNumeric");
  96. };
  97. VanillaMasker.prototype.maskPattern = function(pattern) {
  98. this.opts = {pattern: pattern};
  99. this.bindElementToMask("toPattern");
  100. };
  101. VanillaMasker.prototype.unMask = function() {
  102. this.unbindElementToMask();
  103. };
  104. var VMasker = function(el) {
  105. if (!el) {
  106. throw new Error("VanillaMasker: There is no element to bind.");
  107. }
  108. var elements = ("length" in el) ? (el.length ? el : []) : [el];
  109. return new VanillaMasker(elements);
  110. };
  111. VMasker.toMoney = function(value, opts) {
  112. opts = mergeMoneyOptions(opts);
  113. if (opts.zeroCents) {
  114. opts.lastOutput = opts.lastOutput || "";
  115. var zeroMatcher = ("("+ opts.separator +"[0]{0,"+ opts.precision +"})"),
  116. zeroRegExp = new RegExp(zeroMatcher, "g"),
  117. digitsLength = value.toString().replace(/[\D]/g, "").length || 0,
  118. lastDigitLength = opts.lastOutput.toString().replace(/[\D]/g, "").length || 0
  119. ;
  120. value = value.toString().replace(zeroRegExp, "");
  121. if (digitsLength < lastDigitLength) {
  122. value = value.slice(0, value.length - 1);
  123. }
  124. }
  125. var number = value.toString().replace(/[\D]/g, ""),
  126. clearDelimiter = new RegExp("^(0|\\"+ opts.delimiter +")"),
  127. clearSeparator = new RegExp("(\\"+ opts.separator +")$"),
  128. money = number.substr(0, number.length - opts.moneyPrecision),
  129. masked = money.substr(0, money.length % 3),
  130. cents = new Array(opts.precision + 1).join("0")
  131. ;
  132. money = money.substr(money.length % 3, money.length);
  133. for (var i = 0, len = money.length; i < len; i++) {
  134. if (i % 3 === 0) {
  135. masked += opts.delimiter;
  136. }
  137. masked += money[i];
  138. }
  139. masked = masked.replace(clearDelimiter, "");
  140. masked = masked.length ? masked : "0";
  141. var signal = "";
  142. if(opts.showSignal === true) {
  143. signal = value < 0 || (value.startsWith && value.startsWith('-')) ? "-" : "";
  144. }
  145. if (!opts.zeroCents) {
  146. var beginCents = number.length - opts.precision,
  147. centsValue = number.substr(beginCents, opts.precision),
  148. centsLength = centsValue.length,
  149. centsSliced = (opts.precision > centsLength) ? opts.precision : centsLength
  150. ;
  151. cents = (cents + centsValue).slice(-centsSliced);
  152. }
  153. var output = opts.unit + signal + masked + opts.separator + cents;
  154. return output.replace(clearSeparator, "") + opts.suffixUnit;
  155. };
  156. VMasker.toPattern = function(value, opts) {
  157. var pattern = (typeof opts === 'object' ? opts.pattern : opts),
  158. patternChars = pattern.replace(/\W/g, ''),
  159. output = pattern.split(""),
  160. values = value.toString().replace(/\W/g, ""),
  161. charsValues = values.replace(/\W/g, ''),
  162. index = 0,
  163. i,
  164. outputLength = output.length,
  165. placeholder = (typeof opts === 'object' ? opts.placeholder : undefined)
  166. ;
  167. for (i = 0; i < outputLength; i++) {
  168. // Reached the end of input
  169. if (index >= values.length) {
  170. if (patternChars.length == charsValues.length) {
  171. return output.join("");
  172. }
  173. else if ((placeholder !== undefined) && (patternChars.length > charsValues.length)) {
  174. return addPlaceholdersToOutput(output, i, placeholder).join("");
  175. }
  176. else {
  177. break;
  178. }
  179. }
  180. // Remaining chars in input
  181. else{
  182. if ((output[i] === DIGIT && values[index].match(/[0-9]/)) ||
  183. (output[i] === ALPHA && values[index].match(/[a-zA-Z]/)) ||
  184. (output[i] === ALPHANUM && values[index].match(/[0-9a-zA-Z]/))) {
  185. output[i] = values[index++];
  186. } else if (output[i] === DIGIT || output[i] === ALPHA || output[i] === ALPHANUM) {
  187. if(placeholder !== undefined){
  188. return addPlaceholdersToOutput(output, i, placeholder).join("");
  189. }
  190. else{
  191. return output.slice(0, i).join("");
  192. }
  193. }
  194. }
  195. }
  196. return output.join("").substr(0, i);
  197. };
  198. VMasker.toNumber = function(value) {
  199. return value.toString().replace(/(?!^-)[^0-9]/g, "");
  200. };
  201. VMasker.toAlphaNumeric = function(value) {
  202. return value.toString().replace(/[^a-z0-9 ]+/i, "");
  203. };
  204. return VMasker;
  205. }));