jquery.inputmask-multi.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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. (function (factory) {
  9. if (typeof define === 'function' && define.amd) {
  10. // AMD. Register as an anonymous module.
  11. define("jquery.inputmask-multi", ['jquery', 'jquery.inputmask'], factory);
  12. } else {
  13. // Browser globals
  14. factory(jQuery);
  15. }
  16. }(function ($) {
  17. if ($.fn.inputmask != undefined) {
  18. function multiMaskScope(actionObj, masksets, opts) {
  19. function isInputEventSupported(eventName) {
  20. var el = document.createElement('input'),
  21. eventName = 'on' + eventName,
  22. isSupported = (eventName in el);
  23. if (!isSupported) {
  24. el.setAttribute(eventName, 'return;');
  25. isSupported = typeof el[eventName] == 'function';
  26. }
  27. el = null;
  28. return isSupported;
  29. }
  30. var PasteEventType = isInputEventSupported('paste') ? 'paste' : isInputEventSupported('input') ? 'input' : "propertychange",
  31. isRTL, el, $el, elmasks, activeMasksetIndex;
  32. function PatchValhookMulti(type) {
  33. if ($.valHooks[type] == undefined || $.valHooks[type].inputmaskmultipatch != true) {
  34. var valueGet = $.valHooks[type] && $.valHooks[type].get ? $.valHooks[type].get : function (elem) { return elem.value; };
  35. var valueSet = $.valHooks[type] && $.valHooks[type].set ? $.valHooks[type].set : function (elem, value) {
  36. elem.value = value;
  37. return elem;
  38. };
  39. $.valHooks[type] = {
  40. get: function (elem) {
  41. var $elem = $(elem);
  42. if ($elem.data('_inputmask-multi')) {
  43. var data = $elem.data('_inputmask-multi');
  44. return valueGet(data["elmasks"][data["activeMasksetIndex"]]);
  45. } else return valueGet(elem);
  46. },
  47. set: function (elem, value) {
  48. var $elem = $(elem);
  49. var result = valueSet(elem, value);
  50. if ($elem.data('_inputmask-multi')) $elem.triggerHandler('setvalue');
  51. return result;
  52. },
  53. inputmaskmultipatch: true
  54. };
  55. }
  56. }
  57. function mcaret(input, begin, end) {
  58. var npt = input.jquery && input.length > 0 ? input[0] : input, range;
  59. if (typeof begin == 'number') {
  60. begin = TranslatePosition(begin);
  61. end = TranslatePosition(end);
  62. end = (typeof end == 'number') ? end : begin;
  63. //store caret for multi scope
  64. if (npt != el) {
  65. var data = $(npt).data('_inputmask') || {};
  66. data["caret"] = { "begin": begin, "end": end };
  67. $(npt).data('_inputmask', data);
  68. }
  69. if (!$(npt).is(":visible")) {
  70. return;
  71. }
  72. npt.scrollLeft = npt.scrollWidth;
  73. if (opts.insertMode == false && begin == end) end++; //set visualization for insert/overwrite mode
  74. if (npt.setSelectionRange) {
  75. npt.selectionStart = begin;
  76. npt.selectionEnd = end;
  77. } else if (npt.createTextRange) {
  78. range = npt.createTextRange();
  79. range.collapse(true);
  80. range.moveEnd('character', end);
  81. range.moveStart('character', begin);
  82. range.select();
  83. }
  84. } else {
  85. var data = $(npt).data('_inputmask');
  86. if (!$(npt).is(":visible") && data && data["caret"] != undefined) {
  87. begin = data["caret"]["begin"];
  88. end = data["caret"]["end"];
  89. } else if (npt.setSelectionRange) {
  90. begin = npt.selectionStart;
  91. end = npt.selectionEnd;
  92. } else if (document.selection && document.selection.createRange) {
  93. range = document.selection.createRange();
  94. begin = 0 - range.duplicate().moveStart('character', -100000);
  95. end = begin + range.text.length;
  96. }
  97. begin = TranslatePosition(begin);
  98. end = TranslatePosition(end);
  99. return { "begin": begin, "end": end };
  100. }
  101. }
  102. function TranslatePosition(pos) {
  103. if (isRTL && typeof pos == 'number' && (!opts.greedy || opts.placeholder != "")) {
  104. var bffrLght = el.value.length;
  105. pos = bffrLght - pos;
  106. }
  107. return pos;
  108. }
  109. function determineActiveMask(eventType, elmasks) {
  110. if (eventType != "multiMaskScope") {
  111. if ($.isFunction(opts.determineActiveMasksetIndex))
  112. activeMasksetIndex = opts.determineActiveMasksetIndex.call($el, eventType, elmasks);
  113. else {
  114. var lpc = -1, cp = -1, lvp = -1;;
  115. $.each(elmasks, function (ndx, lmsk) {
  116. var data = $(lmsk).data('_inputmask');
  117. var maskset = data["maskset"];
  118. var lastValidPosition = -1, validPositionCount = 0, caretPos = mcaret(lmsk).begin;
  119. for (var posNdx in maskset["validPositions"]) {
  120. var psNdx = parseInt(posNdx);
  121. if (psNdx > lastValidPosition) lastValidPosition = psNdx;
  122. validPositionCount++;
  123. }
  124. if (validPositionCount > lpc
  125. || (validPositionCount == lpc && cp > caretPos && lvp > lastValidPosition)
  126. || (validPositionCount == lpc && cp == caretPos && lvp < lastValidPosition)
  127. ) {
  128. //console.log("lvp " + lastValidPosition + " vpc " + validPositionCount + " caret " + caretPos + " ams " + ndx);
  129. lpc = validPositionCount;
  130. cp = caretPos;
  131. activeMasksetIndex = ndx;
  132. lvp = lastValidPosition;
  133. }
  134. });
  135. }
  136. var data = $el.data('_inputmask-multi') || { "activeMasksetIndex": 0, "elmasks": elmasks };
  137. data["activeMasksetIndex"] = activeMasksetIndex;
  138. $el.data('_inputmask-multi', data);
  139. }
  140. if ($.inArray(eventType, ["focus"]) == -1 && el.value != elmasks[activeMasksetIndex]._valueGet()) {
  141. var value = $(elmasks[activeMasksetIndex]).val() == "" ? elmasks[activeMasksetIndex]._valueGet() : $(elmasks[activeMasksetIndex]).val();
  142. el.value = value;
  143. }
  144. if ($.inArray(eventType, ["blur", "focus"]) == -1) {
  145. if ($(elmasks[activeMasksetIndex]).hasClass("focus-inputmask")) {
  146. var activeCaret = mcaret(elmasks[activeMasksetIndex]);
  147. mcaret(el, activeCaret.begin, activeCaret.end);
  148. }
  149. }
  150. }
  151. opts.multi = true;
  152. function mask(npt) {
  153. el = npt;
  154. $el = $(el);
  155. isRTL = el.dir == "rtl" || opts.numericInput;
  156. activeMasksetIndex = 0;
  157. elmasks = $.map(masksets, function (msk, ndx) {
  158. var elMaskStr = '<input type="text" ';
  159. if ($el.attr("value")) elMaskStr += 'value="' + $el.attr("value") + '" ';
  160. if ($el.attr("dir")) elMaskStr += 'dir="' + $el.attr("dir") + '" ';
  161. elMaskStr += '/>';
  162. var elmask = $(elMaskStr)[0];
  163. $(elmask).inputmask($.extend({}, opts, { mask: msk.mask }));
  164. return elmask;
  165. });
  166. $el.data('_inputmask-multi', { "activeMasksetIndex": 0, "elmasks": elmasks });
  167. if (el.dir == "rtl" || opts.rightAlign)
  168. $el.css("text-align", "right");
  169. el.dir = "ltr";
  170. $el.removeAttr("dir");
  171. if ($el.attr("value") != "") {
  172. determineActiveMask("init", elmasks);
  173. }
  174. $el.bind("mouseenter blur focus mouseleave click dblclick keydown keypress keypress", function (e) {
  175. var caretPos = mcaret(el), k, goDetermine = true;
  176. if (e.type == "keydown") {
  177. k = e.keyCode;
  178. if (k == opts.keyCode.DOWN && activeMasksetIndex < elmasks.length - 1) {
  179. activeMasksetIndex++;
  180. determineActiveMask("multiMaskScope", elmasks);
  181. return false;
  182. } else if (k == opts.keyCode.UP && activeMasksetIndex > 0) {
  183. activeMasksetIndex--;
  184. determineActiveMask("multiMaskScope", elmasks);
  185. return false;
  186. }
  187. if (e.ctrlKey || k == opts.keyCode.SHIFT || e.altKey) {
  188. return true;
  189. }
  190. } else if (e.type == "keypress" && (e.ctrlKey || k == opts.keyCode.SHIFT || e.altKey)) {
  191. return true;
  192. }
  193. $.each(elmasks, function (ndx, lmnt) {
  194. if (e.type == "keydown") {
  195. k = e.keyCode;
  196. if (k == opts.keyCode.BACKSPACE && lmnt._valueGet().length < caretPos.begin) {
  197. return;
  198. } else if (k == opts.keyCode.TAB) {
  199. goDetermine = false;
  200. } else if (k == opts.keyCode.RIGHT) {
  201. mcaret(lmnt, caretPos.begin + 1, caretPos.end + 1);
  202. goDetermine = false;
  203. return;
  204. } else if (k == opts.keyCode.LEFT) {
  205. mcaret(lmnt, caretPos.begin - 1, caretPos.end - 1);
  206. goDetermine = false;
  207. return;
  208. }
  209. }
  210. if ($.inArray(e.type, ["click"]) != -1) {
  211. mcaret(lmnt, TranslatePosition(caretPos.begin), TranslatePosition(caretPos.end));
  212. if (caretPos.begin != caretPos.end) {
  213. goDetermine = false;
  214. return;
  215. }
  216. }
  217. if ($.inArray(e.type, ["keydown"]) != -1 && caretPos.begin != caretPos.end) {
  218. mcaret(lmnt, caretPos.begin, caretPos.end);
  219. }
  220. $(lmnt).triggerHandler(e);
  221. });
  222. if (goDetermine) {
  223. setTimeout(function () {
  224. determineActiveMask(e.type, elmasks);
  225. }, 0);
  226. }
  227. });
  228. $el.bind(PasteEventType + " dragdrop drop setvalue", function (e) {
  229. var caretPos = mcaret(el);
  230. setTimeout(function () {
  231. $.each(elmasks, function (ndx, lmnt) {
  232. lmnt._valueSet(el.value);
  233. $(lmnt).triggerHandler(e);
  234. });
  235. setTimeout(function () {
  236. determineActiveMask(e.type, elmasks);
  237. }, 0);
  238. }, 0);
  239. });
  240. PatchValhookMulti(el.type);
  241. }
  242. //action object
  243. if (actionObj != undefined) {
  244. switch (actionObj["action"]) {
  245. case "isComplete":
  246. $el = $(actionObj["el"]);
  247. var imdata = $el.data('_inputmask-multi'),
  248. activeMask = imdata["elmasks"][imdata["activeMasksetIndex"]];
  249. return $(activeMask).inputmask("isComplete");
  250. case "unmaskedvalue":
  251. $el = actionObj["$input"];
  252. var imdata = $el.data('_inputmask-multi'),
  253. activeMask = imdata["elmasks"][imdata["activeMasksetIndex"]];
  254. return $(activeMask).inputmask("unmaskedvalue");
  255. case "mask":
  256. mask(actionObj["el"]);
  257. break;
  258. case "remove": //TODO
  259. var el = actionObj["el"];
  260. $el = $(el);
  261. maskset = $el.data('_inputmask')['maskset'];
  262. opts = $el.data('_inputmask')['opts'];
  263. //writeout the unmaskedvalue
  264. el._valueSet(unmaskedvalue($el));
  265. //unbind all events
  266. $el.unbind(".inputmask");
  267. $el.removeClass('focus-inputmask');
  268. //clear data
  269. $el.removeData('_inputmask');
  270. //restore the value property
  271. var valueProperty;
  272. if (Object.getOwnPropertyDescriptor)
  273. valueProperty = Object.getOwnPropertyDescriptor(el, "value");
  274. if (valueProperty && valueProperty.get) {
  275. if (el._valueGet) {
  276. Object.defineProperty(el, "value", {
  277. get: el._valueGet,
  278. set: el._valueSet
  279. });
  280. }
  281. } else if (document.__lookupGetter__ && el.__lookupGetter__("value")) {
  282. if (el._valueGet) {
  283. el.__defineGetter__("value", el._valueGet);
  284. el.__defineSetter__("value", el._valueSet);
  285. }
  286. }
  287. try { //try catch needed for IE7 as it does not supports deleting fns
  288. delete el._valueGet;
  289. delete el._valueSet;
  290. } catch (e) {
  291. el._valueGet = undefined;
  292. el._valueSet = undefined;
  293. }
  294. break;
  295. }
  296. }
  297. };
  298. $.extend($.inputmask.defaults, {
  299. //multi-masks
  300. multi: false, //do not alter - internal use
  301. determineActiveMasksetIndex: undefined //override determineActiveMasksetIndex - args => eventType, elmasks - return int
  302. });
  303. $.inputmask._fn = $.fn.inputmask;
  304. $.fn.inputmask = function (fn, options) {
  305. if (typeof fn === "string") {
  306. if ($.inputmask._fn("_detectScope", options, undefined, undefined, fn))
  307. return $.inputmask._fn.call(this, fn, options, multiMaskScope, "_inputmask-multi");
  308. else return $.inputmask._fn.call(this, fn, options);
  309. } else if (typeof fn == "object") {
  310. if ($.inputmask._fn("_detectScope", fn))
  311. return $.inputmask._fn.call(this, fn, options, multiMaskScope, "_inputmask-multi");
  312. else return $.inputmask._fn.call(this, fn, options);
  313. } else if (fn == undefined)
  314. return $.inputmask._fn.call(this, fn, options);
  315. };
  316. }
  317. }));