jquery.inputmask-multi.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /**
  2. * @license Input Mask plugin for jquery
  3. * http://github.com/RobinHerbots/jquery.inputmask
  4. * Copyright (c) 2010 - 2014 Robin Herbots
  5. * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
  6. * Version: 0.0.0
  7. *
  8. * THIS IS A TEMPORARY HACK TO BE COMPATIBLE WITH MULTIPLE MASKS LIKE IN VERSION 2.X - WHEN THE ALTERNATOR SYNTAX IS IMPLEMENTED inputmask-multi WILL BE DELETED!!
  9. *
  10. *
  11. */
  12. (function (factory) {
  13. if (typeof define === 'function' && define.amd) {
  14. define("jquery.inputmask-multi", ['jquery', 'jquery.inputmask'], factory);
  15. } else {
  16. factory(jQuery);
  17. }
  18. }(function ($) {
  19. if ($.fn.inputmask != undefined) {
  20. function multiMaskScope(actionObj, masksets, opts) {
  21. function isInputEventSupported(eventName) {
  22. var el = document.createElement('input'),
  23. eventName = 'on' + eventName,
  24. isSupported = (eventName in el);
  25. if (!isSupported) {
  26. el.setAttribute(eventName, 'return;');
  27. isSupported = typeof el[eventName] == 'function';
  28. }
  29. el = null;
  30. return isSupported;
  31. }
  32. var PasteEventType = isInputEventSupported('paste') ? 'paste' : isInputEventSupported('input') ? 'input' : "propertychange",
  33. isRTL, el, $el, elmasks, activeMasksetIndex;
  34. function PatchValhookMulti(type) {
  35. if ($.valHooks[type] == undefined || $.valHooks[type].inputmaskmultipatch != true) {
  36. var valueGet = $.valHooks[type] && $.valHooks[type].get ? $.valHooks[type].get : function (elem) { return elem.value; };
  37. var valueSet = $.valHooks[type] && $.valHooks[type].set ? $.valHooks[type].set : function (elem, value) {
  38. elem.value = value;
  39. return elem;
  40. };
  41. $.valHooks[type] = {
  42. get: function (elem) {
  43. var $elem = $(elem);
  44. if ($elem.data('_inputmask-multi')) {
  45. var data = $elem.data('_inputmask-multi');
  46. return valueGet(data["elmasks"][data["activeMasksetIndex"]]);
  47. } else return valueGet(elem);
  48. },
  49. set: function (elem, value) {
  50. var $elem = $(elem);
  51. var result = valueSet(elem, value);
  52. if ($elem.data('_inputmask-multi')) $elem.triggerHandler('setvalue');
  53. return result;
  54. },
  55. inputmaskmultipatch: true
  56. };
  57. }
  58. }
  59. function mcaret(input, begin, end) {
  60. var npt = input.jquery && input.length > 0 ? input[0] : input, range;
  61. if (typeof begin == 'number') {
  62. begin = TranslatePosition(begin);
  63. end = TranslatePosition(end);
  64. end = (typeof end == 'number') ? end : begin;
  65. //store caret for multi scope
  66. if (npt != el) {
  67. var data = $(npt).data('_inputmask') || {};
  68. data["caret"] = { "begin": begin, "end": end };
  69. $(npt).data('_inputmask', data);
  70. }
  71. if (!$(npt).is(":visible")) {
  72. return;
  73. }
  74. npt.scrollLeft = npt.scrollWidth;
  75. if (opts.insertMode == false && begin == end) end++; //set visualization for insert/overwrite mode
  76. if (npt.setSelectionRange) {
  77. npt.selectionStart = begin;
  78. npt.selectionEnd = end;
  79. } else if (npt.createTextRange) {
  80. range = npt.createTextRange();
  81. range.collapse(true);
  82. range.moveEnd('character', end);
  83. range.moveStart('character', begin);
  84. range.select();
  85. }
  86. } else {
  87. var data = $(npt).data('_inputmask');
  88. if (!$(npt).is(":visible") && data && data["caret"] != undefined) {
  89. begin = data["caret"]["begin"];
  90. end = data["caret"]["end"];
  91. } else if (npt.setSelectionRange) {
  92. begin = npt.selectionStart;
  93. end = npt.selectionEnd;
  94. } else if (document.selection && document.selection.createRange) {
  95. range = document.selection.createRange();
  96. begin = 0 - range.duplicate().moveStart('character', -100000);
  97. end = begin + range.text.length;
  98. }
  99. begin = TranslatePosition(begin);
  100. end = TranslatePosition(end);
  101. return { "begin": begin, "end": end };
  102. }
  103. }
  104. function TranslatePosition(pos) {
  105. if (isRTL && typeof pos == 'number' && (!opts.greedy || opts.placeholder != "")) {
  106. var bffrLght = el.value.length;
  107. pos = bffrLght - pos;
  108. }
  109. return pos;
  110. }
  111. function determineActiveMask(eventType, elmasks) {
  112. if (eventType != "multiMaskScope") {
  113. if ($.isFunction(opts.determineActiveMasksetIndex))
  114. activeMasksetIndex = opts.determineActiveMasksetIndex.call($el, eventType, elmasks);
  115. else {
  116. var lpc = -1, cp = -1, lvp = -1;;
  117. $.each(elmasks, function (ndx, lmsk) {
  118. var data = $(lmsk).data('_inputmask');
  119. var maskset = data["maskset"];
  120. var lastValidPosition = -1, validPositionCount = 0, caretPos = mcaret(lmsk).begin;
  121. for (var posNdx in maskset["validPositions"]) {
  122. var psNdx = parseInt(posNdx);
  123. if (psNdx > lastValidPosition) lastValidPosition = psNdx;
  124. validPositionCount++;
  125. }
  126. if (validPositionCount > lpc
  127. || (validPositionCount == lpc && cp > caretPos && lvp > lastValidPosition)
  128. || (validPositionCount == lpc && cp == caretPos && lvp < lastValidPosition)
  129. ) {
  130. //console.log("lvp " + lastValidPosition + " vpc " + validPositionCount + " caret " + caretPos + " ams " + ndx);
  131. lpc = validPositionCount;
  132. cp = caretPos;
  133. activeMasksetIndex = ndx;
  134. lvp = lastValidPosition;
  135. }
  136. });
  137. }
  138. var data = $el.data('_inputmask-multi') || { "activeMasksetIndex": 0, "elmasks": elmasks };
  139. data["activeMasksetIndex"] = activeMasksetIndex;
  140. $el.data('_inputmask-multi', data);
  141. }
  142. if ($.inArray(eventType, ["focus"]) == -1 && el.value != elmasks[activeMasksetIndex]._valueGet()) {
  143. var value = $(elmasks[activeMasksetIndex]).val() == "" ? elmasks[activeMasksetIndex]._valueGet() : $(elmasks[activeMasksetIndex]).val();
  144. el.value = value;
  145. }
  146. if ($.inArray(eventType, ["blur", "focus"]) == -1) {
  147. if ($(elmasks[activeMasksetIndex]).hasClass("focus-inputmask")) {
  148. var activeCaret = mcaret(elmasks[activeMasksetIndex]);
  149. mcaret(el, activeCaret.begin, activeCaret.end);
  150. }
  151. }
  152. }
  153. opts.multi = true;
  154. function mask(npt) {
  155. el = npt;
  156. $el = $(el);
  157. isRTL = el.dir == "rtl" || opts.numericInput;
  158. activeMasksetIndex = 0;
  159. elmasks = $.map(masksets, function (msk, ndx) {
  160. if (isFinite(ndx)) { //handle extension in the prototype of array for ie8
  161. var elMaskStr = '<input type="text" ';
  162. if ($el.attr("value")) elMaskStr += 'value="' + $el.attr("value") + '" ';
  163. if ($el.attr("dir")) elMaskStr += 'dir="' + $el.attr("dir") + '" ';
  164. elMaskStr += '/>';
  165. var elmask = $(elMaskStr)[0];
  166. $(elmask).inputmask($.extend({}, opts, { mask: msk.mask }));
  167. return elmask;
  168. }
  169. });
  170. $el.data('_inputmask-multi', { "activeMasksetIndex": 0, "elmasks": elmasks });
  171. if (el.dir == "rtl" || opts.rightAlign)
  172. $el.css("text-align", "right");
  173. el.dir = "ltr";
  174. $el.removeAttr("dir");
  175. if ($el.attr("value") != "") {
  176. determineActiveMask("init", elmasks);
  177. }
  178. $el.bind("mouseenter blur focus mouseleave click dblclick keydown keypress keypress", function (e) {
  179. var caretPos = mcaret(el), k, goDetermine = true;
  180. if (e.type == "keydown") {
  181. k = e.keyCode;
  182. if (k == opts.keyCode.DOWN && activeMasksetIndex < elmasks.length - 1) {
  183. activeMasksetIndex++;
  184. determineActiveMask("multiMaskScope", elmasks);
  185. return false;
  186. } else if (k == opts.keyCode.UP && activeMasksetIndex > 0) {
  187. activeMasksetIndex--;
  188. determineActiveMask("multiMaskScope", elmasks);
  189. return false;
  190. }
  191. if (e.ctrlKey || k == opts.keyCode.SHIFT || e.altKey) {
  192. return true;
  193. }
  194. } else if (e.type == "keypress" && (e.ctrlKey || k == opts.keyCode.SHIFT || e.altKey)) {
  195. return true;
  196. }
  197. $.each(elmasks, function (ndx, lmnt) {
  198. if (e.type == "keydown") {
  199. k = e.keyCode;
  200. if (k == opts.keyCode.BACKSPACE && lmnt._valueGet().length < caretPos.begin) {
  201. return;
  202. } else if (k == opts.keyCode.TAB) {
  203. goDetermine = false;
  204. } else if (k == opts.keyCode.RIGHT) {
  205. mcaret(lmnt, caretPos.begin + 1, caretPos.end + 1);
  206. goDetermine = false;
  207. return;
  208. } else if (k == opts.keyCode.LEFT) {
  209. mcaret(lmnt, caretPos.begin - 1, caretPos.end - 1);
  210. goDetermine = false;
  211. return;
  212. }
  213. }
  214. if ($.inArray(e.type, ["click"]) != -1) {
  215. mcaret(lmnt, TranslatePosition(caretPos.begin), TranslatePosition(caretPos.end));
  216. if (caretPos.begin != caretPos.end) {
  217. goDetermine = false;
  218. return;
  219. }
  220. }
  221. if ($.inArray(e.type, ["keydown"]) != -1 && caretPos.begin != caretPos.end) {
  222. mcaret(lmnt, caretPos.begin, caretPos.end);
  223. }
  224. $(lmnt).triggerHandler(e);
  225. });
  226. if (goDetermine) {
  227. setTimeout(function () {
  228. determineActiveMask(e.type, elmasks);
  229. }, 0);
  230. }
  231. });
  232. $el.bind(PasteEventType + " dragdrop drop setvalue", function (e) {
  233. var caretPos = mcaret(el);
  234. setTimeout(function () {
  235. $.each(elmasks, function (ndx, lmnt) {
  236. lmnt._valueSet(el.value);
  237. $(lmnt).triggerHandler(e);
  238. });
  239. setTimeout(function () {
  240. determineActiveMask(e.type, elmasks);
  241. }, 0);
  242. }, 0);
  243. });
  244. PatchValhookMulti(el.type);
  245. }
  246. //action object
  247. if (actionObj != undefined) {
  248. switch (actionObj["action"]) {
  249. case "isComplete":
  250. $el = $(actionObj["el"]);
  251. var imdata = $el.data('_inputmask-multi'),
  252. activeMask = imdata["elmasks"][imdata["activeMasksetIndex"]];
  253. return $(activeMask).inputmask("isComplete");
  254. case "unmaskedvalue":
  255. $el = actionObj["$input"];
  256. var imdata = $el.data('_inputmask-multi'),
  257. activeMask = imdata["elmasks"][imdata["activeMasksetIndex"]];
  258. return $(activeMask).inputmask("unmaskedvalue");
  259. case "mask":
  260. mask(actionObj["el"]);
  261. break;
  262. }
  263. }
  264. };
  265. $.extend($.inputmask.defaults, {
  266. //multi-masks
  267. multi: false, //do not alter - internal use
  268. determineActiveMasksetIndex: undefined //override determineActiveMasksetIndex - args => eventType, elmasks - return int
  269. });
  270. $.inputmask._fn = $.fn.inputmask;
  271. $.fn.inputmask = function (fn, options) {
  272. if (typeof fn === "string") {
  273. if ($.inputmask._fn("_detectScope", options, undefined, undefined, fn))
  274. return $.inputmask._fn.call(this, fn, options, multiMaskScope, "_inputmask-multi");
  275. else return $.inputmask._fn.call(this, fn, options);
  276. } else if (typeof fn == "object") {
  277. if ($.inputmask._fn("_detectScope", fn))
  278. return $.inputmask._fn.call(this, fn, options, multiMaskScope, "_inputmask-multi");
  279. else return $.inputmask._fn.call(this, fn, options);
  280. } else if (fn == undefined)
  281. return $.inputmask._fn.call(this, fn, options);
  282. };
  283. }
  284. }));