Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

jquery.mask.js 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. /**
  2. * jquery.mask.js
  3. * @version: v1.14.0
  4. * @author: Igor Escobar
  5. *
  6. * Created by Igor Escobar on 2012-03-10. Please report any bug at http://blog.igorescobar.com
  7. *
  8. * Copyright (c) 2012 Igor Escobar http://blog.igorescobar.com
  9. *
  10. * The MIT License (http://www.opensource.org/licenses/mit-license.php)
  11. *
  12. * Permission is hereby granted, free of charge, to any person
  13. * obtaining a copy of this software and associated documentation
  14. * files (the "Software"), to deal in the Software without
  15. * restriction, including without limitation the rights to use,
  16. * copy, modify, merge, publish, distribute, sublicense, and/or sell
  17. * copies of the Software, and to permit persons to whom the
  18. * Software is furnished To Do so, subject to the following
  19. * conditions:
  20. *
  21. * The above copyright notice and this permission notice shall be
  22. * included in all copies or substantial portions of the Software.
  23. *
  24. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  26. * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  28. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  29. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  30. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  31. * OTHER DEALINGS IN THE SOFTWARE.
  32. */
  33. /* jshint laxbreak: true */
  34. /* global define, jQuery, Zepto */
  35. 'use strict';
  36. // UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere.
  37. // https://github.com/umdjs/umd/blob/master/jqueryPluginCommonjs.js
  38. (function (factory) {
  39. if (typeof define === 'function' && define.amd) {
  40. define(['jquery'], factory);
  41. } else if (typeof exports === 'object') {
  42. module.exports = factory(require('jquery'));
  43. } else {
  44. factory(jQuery || Zepto);
  45. }
  46. }(function ($) {
  47. var Mask = function (el, mask, options) {
  48. var p = {
  49. invalid: [],
  50. getCaret: function () {
  51. try {
  52. var sel,
  53. pos = 0,
  54. ctrl = el.get(0),
  55. dSel = document.selection,
  56. cSelStart = ctrl.selectionStart;
  57. // IE Support
  58. if (dSel && navigator.appVersion.indexOf('MSIE 10') === -1) {
  59. sel = dSel.createRange();
  60. sel.moveStart('character', -p.val().length);
  61. pos = sel.text.length;
  62. }
  63. // Firefox support
  64. else if (cSelStart || cSelStart === '0') {
  65. pos = cSelStart;
  66. }
  67. return pos;
  68. } catch (e) {}
  69. },
  70. setCaret: function(pos) {
  71. try {
  72. if (el.is(':focus')) {
  73. var range, ctrl = el.get(0);
  74. // Firefox, WebKit, etc..
  75. if (ctrl.setSelectionRange) {
  76. ctrl.focus();
  77. ctrl.setSelectionRange(pos, pos);
  78. } else { // IE
  79. range = ctrl.createTextRange();
  80. range.collapse(true);
  81. range.moveEnd('character', pos);
  82. range.moveStart('character', pos);
  83. range.select();
  84. }
  85. }
  86. } catch (e) {}
  87. },
  88. events: function() {
  89. el
  90. .on('keydown.mask', function(e) {
  91. el.data('mask-keycode', e.keyCode || e.which);
  92. })
  93. .on($.jMaskGlobals.useInput ? 'input.mask' : 'keyup.mask', p.behaviour)
  94. .on('paste.mask drop.mask', function() {
  95. setTimeout(function() {
  96. el.keydown().keyup();
  97. }, 100);
  98. })
  99. .on('change.mask', function(){
  100. el.data('changed', true);
  101. })
  102. .on('blur.mask', function(){
  103. if (oldValue !== p.val() && !el.data('changed')) {
  104. el.trigger('change');
  105. }
  106. el.data('changed', false);
  107. })
  108. // it's very important that this callback remains in this position
  109. // otherwhise oldValue it's going to work buggy
  110. .on('blur.mask', function() {
  111. oldValue = p.val();
  112. })
  113. // select all text on focus
  114. .on('focus.mask', function (e) {
  115. if (options.selectOnFocus === true) {
  116. $(e.target).select();
  117. }
  118. })
  119. // clear the value if it not complete the mask
  120. .on('focusout.mask', function() {
  121. if (options.clearIfNotMatch && !regexMask.test(p.val())) {
  122. p.val('');
  123. }
  124. });
  125. },
  126. getRegexMask: function() {
  127. var maskChunks = [], translation, pattern, optional, recursive, oRecursive, r;
  128. for (var i = 0; i < mask.length; i++) {
  129. translation = jMask.translation[mask.charAt(i)];
  130. if (translation) {
  131. pattern = translation.pattern.toString().replace(/.{1}$|^.{1}/g, '');
  132. optional = translation.optional;
  133. recursive = translation.recursive;
  134. if (recursive) {
  135. maskChunks.push(mask.charAt(i));
  136. oRecursive = {digit: mask.charAt(i), pattern: pattern};
  137. } else {
  138. maskChunks.push(!optional && !recursive ? pattern : (pattern + '?'));
  139. }
  140. } else {
  141. maskChunks.push(mask.charAt(i).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'));
  142. }
  143. }
  144. r = maskChunks.join('');
  145. if (oRecursive) {
  146. r = r.replace(new RegExp('(' + oRecursive.digit + '(.*' + oRecursive.digit + ')?)'), '($1)?')
  147. .replace(new RegExp(oRecursive.digit, 'g'), oRecursive.pattern);
  148. }
  149. return new RegExp(r);
  150. },
  151. destroyEvents: function() {
  152. el.off(['input', 'keydown', 'keyup', 'paste', 'drop', 'blur', 'focusout', ''].join('.mask '));
  153. },
  154. val: function(v) {
  155. var isInput = el.is('input'),
  156. method = isInput ? 'val' : 'text',
  157. r;
  158. if (arguments.length > 0) {
  159. if (el[method]() !== v) {
  160. el[method](v);
  161. }
  162. r = el;
  163. } else {
  164. r = el[method]();
  165. }
  166. return r;
  167. },
  168. getMCharsBeforeCount: function(index, onCleanVal) {
  169. for (var count = 0, i = 0, maskL = mask.length; i < maskL && i < index; i++) {
  170. if (!jMask.translation[mask.charAt(i)]) {
  171. index = onCleanVal ? index + 1 : index;
  172. count++;
  173. }
  174. }
  175. return count;
  176. },
  177. caretPos: function (originalCaretPos, oldLength, newLength, maskDif) {
  178. var translation = jMask.translation[mask.charAt(Math.min(originalCaretPos - 1, mask.length - 1))];
  179. return !translation ? p.caretPos(originalCaretPos + 1, oldLength, newLength, maskDif)
  180. : Math.min(originalCaretPos + newLength - oldLength - maskDif, newLength);
  181. },
  182. behaviour: function(e) {
  183. e = e || window.event;
  184. p.invalid = [];
  185. var keyCode = el.data('mask-keycode');
  186. if ($.inArray(keyCode, jMask.byPassKeys) === -1) {
  187. var caretPos = p.getCaret(),
  188. currVal = p.val(),
  189. currValL = currVal.length,
  190. newVal = p.getMasked(),
  191. newValL = newVal.length,
  192. maskDif = p.getMCharsBeforeCount(newValL - 1) - p.getMCharsBeforeCount(currValL - 1),
  193. changeCaret = caretPos < currValL;
  194. p.val(newVal);
  195. if (changeCaret) {
  196. // Avoid adjusting caret on backspace or delete
  197. if (!(keyCode === 8 || keyCode === 46)) {
  198. caretPos = p.caretPos(caretPos, currValL, newValL, maskDif);
  199. }
  200. p.setCaret(caretPos);
  201. }
  202. return p.callbacks(e);
  203. }
  204. },
  205. getMasked: function(skipMaskChars, val) {
  206. var buf = [],
  207. value = val === undefined ? p.val() : val + '',
  208. m = 0, maskLen = mask.length,
  209. v = 0, valLen = value.length,
  210. offset = 1, addMethod = 'push',
  211. resetPos = -1,
  212. lastMaskChar,
  213. check;
  214. if (options.reverse) {
  215. addMethod = 'unshift';
  216. offset = -1;
  217. lastMaskChar = 0;
  218. m = maskLen - 1;
  219. v = valLen - 1;
  220. check = function () {
  221. return m > -1 && v > -1;
  222. };
  223. } else {
  224. lastMaskChar = maskLen - 1;
  225. check = function () {
  226. return m < maskLen && v < valLen;
  227. };
  228. }
  229. while (check()) {
  230. var maskDigit = mask.charAt(m),
  231. valDigit = value.charAt(v),
  232. translation = jMask.translation[maskDigit];
  233. if (translation) {
  234. if (valDigit.match(translation.pattern)) {
  235. buf[addMethod](valDigit);
  236. if (translation.recursive) {
  237. if (resetPos === -1) {
  238. resetPos = m;
  239. } else if (m === lastMaskChar) {
  240. m = resetPos - offset;
  241. }
  242. if (lastMaskChar === resetPos) {
  243. m -= offset;
  244. }
  245. }
  246. m += offset;
  247. } else if (translation.optional) {
  248. m += offset;
  249. v -= offset;
  250. } else if (translation.fallback) {
  251. buf[addMethod](translation.fallback);
  252. m += offset;
  253. v -= offset;
  254. } else {
  255. p.invalid.push({p: v, v: valDigit, e: translation.pattern});
  256. }
  257. v += offset;
  258. } else {
  259. if (!skipMaskChars) {
  260. buf[addMethod](maskDigit);
  261. }
  262. if (valDigit === maskDigit) {
  263. v += offset;
  264. }
  265. m += offset;
  266. }
  267. }
  268. var lastMaskCharDigit = mask.charAt(lastMaskChar);
  269. if (maskLen === valLen + 1 && !jMask.translation[lastMaskCharDigit]) {
  270. buf.push(lastMaskCharDigit);
  271. }
  272. return buf.join('');
  273. },
  274. callbacks: function (e) {
  275. var val = p.val(),
  276. changed = val !== oldValue,
  277. defaultArgs = [val, e, el, options],
  278. callback = function(name, criteria, args) {
  279. if (typeof options[name] === 'function' && criteria) {
  280. options[name].apply(this, args);
  281. }
  282. };
  283. callback('onChange', changed === true, defaultArgs);
  284. callback('onKeyPress', changed === true, defaultArgs);
  285. callback('onComplete', val.length === mask.length, defaultArgs);
  286. callback('onInvalid', p.invalid.length > 0, [val, e, el, p.invalid, options]);
  287. }
  288. };
  289. el = $(el);
  290. var jMask = this, oldValue = p.val(), regexMask;
  291. mask = typeof mask === 'function' ? mask(p.val(), undefined, el, options) : mask;
  292. // public methods
  293. jMask.mask = mask;
  294. jMask.options = options;
  295. jMask.remove = function() {
  296. var caret = p.getCaret();
  297. p.destroyEvents();
  298. p.val(jMask.getCleanVal());
  299. p.setCaret(caret - p.getMCharsBeforeCount(caret));
  300. return el;
  301. };
  302. // get value without mask
  303. jMask.getCleanVal = function() {
  304. return p.getMasked(true);
  305. };
  306. // get masked value without the value being in the input or element
  307. jMask.getMaskedVal = function(val) {
  308. return p.getMasked(false, val);
  309. };
  310. jMask.init = function(onlyMask) {
  311. onlyMask = onlyMask || false;
  312. options = options || {};
  313. jMask.clearIfNotMatch = $.jMaskGlobals.clearIfNotMatch;
  314. jMask.byPassKeys = $.jMaskGlobals.byPassKeys;
  315. jMask.translation = $.extend({}, $.jMaskGlobals.translation, options.translation);
  316. jMask = $.extend(true, {}, jMask, options);
  317. regexMask = p.getRegexMask();
  318. if (onlyMask === false) {
  319. if (options.placeholder) {
  320. el.attr('placeholder' , options.placeholder);
  321. }
  322. // this is necessary, otherwise if the user submit the form
  323. // and then press the "back" button, the autocomplete will erase
  324. // the data. Works fine on IE9+, FF, Opera, Safari.
  325. if (el.data('mask')) {
  326. el.attr('autocomplete', 'off');
  327. }
  328. p.destroyEvents();
  329. p.events();
  330. var caret = p.getCaret();
  331. p.val(p.getMasked());
  332. p.setCaret(caret + p.getMCharsBeforeCount(caret, true));
  333. } else {
  334. p.events();
  335. p.val(p.getMasked());
  336. }
  337. };
  338. jMask.init(!el.is('input'));
  339. };
  340. $.maskWatchers = {};
  341. var HTMLAttributes = function () {
  342. var input = $(this),
  343. options = {},
  344. prefix = 'data-mask-',
  345. mask = input.attr('data-mask');
  346. if (input.attr(prefix + 'reverse')) {
  347. options.reverse = true;
  348. }
  349. if (input.attr(prefix + 'clearifnotmatch')) {
  350. options.clearIfNotMatch = true;
  351. }
  352. if (input.attr(prefix + 'selectonfocus') === 'true') {
  353. options.selectOnFocus = true;
  354. }
  355. if (notSameMaskObject(input, mask, options)) {
  356. return input.data('mask', new Mask(this, mask, options));
  357. }
  358. },
  359. notSameMaskObject = function(field, mask, options) {
  360. options = options || {};
  361. var maskObject = $(field).data('mask'),
  362. stringify = JSON.stringify,
  363. value = $(field).val() || $(field).text();
  364. try {
  365. if (typeof mask === 'function') {
  366. mask = mask(value);
  367. }
  368. return typeof maskObject !== 'object' || stringify(maskObject.options) !== stringify(options) || maskObject.mask !== mask;
  369. } catch (e) {}
  370. },
  371. eventSupported = function(eventName) {
  372. var el = document.createElement('div'), isSupported;
  373. eventName = 'on' + eventName;
  374. isSupported = (eventName in el);
  375. if ( !isSupported ) {
  376. el.setAttribute(eventName, 'return;');
  377. isSupported = typeof el[eventName] === 'function';
  378. }
  379. el = null;
  380. return isSupported;
  381. };
  382. $.fn.mask = function(mask, options) {
  383. options = options || {};
  384. var selector = this.selector,
  385. globals = $.jMaskGlobals,
  386. interval = globals.watchInterval,
  387. watchInputs = options.watchInputs || globals.watchInputs,
  388. maskFunction = function() {
  389. if (notSameMaskObject(this, mask, options)) {
  390. return $(this).data('mask', new Mask(this, mask, options));
  391. }
  392. };
  393. $(this).each(maskFunction);
  394. if (selector && selector !== '' && watchInputs) {
  395. clearInterval($.maskWatchers[selector]);
  396. $.maskWatchers[selector] = setInterval(function(){
  397. $(document).find(selector).each(maskFunction);
  398. }, interval);
  399. }
  400. return this;
  401. };
  402. $.fn.masked = function(val) {
  403. return this.data('mask').getMaskedVal(val);
  404. };
  405. $.fn.unmask = function() {
  406. clearInterval($.maskWatchers[this.selector]);
  407. delete $.maskWatchers[this.selector];
  408. return this.each(function() {
  409. var dataMask = $(this).data('mask');
  410. if (dataMask) {
  411. dataMask.remove().removeData('mask');
  412. }
  413. });
  414. };
  415. $.fn.cleanVal = function() {
  416. return this.data('mask').getCleanVal();
  417. };
  418. $.applyDataMask = function(selector) {
  419. selector = selector || $.jMaskGlobals.maskElements;
  420. var $selector = (selector instanceof $) ? selector : $(selector);
  421. $selector.filter($.jMaskGlobals.dataMaskAttr).each(HTMLAttributes);
  422. };
  423. var globals = {
  424. maskElements: 'input,td,span,div',
  425. dataMaskAttr: '*[data-mask]',
  426. dataMask: true,
  427. watchInterval: 300,
  428. watchInputs: true,
  429. useInput: eventSupported('input'),
  430. watchDataMask: false,
  431. byPassKeys: [9, 16, 17, 18, 36, 37, 38, 39, 40, 91],
  432. translation: {
  433. '0': {pattern: /\d/},
  434. '9': {pattern: /\d/, optional: true},
  435. '#': {pattern: /\d/, recursive: true},
  436. 'A': {pattern: /[a-zA-Z0-9]/},
  437. 'S': {pattern: /[a-zA-Z]/}
  438. }
  439. };
  440. $.jMaskGlobals = $.jMaskGlobals || {};
  441. globals = $.jMaskGlobals = $.extend(true, {}, globals, $.jMaskGlobals);
  442. // looking for inputs with data-mask attribute
  443. if (globals.dataMask) {
  444. $.applyDataMask();
  445. }
  446. setInterval(function() {
  447. if ($.jMaskGlobals.watchDataMask) {
  448. $.applyDataMask();
  449. }
  450. }, globals.watchInterval);
  451. }));