bootstrapValidator.js 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848
  1. /**
  2. * BootstrapValidator (https://github.com/nghuuphuoc/bootstrapvalidator)
  3. *
  4. * A jQuery plugin to validate form fields. Use with Bootstrap 3
  5. *
  6. * @version v0.4.0-dev
  7. * @author https://twitter.com/nghuuphuoc
  8. * @copyright (c) 2013 - 2014 Nguyen Huu Phuoc
  9. * @license MIT
  10. */
  11. (function($) {
  12. var BootstrapValidator = function(form, options) {
  13. this.$form = $(form);
  14. this.options = $.extend({}, BootstrapValidator.DEFAULT_OPTIONS, options);
  15. this.results = {}; // Validating results
  16. this.$invalidField = null; // First invalid field
  17. this.$submitButton = null; // The submit button which is clicked to submit form
  18. // Validating status
  19. this.STATUS_NOT_VALIDATED = 'NOT_VALIDATED';
  20. this.STATUS_VALIDATING = 'VALIDATING';
  21. this.STATUS_INVALID = 'INVALID';
  22. this.STATUS_VALID = 'VALID';
  23. this._init();
  24. };
  25. // The default options
  26. BootstrapValidator.DEFAULT_OPTIONS = {
  27. // The form CSS class
  28. elementClass: 'bootstrap-validator-form',
  29. // Default invalid message
  30. message: 'This value is not valid',
  31. // Shows ok/error/loading icons based on the field validity.
  32. // This feature requires Bootstrap v3.1.0 or later (http://getbootstrap.com/css/#forms-control-validation).
  33. // Since Bootstrap doesn't provide any methods to know its version, this option cannot be on/off automatically.
  34. // In other word, to use this feature you have to upgrade your Bootstrap to v3.1.0 or later.
  35. //
  36. // Examples:
  37. // - Use Glyphicons icons:
  38. // feedbackIcons: {
  39. // valid: 'glyphicon glyphicon-ok',
  40. // invalid: 'glyphicon glyphicon-remove',
  41. // validating: 'glyphicon glyphicon-refresh'
  42. // }
  43. // - Use FontAwesome icons:
  44. // feedbackIcons: {
  45. // valid: 'fa fa-check',
  46. // invalid: 'fa fa-times',
  47. // validating: 'fa fa-refresh'
  48. // }
  49. feedbackIcons: {
  50. valid: null,
  51. invalid: null,
  52. validating: null
  53. },
  54. // The submit buttons selector
  55. // These buttons will be disabled to prevent the valid form from multiple submissions
  56. submitButtons: 'button[type="submit"]',
  57. // The custom submit handler
  58. // It will prevent the form from the default submission
  59. //
  60. // submitHandler: function(validator, form) {
  61. // - validator is the BootstrapValidator instance
  62. // - form is the jQuery object present the current form
  63. // }
  64. submitHandler: null,
  65. // Live validating option
  66. // Can be one of 3 values:
  67. // - enabled: The plugin validates fields as soon as they are changed
  68. // - disabled: Disable the live validating. The error messages are only shown after the form is submitted
  69. // - submitted: The live validating is enabled after the form is submitted
  70. live: 'enabled',
  71. // Map the field name with validator rules
  72. fields: null
  73. };
  74. BootstrapValidator.prototype = {
  75. constructor: BootstrapValidator,
  76. /**
  77. * Init form
  78. */
  79. _init: function() {
  80. var that = this,
  81. options = {
  82. trigger: this.$form.attr('data-bv-trigger'),
  83. message: this.$form.attr('data-bv-message'),
  84. submitButtons: this.$form.attr('data-bv-submitbuttons'),
  85. live: this.$form.attr('data-bv-live'),
  86. fields: {},
  87. feedbackIcons: {
  88. valid: this.$form.attr('data-bv-feedbackicons-valid'),
  89. invalid: this.$form.attr('data-bv-feedbackicons-invalid'),
  90. validating: this.$form.attr('data-bv-feedbackicons-validating')
  91. }
  92. },
  93. validator,
  94. i = 0,
  95. v, // Validator name
  96. enabled,
  97. optionName,
  98. optionValue,
  99. html5Attrs;
  100. this.$form
  101. // Disable client side validation in HTML 5
  102. .attr('novalidate', 'novalidate')
  103. .addClass(this.options.elementClass)
  104. // Disable the default submission first
  105. .on('submit.bv', function(e) {
  106. e.preventDefault();
  107. that.validate();
  108. })
  109. .on('click', this.options.submitButtons, function() {
  110. that.$submitButton = $(this);
  111. })
  112. // Find all fields which have either "name" or "data-bv-field" attribute
  113. .find('[name], [data-bv-field]').each(function() {
  114. var $field = $(this),
  115. field = $field.attr('name') || $field.attr('data-bv-field');
  116. $field.attr('data-bv-field', field);
  117. options.fields[field] = $.extend({}, {
  118. trigger: $field.attr('data-bv-trigger'),
  119. message: $field.attr('data-bv-message'),
  120. container: $field.attr('data-bv-container'),
  121. selector: $field.attr('data-bv-selector'),
  122. validators: {}
  123. }, options.fields[field]);
  124. for (v in $.fn.bootstrapValidator.validators) {
  125. validator = $.fn.bootstrapValidator.validators[v];
  126. enabled = $field.attr('data-bv-' + v.toLowerCase()) + '';
  127. html5Attrs = {};
  128. if (('function' == typeof validator.enableByHtml5
  129. && (html5Attrs = validator.enableByHtml5($(this)))
  130. && (enabled != 'false'))
  131. || ('undefined' == typeof validator.enableByHtml5 && ('' == enabled || 'true' == enabled)))
  132. {
  133. // Try to parse the options via attributes
  134. validator.html5Attributes = validator.html5Attributes || ['message'];
  135. options.fields[field]['validators'][v] = $.extend({}, html5Attrs == true ? {} : html5Attrs, options.fields[field]['validators'][v]);
  136. for (i in validator.html5Attributes) {
  137. optionName = validator.html5Attributes[i];
  138. optionValue = $field.attr('data-bv-' + v.toLowerCase() + '-' + optionName.toLowerCase());
  139. if (optionValue) {
  140. if ('true' == optionValue) {
  141. optionValue = true;
  142. } else if ('false' == optionValue) {
  143. optionValue = false;
  144. }
  145. options.fields[field]['validators'][v][optionName] = optionValue;
  146. }
  147. }
  148. }
  149. }
  150. });
  151. this.options = $.extend(true, this.options, options);
  152. //console.log(this.options);
  153. for (var field in this.options.fields) {
  154. this._initField(field);
  155. }
  156. this._setLiveValidating();
  157. },
  158. /**
  159. * Init field
  160. *
  161. * @param {String} field The field name
  162. */
  163. _initField: function(field) {
  164. if (this.options.fields[field] == null || this.options.fields[field].validators == null) {
  165. return;
  166. }
  167. this.results[field] = {};
  168. var fields = this.getFieldElements(field);
  169. // We don't need to validate non-existing fields
  170. if (fields == null) {
  171. delete this.options.fields[field];
  172. return;
  173. }
  174. for (var validatorName in this.options.fields[field].validators) {
  175. if (!$.fn.bootstrapValidator.validators[validatorName]) {
  176. delete this.options.fields[field].validators[validatorName];
  177. }
  178. }
  179. // Set the attribute to indicate the fields which are defined by selector
  180. if (!fields.attr('data-bv-field')) {
  181. fields.attr('data-bv-field', field);
  182. }
  183. var that = this,
  184. type = fields.attr('type'),
  185. event = ('radio' == type || 'checkbox' == type || 'file' == type || 'SELECT' == fields[0].tagName) ? 'change' : 'keyup',
  186. total = fields.length,
  187. updateAll = (total == 1) || ('radio' == type) || ('checkbox' == type);
  188. for (var i = 0; i < total; i++) {
  189. var $field = $(fields[i]),
  190. $parent = $field.parents('.form-group'),
  191. // Allow user to indicate where the error messages are shown
  192. $message = this.options.fields[field].container ? $parent.find(this.options.fields[field].container) : this._getMessageContainer($field);
  193. // Whenever the user change the field value, mark it as not validated yet
  194. $field.on(event + '.bv', function() {
  195. updateAll ? that.updateStatus(field, that.STATUS_NOT_VALIDATED, null)
  196. : that.updateElementStatus($(this), that.STATUS_NOT_VALIDATED, null);
  197. });
  198. // Create help block elements for showing the error messages
  199. $field.data('bv.messageContainer', $message);
  200. for (validatorName in this.options.fields[field].validators) {
  201. $field.data('bv.result.' + validatorName, this.STATUS_NOT_VALIDATED);
  202. //this.results[field][validatorName] = this.STATUS_NOT_VALIDATED;
  203. if (!updateAll || i == total - 1) {
  204. $('<small/>')
  205. .css('display', 'none')
  206. .attr('data-bv-validator', validatorName)
  207. .html(this.options.fields[field].validators[validatorName].message || this.options.fields[field].message || this.options.message)
  208. .addClass('help-block')
  209. .appendTo($message);
  210. }
  211. }
  212. // Prepare the feedback icons
  213. // Available from Bootstrap 3.1 (http://getbootstrap.com/css/#forms-control-validation)
  214. if (this.options.feedbackIcons
  215. && this.options.feedbackIcons.validating && this.options.feedbackIcons.invalid && this.options.feedbackIcons.valid
  216. && (!updateAll || i == total - 1))
  217. {
  218. $parent.addClass('has-feedback');
  219. var $icon = $('<i/>').css('display', 'none').addClass('form-control-feedback').attr('data-bv-field', field).insertAfter($field);
  220. // The feedback icon does not render correctly if there is no label
  221. // https://github.com/twbs/bootstrap/issues/12873
  222. if ($parent.find('label').length == 0) {
  223. $icon.css('top', 0);
  224. }
  225. }
  226. }
  227. if (this.options.fields[field]['enabled'] == null) {
  228. this.options.fields[field]['enabled'] = true;
  229. }
  230. },
  231. /**
  232. * Get the element to place the error messages
  233. *
  234. * @param {jQuery} $field The field element
  235. * @returns {jQuery}
  236. */
  237. _getMessageContainer: function($field) {
  238. var $parent = $field.parent();
  239. if ($parent.hasClass('form-group')) {
  240. return $parent;
  241. }
  242. var cssClasses = $parent.attr('class');
  243. if (!cssClasses) {
  244. return this._getMessageContainer($parent);
  245. }
  246. cssClasses = cssClasses.split(' ');
  247. var n = cssClasses.length;
  248. for (var i = 0; i < n; i++) {
  249. if (/^col-(xs|sm|md|lg)-\d+$/.test(cssClasses[i]) || /^col-(xs|sm|md|lg)-offset-\d+$/.test(cssClasses[i])) {
  250. return $parent;
  251. }
  252. }
  253. return this._getMessageContainer($parent);
  254. },
  255. /**
  256. * Enable live validating
  257. */
  258. _setLiveValidating: function() {
  259. if ('enabled' == this.options.live) {
  260. var that = this;
  261. for (var field in this.options.fields) {
  262. (function(f) {
  263. var fields = that.getFieldElements(f);
  264. if (fields) {
  265. var type = fields.attr('type'),
  266. total = fields.length,
  267. updateAll = (total == 1) || ('radio' == type) || ('checkbox' == type),
  268. trigger = that.options.fields[field].trigger
  269. || that.options.trigger
  270. || (('radio' == type || 'checkbox' == type || 'file' == type || 'SELECT' == fields[0].tagName) ? 'change' : 'keyup'),
  271. events = trigger.split(' ').map(function(item) {
  272. return item + '.bv';
  273. }).join(' ');
  274. for (var i = 0; i < total; i++) {
  275. $(fields[i]).on(events, function () {
  276. updateAll ? that.validateField(f) : that.validateFieldElement($(this), false);
  277. });
  278. }
  279. }
  280. })(field);
  281. }
  282. }
  283. },
  284. /**
  285. * Disable/Enable submit buttons
  286. *
  287. * @param {Boolean} disabled
  288. */
  289. _disableSubmitButtons: function(disabled) {
  290. if (!disabled) {
  291. this.$form.find(this.options.submitButtons).removeAttr('disabled');
  292. } else if (this.options.live != 'disabled') {
  293. // Don't disable if the live validating mode is disabled
  294. this.$form.find(this.options.submitButtons).attr('disabled', 'disabled');
  295. }
  296. },
  297. /**
  298. * Called when all validations are completed
  299. */
  300. _submit: function() {
  301. if (!this.isValid()) {
  302. if ('submitted' == this.options.live) {
  303. this.options.live = 'enabled';
  304. this._setLiveValidating();
  305. }
  306. // Focus to the first invalid field
  307. if (this.$invalidField) {
  308. this.$invalidField.focus();
  309. }
  310. return;
  311. }
  312. this._disableSubmitButtons(true);
  313. // Call the custom submission if enabled
  314. if (this.options.submitHandler && 'function' == typeof this.options.submitHandler) {
  315. // Turn off the submit handler, so user can call form.submit() inside their submitHandler method
  316. this.$form.off('submit.bv');
  317. this.options.submitHandler.call(this, this, this.$form, this.$submitButton);
  318. } else {
  319. // Submit form
  320. this.$form.off('submit.bv').submit();
  321. }
  322. },
  323. // --- Public methods ---
  324. /**
  325. * Retrieve the field elements by given name
  326. *
  327. * @param {String} field The field name
  328. * @returns {null|jQuery[]}
  329. */
  330. getFieldElements: function(field) {
  331. var fields = this.$form.find(this.options.fields[field].selector || '[name="' + field + '"]');
  332. return (fields.length == 0) ? null : fields;
  333. },
  334. /**
  335. * Validate the form
  336. *
  337. * @return {BootstrapValidator}
  338. */
  339. validate: function() {
  340. if (!this.options.fields) {
  341. return this;
  342. }
  343. this._disableSubmitButtons(true);
  344. for (var field in this.options.fields) {
  345. this.validateField(field);
  346. }
  347. this._submit();
  348. return this;
  349. },
  350. /**
  351. * Validate given field
  352. *
  353. * @param {String} field The field element
  354. * @returns {BootstrapValidator}
  355. */
  356. validateField: function(field) {
  357. var fields = this.getFieldElements(field),
  358. type = fields.attr('type'),
  359. n = (('radio' == type) || ('checkbox' == type)) ? 1 : fields.length;
  360. for (var i = 0; i < n; i++) {
  361. this.validateFieldElement($(fields[i]), (n == 1));
  362. }
  363. return this;
  364. },
  365. /**
  366. * Validate field element
  367. *
  368. * @param {jQuery} $field The field element
  369. * @param {Boolean} updateAll If true, update status of all elements which have the same name
  370. * @returns {BootstrapValidator}
  371. */
  372. validateFieldElement: function($field, updateAll) {
  373. var that = this,
  374. field = $field.attr('data-bv-field'),
  375. validators = this.options.fields[field].validators,
  376. validatorName,
  377. validateResult;
  378. // We don't need to validate disabled field
  379. if ($field.is(':disabled')) {
  380. return this;
  381. }
  382. for (validatorName in validators) {
  383. if ($field.data('bv.dfs.' + validatorName)) {
  384. $field.data('bv.dfs.' + validatorName).reject();
  385. }
  386. // Don't validate field if it is already done
  387. var result = $field.data('bv.result.' + validatorName);
  388. if (result == this.STATUS_VALID || result == this.STATUS_INVALID) {
  389. continue;
  390. }
  391. $field.data('bv.result.' + validatorName, this.STATUS_VALIDATING);
  392. validateResult = $.fn.bootstrapValidator.validators[validatorName].validate(this, $field, validators[validatorName]);
  393. if ('object' == typeof validateResult) {
  394. updateAll ? this.updateStatus(field, this.STATUS_VALIDATING, validatorName)
  395. : this.updateElementStatus($field, this.STATUS_VALIDATING, validatorName);
  396. $field.data('bv.dfs.' + validatorName, validateResult);
  397. validateResult.done(function($f, v, isValid) {
  398. // v is validator name
  399. $f.removeData('bv.dfs.' + v);
  400. updateAll ? that.updateStatus($f.attr('data-bv-field'), isValid ? that.STATUS_VALID : that.STATUS_INVALID, v)
  401. : that.updateElementStatus($f, isValid ? that.STATUS_VALID : that.STATUS_INVALID, v);
  402. if (isValid && 'disabled' == that.options.live) {
  403. that._submit();
  404. }
  405. });
  406. } else if ('boolean' == typeof validateResult) {
  407. updateAll ? this.updateStatus(field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName)
  408. : this.updateElementStatus($field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
  409. }
  410. }
  411. return this;
  412. },
  413. /**
  414. * Update all validating results of elements which have the same field name
  415. *
  416. * @param {String} field The field name
  417. * @param {String} status The status
  418. * Can be 'NOT_VALIDATED', 'VALIDATING', 'INVALID' or 'VALID'
  419. * @param {String|null} validatorName The validator name. If null, the method updates validity result for all validators
  420. * @return {BootstrapValidator}
  421. */
  422. updateStatus: function(field, status, validatorName) {
  423. var fields = this.getFieldElements(field),
  424. type = fields.attr('type'),
  425. n = (('radio' == type) || ('checkbox' == type)) ? 1 : fields.length;
  426. for (var i = 0; i < n; i++) {
  427. this.updateElementStatus($(fields[i]), status, validatorName);
  428. }
  429. return this;
  430. },
  431. /**
  432. * Update validating result of given element
  433. *
  434. * @param {String} field The field name
  435. * @param {String} status The status
  436. * Can be 'NOT_VALIDATED', 'VALIDATING', 'INVALID' or 'VALID'
  437. * @param {String|null} validatorName The validator name. If null, the method updates validity result for all validators
  438. * @return {BootstrapValidator}
  439. */
  440. updateElementStatus: function($field, status, validatorName) {
  441. var that = this,
  442. field = $field.attr('data-bv-field'),
  443. $parent = $field.parents('.form-group'),
  444. $message = $field.data('bv.messageContainer'),
  445. $errors = $message.find('.help-block[data-bv-validator]'),
  446. $icon = $parent.find('.form-control-feedback[data-bv-field="' + field + '"]');
  447. // Update status
  448. if (validatorName) {
  449. $field.data('bv.result.' + validatorName, status);
  450. } else {
  451. for (var v in this.options.fields[field].validators) {
  452. $field.data('bv.result.' + v, status);
  453. }
  454. }
  455. // Show/hide error elements and feedback icons
  456. switch (status) {
  457. case this.STATUS_VALIDATING:
  458. this._disableSubmitButtons(true);
  459. $parent.removeClass('has-success').removeClass('has-error');
  460. // TODO: Show validating message
  461. validatorName ? $errors.filter('.help-block[data-bv-validator="' + validatorName + '"]').hide() : $errors.hide();
  462. if ($icon) {
  463. $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).addClass(this.options.feedbackIcons.validating).show();
  464. }
  465. break;
  466. case this.STATUS_INVALID:
  467. this._disableSubmitButtons(true);
  468. $parent.removeClass('has-success').addClass('has-error');
  469. validatorName ? $errors.filter('[data-bv-validator="' + validatorName + '"]').show() : $errors.show();
  470. if ($icon) {
  471. $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.validating).addClass(this.options.feedbackIcons.invalid).show();
  472. }
  473. break;
  474. case this.STATUS_VALID:
  475. validatorName ? $errors.filter('[data-bv-validator="' + validatorName + '"]').hide() : $errors.hide();
  476. // If the field is valid
  477. if ($errors.filter(function() {
  478. var display = $(this).css('display'), v = $(this).attr('data-bv-validator');
  479. return ('block' == display) || ($field.data('bv.result.' + v) != that.STATUS_VALID);
  480. }).length == 0
  481. ) {
  482. this._disableSubmitButtons(false);
  483. $parent.removeClass('has-error').addClass('has-success');
  484. if ($icon) {
  485. $icon.removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).addClass(this.options.feedbackIcons.valid).show();
  486. }
  487. }
  488. break;
  489. case this.STATUS_NOT_VALIDATED:
  490. default:
  491. this._disableSubmitButtons(false);
  492. $parent.removeClass('has-success').removeClass('has-error');
  493. validatorName ? $errors.filter('.help-block[data-bv-validator="' + validatorName + '"]').hide() : $errors.hide();
  494. if ($icon) {
  495. $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).hide();
  496. }
  497. break;
  498. }
  499. return this;
  500. },
  501. /**
  502. * Check the form validity
  503. *
  504. * @returns {Boolean}
  505. */
  506. isValid: function() {
  507. var fields, field, $field,
  508. type, status, validatorName,
  509. n, i;
  510. for (field in this.options.fields) {
  511. if (this.options.fields[field] == null || !this.options.fields[field]['enabled']) {
  512. continue;
  513. }
  514. fields = this.getFieldElements(field);
  515. type = fields.attr('type');
  516. n = (('radio' == type) || ('checkbox' == type)) ? 1 : fields.length;
  517. for (i = 0; i < n; i++) {
  518. $field = $(fields[i]);
  519. for (validatorName in this.options.fields[field].validators) {
  520. status = $field.data('bv.result.' + validatorName);
  521. if (status == this.STATUS_NOT_VALIDATED || status == this.STATUS_VALIDATING) {
  522. return false;
  523. }
  524. if (status == this.STATUS_INVALID) {
  525. this.$invalidField = $field;
  526. return false;
  527. }
  528. }
  529. }
  530. }
  531. return true;
  532. },
  533. // Useful APIs which aren't used internally
  534. /**
  535. * Reset the form
  536. *
  537. * @param {Boolean} resetFormData Reset current form data
  538. * @return {BootstrapValidator}
  539. */
  540. resetForm: function(resetFormData) {
  541. var field, fields, total, type, validator;
  542. for (field in this.options.fields) {
  543. fields = this.getFieldElements(field);
  544. total = fields.length;
  545. for (var i = 0; i < total; i++) {
  546. for (validator in this.options.fields[field].validators) {
  547. $(fields[i]).removeData('bv.dfs.' + validator);
  548. }
  549. }
  550. // Mark field as not validated yet
  551. this.updateStatus(field, this.STATUS_NOT_VALIDATED, null);
  552. if (resetFormData) {
  553. type = fields.attr('type');
  554. ('radio' == type || 'checkbox' == type) ? fields.removeAttr('checked').removeAttr('selected') : fields.val('');
  555. }
  556. }
  557. this.$invalidField = null;
  558. this.$submitButton = null;
  559. // Enable submit buttons
  560. this._disableSubmitButtons(false);
  561. return this;
  562. },
  563. /**
  564. * Enable/Disable all validators to given field
  565. *
  566. * @param {String} field The field name
  567. * @param {Boolean} enabled Enable/Disable field validators
  568. * @return {BootstrapValidator}
  569. */
  570. enableFieldValidators: function(field, enabled) {
  571. this.options.fields[field]['enabled'] = enabled;
  572. this.updateStatus(field, this.STATUS_NOT_VALIDATED, null);
  573. return this;
  574. }
  575. };
  576. // Plugin definition
  577. $.fn.bootstrapValidator = function(options) {
  578. return this.each(function() {
  579. var $this = $(this), data = $this.data('bootstrapValidator');
  580. if (!data) {
  581. $this.data('bootstrapValidator', (data = new BootstrapValidator(this, options)));
  582. }
  583. if ('string' == typeof options) {
  584. data[options]();
  585. }
  586. });
  587. };
  588. // Available validators
  589. $.fn.bootstrapValidator.validators = {};
  590. $.fn.bootstrapValidator.Constructor = BootstrapValidator;
  591. }(window.jQuery));
  592. ;(function($) {
  593. $.fn.bootstrapValidator.validators.base64 = {
  594. /**
  595. * Return true if the input value is a base 64 encoded string.
  596. *
  597. * @param {BootstrapValidator} validator The validator plugin instance
  598. * @param {jQuery} $field Field element
  599. * @param {Object} options Can consist of the following keys:
  600. * - message: The invalid message
  601. * @returns {Boolean}
  602. */
  603. validate: function(validator, $field, options) {
  604. var value = $field.val();
  605. if (value == '') {
  606. return true;
  607. }
  608. return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/.test(value);
  609. }
  610. };
  611. }(window.jQuery));
  612. ;(function($) {
  613. $.fn.bootstrapValidator.validators.between = {
  614. /**
  615. * Return true if the input value is between (strictly or not) two given numbers
  616. *
  617. * @param {BootstrapValidator} validator The validator plugin instance
  618. * @param {jQuery} $field Field element
  619. * @param {Object} options Can consist of the following keys:
  620. * - min
  621. * - max
  622. * - inclusive [optional]: Can be true or false. Default is true
  623. * - message: The invalid message
  624. * @returns {Boolean}
  625. */
  626. validate: function(validator, $field, options) {
  627. var value = $field.val();
  628. if (value == '') {
  629. return true;
  630. }
  631. value = parseFloat(value);
  632. return (options.inclusive === true)
  633. ? (value > options.min && value < options.max)
  634. : (value >= options.min && value <= options.max);
  635. }
  636. };
  637. }(window.jQuery));
  638. ;(function($) {
  639. $.fn.bootstrapValidator.validators.callback = {
  640. /**
  641. * Return result from the callback method
  642. *
  643. * @param {BootstrapValidator} validator The validator plugin instance
  644. * @param {jQuery} $field Field element
  645. * @param {Object} options Can consist of the following keys:
  646. * - callback: The callback method that passes 2 parameters:
  647. * callback: function(fieldValue, validator) {
  648. * // fieldValue is the value of field
  649. * // validator is instance of BootstrapValidator
  650. * }
  651. * - message: The invalid message
  652. * @returns {Boolean|Deferred}
  653. */
  654. validate: function(validator, $field, options) {
  655. var value = $field.val();
  656. if (options.callback && 'function' == typeof options.callback) {
  657. var dfd = new $.Deferred();
  658. dfd.resolve($field, 'callback', options.callback.call(this, value, validator));
  659. return dfd;
  660. }
  661. return true;
  662. }
  663. };
  664. }(window.jQuery));
  665. ;(function($) {
  666. $.fn.bootstrapValidator.validators.choice = {
  667. html5Attributes: ['message', 'min', 'max'],
  668. /**
  669. * Check if the number of checked boxes are less or more than a given number
  670. *
  671. * @param {BootstrapValidator} validator The validator plugin instance
  672. * @param {jQuery} $field Field element
  673. * @param {Object} options Consists of following keys:
  674. * - min
  675. * - max
  676. * At least one of two keys is required
  677. * @returns {Boolean}
  678. */
  679. validate: function(validator, $field, options) {
  680. var numChoices = validator
  681. .getFieldElements($field.attr('data-bv-field'))
  682. .filter(':checked')
  683. .length;
  684. if ((options.min && numChoices < options.min) || (options.max && numChoices > options.max)) {
  685. return false;
  686. }
  687. return true;
  688. }
  689. };
  690. }(window.jQuery));
  691. ;(function($) {
  692. $.fn.bootstrapValidator.validators.creditCard = {
  693. /**
  694. * Return true if the input value is valid credit card number
  695. * Based on https://gist.github.com/DiegoSalazar/4075533
  696. *
  697. * @param {BootstrapValidator} validator The validator plugin instance
  698. * @param {jQuery} $field Field element
  699. * @param {Object} options Can consist of the following key:
  700. * - message: The invalid message
  701. * @returns {Boolean}
  702. */
  703. validate: function(validator, $field, options) {
  704. var value = $field.val();
  705. if (value == '') {
  706. return true;
  707. }
  708. // Accept only digits, dashes or spaces
  709. if (/[^0-9-\s]+/.test(value)) {
  710. return false;
  711. }
  712. value = value.replace(/\D/g, '');
  713. // Validate the check sum
  714. // The Luhn Algorithm
  715. // http://en.wikipedia.org/wiki/Luhn
  716. var check = 0, digit = 0, even = false, length = value.length;
  717. for (var n = length - 1; n >= 0; n--) {
  718. digit = parseInt(value.charAt(n), 10);
  719. if (even) {
  720. if ((digit *= 2) > 9) {
  721. digit -= 9;
  722. }
  723. }
  724. check += digit;
  725. even = !even;
  726. }
  727. if ((check % 10) != 0) {
  728. return false;
  729. }
  730. // Validate the card number based on prefix (IIN ranges) and length
  731. var cards = {
  732. AMERICAN_EXPRESS: {
  733. length: [15],
  734. prefix: ['34', '37']
  735. },
  736. DINERS_CLUB: {
  737. length: [14],
  738. prefix: ['300', '301', '302', '303', '304', '305', '36']
  739. },
  740. DINERS_CLUB_US: {
  741. length: [16],
  742. prefix: ['54', '55']
  743. },
  744. DISCOVER: {
  745. length: [16],
  746. prefix: ['6011', '622126', '622127', '622128', '622129', '62213',
  747. '62214', '62215', '62216', '62217', '62218', '62219',
  748. '6222', '6223', '6224', '6225', '6226', '6227', '6228',
  749. '62290', '62291', '622920', '622921', '622922', '622923',
  750. '622924', '622925', '644', '645', '646', '647', '648',
  751. '649', '65']
  752. },
  753. JCB: {
  754. length: [16],
  755. prefix: ['3528', '3529', '353', '354', '355', '356', '357', '358']
  756. },
  757. LASER: {
  758. length: [16, 17, 18, 19],
  759. prefix: ['3528', '3529', '353', '354', '355', '356', '357', '358']
  760. },
  761. MAESTRO: {
  762. length: [12, 13, 14, 15, 16, 17, 18, 19],
  763. prefix: ['5018', '5020', '5038', '6304', '6759', '6761', '6762', '6763', '6764', '6765', '6766']
  764. },
  765. MASTERCARD: {
  766. length: [16],
  767. prefix: ['51', '52', '53', '54', '55']
  768. },
  769. SOLO: {
  770. length: [16, 18, 19],
  771. prefix: ['6334', '6767']
  772. },
  773. UNIONPAY: {
  774. length: [16, 17, 18, 19],
  775. prefix: ['622126', '622127', '622128', '622129', '62213', '62214',
  776. '62215', '62216', '62217', '62218', '62219', '6222', '6223',
  777. '6224', '6225', '6226', '6227', '6228', '62290', '62291',
  778. '622920', '622921', '622922', '622923', '622924', '622925']
  779. },
  780. VISA: {
  781. length: [16],
  782. prefix: ['4']
  783. }
  784. };
  785. var type, i;
  786. for (type in cards) {
  787. for (i in cards[type]['prefix']) {
  788. if (value.substr(0, cards[type]['prefix'][i].length) == cards[type]['prefix'][i] // Check the prefix
  789. && cards[type]['length'].indexOf(value.length) != -1) // and length
  790. {
  791. return true;
  792. }
  793. }
  794. }
  795. return false;
  796. }
  797. };
  798. }(window.jQuery));
  799. ;(function($) {
  800. $.fn.bootstrapValidator.validators.cvv = {
  801. /**
  802. * Return true if the input value is a valid CVV number.
  803. *
  804. * @param {BootstrapValidator} validator The validator plugin instance
  805. * @param {jQuery} $field Field element
  806. * @param {Object} options Can consist of the following keys:
  807. * - creditCardField: The credit card number field. It can be null
  808. * - message: The invalid message
  809. * @returns {Boolean}
  810. */
  811. validate: function(validator, $field, options) {
  812. var value = $field.val();
  813. if (value == '') {
  814. return true;
  815. }
  816. if (!/^[0-9]{3,4}$/.test(value)) {
  817. return false;
  818. }
  819. if (!options.creditCardField) {
  820. return true;
  821. }
  822. // Get the credit card number
  823. var creditCard = validator.getFieldElements(options.creditCardField).val();
  824. if (creditCard == '') {
  825. return true;
  826. }
  827. // Supported credit card types
  828. var cards = {
  829. AMERICAN_EXPRESS: {
  830. length: [15],
  831. prefix: ['34', '37']
  832. },
  833. DINERS_CLUB: {
  834. length: [14],
  835. prefix: ['300', '301', '302', '303', '304', '305', '36']
  836. },
  837. DINERS_CLUB_US: {
  838. length: [16],
  839. prefix: ['54', '55']
  840. },
  841. DISCOVER: {
  842. length: [16],
  843. prefix: ['6011', '622126', '622127', '622128', '622129', '62213',
  844. '62214', '62215', '62216', '62217', '62218', '62219',
  845. '6222', '6223', '6224', '6225', '6226', '6227', '6228',
  846. '62290', '62291', '622920', '622921', '622922', '622923',
  847. '622924', '622925', '644', '645', '646', '647', '648',
  848. '649', '65']
  849. },
  850. JCB: {
  851. length: [16],
  852. prefix: ['3528', '3529', '353', '354', '355', '356', '357', '358']
  853. },
  854. LASER: {
  855. length: [16, 17, 18, 19],
  856. prefix: ['3528', '3529', '353', '354', '355', '356', '357', '358']
  857. },
  858. MAESTRO: {
  859. length: [12, 13, 14, 15, 16, 17, 18, 19],
  860. prefix: ['5018', '5020', '5038', '6304', '6759', '6761', '6762', '6763', '6764', '6765', '6766']
  861. },
  862. MASTERCARD: {
  863. length: [16],
  864. prefix: ['51', '52', '53', '54', '55']
  865. },
  866. SOLO: {
  867. length: [16, 18, 19],
  868. prefix: ['6334', '6767']
  869. },
  870. UNIONPAY: {
  871. length: [16, 17, 18, 19],
  872. prefix: ['622126', '622127', '622128', '622129', '62213', '62214',
  873. '62215', '62216', '62217', '62218', '62219', '6222', '6223',
  874. '6224', '6225', '6226', '6227', '6228', '62290', '62291',
  875. '622920', '622921', '622922', '622923', '622924', '622925']
  876. },
  877. VISA: {
  878. length: [16],
  879. prefix: ['4']
  880. }
  881. };
  882. var type, i, creditCardType = null;
  883. for (type in cards) {
  884. for (i in cards[type]['prefix']) {
  885. if (creditCard.substr(0, cards[type]['prefix'][i].length) == cards[type]['prefix'][i] // Check the prefix
  886. && cards[type]['length'].indexOf(creditCard.length) != -1) // and length
  887. {
  888. creditCardType = type;
  889. break;
  890. }
  891. }
  892. }
  893. return (creditCardType == null)
  894. ? false
  895. : (('AMERICAN_EXPRESS' == creditCardType) ? (value.length == 4) : (value.length == 3));
  896. }
  897. };
  898. }(window.jQuery));
  899. ;(function($) {
  900. $.fn.bootstrapValidator.validators.date = {
  901. html5Attributes: ['message', 'format'],
  902. /**
  903. * Return true if the input value is valid date
  904. *
  905. * @param {BootstrapValidator} validator The validator plugin instance
  906. * @param {jQuery} $field Field element
  907. * @param {Object} options Can consist of the following keys:
  908. * - format: The date format. Default is MM/DD/YYYY
  909. * Support the following formats:
  910. * YYYY/DD/MM
  911. * YYYY/DD/MM h:m A
  912. * YYYY/MM/DD
  913. * YYYY/MM/DD h:m A
  914. *
  915. * YYYY-DD-MM
  916. * YYYY-DD-MM h:m A
  917. * YYYY-MM-DD
  918. * YYYY-MM-DD h:m A
  919. *
  920. * MM/DD/YYYY
  921. * MM/DD/YYYY h:m A
  922. * DD/MM/YYYY
  923. * DD/MM/YYYY h:m A
  924. *
  925. * MM-DD-YYYY
  926. * MM-DD-YYYY h:m A
  927. * DD-MM-YYYY
  928. * DD-MM-YYYY h:m A
  929. * - message: The invalid message
  930. * @returns {Boolean}
  931. */
  932. validate: function(validator, $field, options) {
  933. var value = $field.val();
  934. if (value == '') {
  935. return true;
  936. }
  937. // Determine the separator
  938. options.format = options.format || 'MM/DD/YYYY';
  939. var separator = (options.format.indexOf('/') != -1)
  940. ? '/'
  941. : ((options.format.indexOf('-') != -1) ? '-' : null);
  942. if (separator == null) {
  943. return false;
  944. }
  945. var month, day, year, minutes = null, hours = null, matches;
  946. switch (true) {
  947. case (separator == '/' && (matches = value.match(/^(\d{4})\/(\d{1,2})\/(\d{1,2})$/i)) && options.format == 'YYYY/DD/MM'):
  948. case (separator == '-' && (matches = value.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/i)) && options.format == 'YYYY-DD-MM'):
  949. year = matches[1]; day = matches[2]; month = matches[3];
  950. break;
  951. case (separator == '/' && (matches = value.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/i)) && options.format == 'DD/MM/YYYY'):
  952. case (separator == '-' && (matches = value.match(/^(\d{1,2})-(\d{1,2})-(\d{4})$/i)) && options.format == 'DD-MM-YYYY'):
  953. day = matches[1]; month = matches[2]; year = matches[3];
  954. break;
  955. case (separator == '/' && (matches = value.match(/^(\d{4})\/(\d{1,2})\/(\d{1,2})$/i)) && options.format == 'YYYY/MM/DD'):
  956. case (separator == '-' && (matches = value.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/i)) && options.format == 'YYYY-MM-DD'):
  957. year = matches[1]; month = matches[2]; day = matches[3];
  958. break;
  959. case (separator == '/' && (matches = value.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/i)) && options.format == 'MM/DD/YYYY'):
  960. case (separator == '-' && (matches = value.match(/^(\d{1,2})-(\d{1,2})-(\d{4})$/i)) && options.format == 'MM-DD-YYYY'):
  961. month = matches[1]; day = matches[2]; year = matches[3];
  962. break;
  963. case (separator == '/' && (matches = value.match(/^(\d{4})\/(\d{1,2})\/(\d{1,2})\s+(\d{1,2}):(\d{1,2})\s+(AM|PM)$/i)) && options.format == 'YYYY/DD/MM h:m A'):
  964. case (separator == '-' && (matches = value.match(/^(\d{4})-(\d{1,2})-(\d{1,2})\s+(\d{1,2}):(\d{1,2})\s+(AM|PM)$/i)) && options.format == 'YYYY-DD-MM h:m A'):
  965. year = matches[1]; day = matches[2]; month = matches[3]; hours = matches[4]; minutes = matches[5];
  966. break;
  967. case (separator == '/' && (matches = value.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})\s+(\d{1,2}):(\d{1,2})\s+(AM|PM)$/i)) && options.format == 'DD/MM/YYYY h:m A'):
  968. case (separator == '-' && (matches = value.match(/^(\d{1,2})-(\d{1,2})-(\d{4})\s+(\d{1,2}):(\d{1,2})\s+(AM|PM)$/i)) && options.format == 'DD-MM-YYYY h:m A'):
  969. day = matches[1]; month = matches[2]; year = matches[3]; hours = matches[4]; minutes = matches[5];
  970. break;
  971. case (separator == '/' && (matches = value.match(/^(\d{4})\/(\d{1,2})\/(\d{1,2})\s+(\d{1,2}):(\d{1,2})\s+(AM|PM)$/i)) && options.format == 'YYYY/MM/DD h:m A'):
  972. case (separator == '-' && (matches = value.match(/^(\d{4})-(\d{1,2})-(\d{1,2})\s+(\d{1,2}):(\d{1,2})\s+(AM|PM)$/i)) && options.format == 'YYYY-MM-DD h:m A'):
  973. year = matches[1]; month = matches[2]; day = matches[3]; hours = matches[4]; minutes = matches[5];
  974. break;
  975. case (separator == '/' && (matches = value.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})\s+(\d{1,2}):(\d{1,2})\s+(AM|PM)$/i)) && options.format == 'MM/DD/YYYY h:m A'):
  976. case (separator == '-' && (matches = value.match(/^(\d{1,2})-(\d{1,2})-(\d{4})\s+(\d{1,2}):(\d{1,2})\s+(AM|PM)$/i)) && options.format == 'MM-DD-YYYY h:m A'):
  977. month = matches[1]; day = matches[2]; year = matches[3]; hours = matches[4]; minutes = matches[5];
  978. break;
  979. default:
  980. return false;
  981. }
  982. // Validate hours and minutes
  983. if (hours && minutes) {
  984. hours = parseInt(hours, 10);
  985. minutes = parseInt(minutes, 10);
  986. if (hours < 1 || hours > 12 || minutes < 0 || minutes > 59) {
  987. return false;
  988. }
  989. }
  990. // Validate day, month, and year
  991. day = parseInt(day, 10);
  992. month = parseInt(month, 10);
  993. year = parseInt(year, 10);
  994. if (year < 1000 || year > 9999 || month == 0 || month > 12) {
  995. return false;
  996. }
  997. var numDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  998. // Update the number of days in Feb of leap year
  999. if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
  1000. numDays[1] = 29;
  1001. }
  1002. // Check the day
  1003. return (day > 0 && day <= numDays[month - 1]);
  1004. }
  1005. };
  1006. }(window.jQuery));
  1007. ;(function($) {
  1008. $.fn.bootstrapValidator.validators.different = {
  1009. html5Attributes: ['message', 'field'],
  1010. /**
  1011. * Return true if the input value is different with given field's value
  1012. *
  1013. * @param {BootstrapValidator} validator The validator plugin instance
  1014. * @param {jQuery} $field Field element
  1015. * @param {Object} options Consists of the following key:
  1016. * - field: The name of field that will be used to compare with current one
  1017. * - message: The invalid message
  1018. * @returns {Boolean}
  1019. */
  1020. validate: function(validator, $field, options) {
  1021. var value = $field.val();
  1022. if (value == '') {
  1023. return true;
  1024. }
  1025. var compareWith = validator.getFieldElements(options.field);
  1026. if (compareWith == null) {
  1027. return true;
  1028. }
  1029. if (value != compareWith.val()) {
  1030. validator.updateStatus(options.field, validator.STATUS_VALID, 'different');
  1031. return true;
  1032. } else {
  1033. return false;
  1034. }
  1035. }
  1036. };
  1037. }(window.jQuery));
  1038. ;(function($) {
  1039. $.fn.bootstrapValidator.validators.digits = {
  1040. /**
  1041. * Return true if the input value contains digits only
  1042. *
  1043. * @param {BootstrapValidator} validator Validate plugin instance
  1044. * @param {jQuery} $field Field element
  1045. * @param {Object} options
  1046. * @returns {Boolean}
  1047. */
  1048. validate: function(validator, $field, options) {
  1049. var value = $field.val();
  1050. if (value == '') {
  1051. return true;
  1052. }
  1053. return /^\d+$/.test(value);
  1054. }
  1055. }
  1056. }(window.jQuery));
  1057. ;(function($) {
  1058. $.fn.bootstrapValidator.validators.emailAddress = {
  1059. enableByHtml5: function($field) {
  1060. return ('email' == $field.attr('type'));
  1061. },
  1062. /**
  1063. * Return true if and only if the input value is a valid email address
  1064. *
  1065. * @param {BootstrapValidator} validator Validate plugin instance
  1066. * @param {jQuery} $field Field element
  1067. * @param {Object} options
  1068. * @returns {Boolean}
  1069. */
  1070. validate: function(validator, $field, options) {
  1071. var value = $field.val();
  1072. if (value == '') {
  1073. return true;
  1074. }
  1075. // Email address regular expression
  1076. // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
  1077. var emailRegExp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  1078. return emailRegExp.test(value);
  1079. }
  1080. }
  1081. }(window.jQuery));
  1082. ;(function($) {
  1083. $.fn.bootstrapValidator.validators.greaterThan = {
  1084. html5Attributes: ['message', 'value', 'inclusive'],
  1085. enableByHtml5: function($field) {
  1086. var min = $field.attr('min');
  1087. if (min) {
  1088. return {
  1089. value: min
  1090. };
  1091. }
  1092. return false;
  1093. },
  1094. /**
  1095. * Return true if the input value is greater than or equals to given number
  1096. *
  1097. * @param {BootstrapValidator} validator Validate plugin instance
  1098. * @param {jQuery} $field Field element
  1099. * @param {Object} options Can consist of the following keys:
  1100. * - value: The number used to compare to
  1101. * - inclusive [optional]: Can be true or false. Default is true
  1102. * - message: The invalid message
  1103. * @returns {Boolean}
  1104. */
  1105. validate: function(validator, $field, options) {
  1106. var value = $field.val();
  1107. if (value == '') {
  1108. return true;
  1109. }
  1110. value = parseFloat(value);
  1111. return (options.inclusive === true) ? (value > options.value) : (value >= options.value);
  1112. }
  1113. }
  1114. }(window.jQuery));
  1115. ;(function($) {
  1116. $.fn.bootstrapValidator.validators.hexColor = {
  1117. enableByHtml5: function($field) {
  1118. return ('color' == $field.attr('type'));
  1119. },
  1120. /**
  1121. * Return true if the input value is a valid hex color
  1122. *
  1123. * @param {BootstrapValidator} validator The validator plugin instance
  1124. * @param {jQuery} $field Field element
  1125. * @param {Object} options Can consist of the following keys:
  1126. * - message: The invalid message
  1127. * @returns {Boolean}
  1128. */
  1129. validate: function(validator, $field, options) {
  1130. var value = $field.val();
  1131. if (value == '') {
  1132. return true;
  1133. }
  1134. return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(value);
  1135. }
  1136. };
  1137. }(window.jQuery));
  1138. ;(function($) {
  1139. $.fn.bootstrapValidator.validators.identical = {
  1140. html5Attributes: ['message', 'field'],
  1141. /**
  1142. * Check if input value equals to value of particular one
  1143. *
  1144. * @param {BootstrapValidator} validator The validator plugin instance
  1145. * @param {jQuery} $field Field element
  1146. * @param {Object} options Consists of the following key:
  1147. * - field: The name of field that will be used to compare with current one
  1148. * @returns {Boolean}
  1149. */
  1150. validate: function(validator, $field, options) {
  1151. var value = $field.val();
  1152. if (value == '') {
  1153. return true;
  1154. }
  1155. var compareWith = validator.getFieldElements(options.field);
  1156. if (compareWith == null) {
  1157. return true;
  1158. }
  1159. if (value == compareWith.val()) {
  1160. validator.updateStatus(options.field, validator.STATUS_VALID, 'identical');
  1161. return true;
  1162. } else {
  1163. return false;
  1164. }
  1165. }
  1166. };
  1167. }(window.jQuery));
  1168. ;(function($) {
  1169. $.fn.bootstrapValidator.validators.integer = {
  1170. enableByHtml5: function($field) {
  1171. return ('number' == $field.attr('type'));
  1172. },
  1173. /**
  1174. * Return true if the input value is an integer
  1175. *
  1176. * @param {BootstrapValidator} validator The validator plugin instance
  1177. * @param {jQuery} $field Field element
  1178. * @param {Object} options Can consist of the following key:
  1179. * - message: The invalid message
  1180. * @returns {Boolean}
  1181. */
  1182. validate: function(validator, $field, options) {
  1183. var value = $field.val();
  1184. if (value == '') {
  1185. return true;
  1186. }
  1187. return /^(?:-?(?:0|[1-9][0-9]*))$/.test(value);
  1188. }
  1189. };
  1190. }(window.jQuery));
  1191. ;(function($) {
  1192. $.fn.bootstrapValidator.validators.ip = {
  1193. html5Attributes: ['message', 'ipv4', 'ipv6'],
  1194. /**
  1195. * Return true if the input value is a IP address.
  1196. *
  1197. * @param {BootstrapValidator} validator The validator plugin instance
  1198. * @param {jQuery} $field Field element
  1199. * @param {Object} options Can consist of the following keys:
  1200. * - ipv4: Enable IPv4 validator, default to true
  1201. * - ipv6: Enable IPv6 validator, default to true
  1202. * - message: The invalid message
  1203. * @returns {Boolean}
  1204. */
  1205. validate: function(validator, $field, options) {
  1206. var value = $field.val();
  1207. if (value == '') {
  1208. return true;
  1209. }
  1210. options = $.extend({}, { ipv4: true, ipv6: true }, options);
  1211. if (options.ipv4) {
  1212. return /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(value);
  1213. } else if (options.ipv6) {
  1214. return /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(str);
  1215. }
  1216. return false;
  1217. }
  1218. };
  1219. }(window.jQuery));
  1220. ;(function($) {
  1221. $.fn.bootstrapValidator.validators.isbn = {
  1222. /**
  1223. * Return true if the input value is a valid ISBN 10 or ISBN 13 number
  1224. *
  1225. * @param {BootstrapValidator} validator The validator plugin instance
  1226. * @param {jQuery} $field Field element
  1227. * @param {Object} options Can consist of the following keys:
  1228. * - message: The invalid message
  1229. * @returns {Boolean}
  1230. */
  1231. validate: function(validator, $field, options) {
  1232. var value = $field.val();
  1233. if (value == '') {
  1234. return true;
  1235. }
  1236. // Replace all special characters except digits and X
  1237. value = value.replace(/[^\dX]/gi, '');
  1238. var chars = value.split(''),
  1239. sum = 0,
  1240. checksum;
  1241. // See http://en.wikipedia.org/wiki/International_Standard_Book_Number
  1242. switch (chars.length) {
  1243. // ISBN 10
  1244. case 10:
  1245. sum = 0;
  1246. for (var i = 0; i < 9; i++) {
  1247. sum += ((10 - i) * parseInt(chars[i]));
  1248. }
  1249. checksum = 11 - (sum % 11);
  1250. if (checksum == 11) {
  1251. checksum = 0;
  1252. } else if (checksum == 10) {
  1253. checksum = 'X';
  1254. }
  1255. return (checksum == chars[9]);
  1256. // ISBN 13
  1257. case 13:
  1258. sum = 0;
  1259. for (var i = 0; i < 12; i++) {
  1260. sum += ((i % 2 == 0) ? parseInt(chars[i]) : (parseInt(chars[i]) * 3));
  1261. }
  1262. checksum = 10 - (sum % 10);
  1263. if (checksum == 10) {
  1264. checksum = '0';
  1265. }
  1266. return (checksum == chars[12]);
  1267. default:
  1268. return false;
  1269. }
  1270. }
  1271. };
  1272. }(window.jQuery));
  1273. ;(function($) {
  1274. $.fn.bootstrapValidator.validators.lessThan = {
  1275. html5Attributes: ['message', 'value', 'inclusive'],
  1276. enableByHtml5: function($field) {
  1277. var max = $field.attr('max');
  1278. if (max) {
  1279. return {
  1280. value: max
  1281. };
  1282. }
  1283. return false;
  1284. },
  1285. /**
  1286. * Return true if the input value is less than or equal to given number
  1287. *
  1288. * @param {BootstrapValidator} validator The validator plugin instance
  1289. * @param {jQuery} $field Field element
  1290. * @param {Object} options Can consist of the following keys:
  1291. * - value: The number used to compare to
  1292. * - inclusive [optional]: Can be true or false. Default is true
  1293. * - message: The invalid message
  1294. * @returns {Boolean}
  1295. */
  1296. validate: function(validator, $field, options) {
  1297. var value = $field.val();
  1298. if (value == '') {
  1299. return true;
  1300. }
  1301. value = parseFloat(value);
  1302. return (options.inclusive === false) ? (value <= options.value) : (value < options.value);
  1303. }
  1304. };
  1305. }(window.jQuery));
  1306. ;(function($) {
  1307. $.fn.bootstrapValidator.validators.mac = {
  1308. /**
  1309. * Return true if the input value is a MAC address.
  1310. *
  1311. * @param {BootstrapValidator} validator The validator plugin instance
  1312. * @param {jQuery} $field Field element
  1313. * @param {Object} options Can consist of the following keys:
  1314. * - message: The invalid message
  1315. * @returns {Boolean}
  1316. */
  1317. validate: function(validator, $field, options) {
  1318. var value = $field.val();
  1319. if (value == '') {
  1320. return true;
  1321. }
  1322. return /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/.test(value);
  1323. }
  1324. };
  1325. }(window.jQuery));
  1326. ;(function($) {
  1327. $.fn.bootstrapValidator.validators.notEmpty = {
  1328. enableByHtml5: function($field) {
  1329. var required = $field.attr('required') + '';
  1330. return ('required' == required || 'true' == required);
  1331. },
  1332. /**
  1333. * Check if input value is empty or not
  1334. *
  1335. * @param {BootstrapValidator} validator The validator plugin instance
  1336. * @param {jQuery} $field Field element
  1337. * @param {Object} options
  1338. * @returns {Boolean}
  1339. */
  1340. validate: function(validator, $field, options) {
  1341. var type = $field.attr('type');
  1342. if ('radio' == type || 'checkbox' == type) {
  1343. return validator
  1344. .getFieldElements($field.attr('data-bv-field'))
  1345. .filter(':checked')
  1346. .length > 0;
  1347. }
  1348. return $.trim($field.val()) != '';
  1349. }
  1350. };
  1351. }(window.jQuery));
  1352. ;(function($) {
  1353. $.fn.bootstrapValidator.validators.phone = {
  1354. html5Attributes: ['message', 'country'],
  1355. /**
  1356. * Return true if the input value contains a valid US phone number only
  1357. *
  1358. * @param {BootstrapValidator} validator Validate plugin instance
  1359. * @param {jQuery} $field Field element
  1360. * @param {Object} options Consist of key:
  1361. * - message: The invalid message
  1362. * - country: The ISO 3166 country code
  1363. * Currently it only supports United State (US) country
  1364. * @returns {Boolean}
  1365. */
  1366. validate: function(validator, $field, options) {
  1367. var value = $field.val();
  1368. if (value == '') {
  1369. return true;
  1370. }
  1371. options.country = options.country || 'US';
  1372. switch (options.country.toUpperCase()) {
  1373. case 'US':
  1374. default:
  1375. value = value.replace(/\(|\)|\s+/g, '');
  1376. return (/^(?:1\-?)?(\d{3})[\-\.]?(\d{3})[\-\.]?(\d{4})$/).test(value);
  1377. }
  1378. }
  1379. }
  1380. }(window.jQuery));
  1381. ;(function($) {
  1382. $.fn.bootstrapValidator.validators.regexp = {
  1383. html5Attributes: ['message', 'regexp'],
  1384. enableByHtml5: function($field) {
  1385. var pattern = $field.attr('pattern');
  1386. if (pattern) {
  1387. return {
  1388. regexp: pattern
  1389. };
  1390. }
  1391. return false;
  1392. },
  1393. /**
  1394. * Check if the element value matches given regular expression
  1395. *
  1396. * @param {BootstrapValidator} validator The validator plugin instance
  1397. * @param {jQuery} $field Field element
  1398. * @param {Object} options Consists of the following key:
  1399. * - regexp: The regular expression you need to check
  1400. * @returns {Boolean}
  1401. */
  1402. validate: function(validator, $field, options) {
  1403. var value = $field.val();
  1404. if (value == '') {
  1405. return true;
  1406. }
  1407. var regexp = ('string' == typeof options.regexp) ? new RegExp(options.regexp) : options.regexp;
  1408. return regexp.test(value);
  1409. }
  1410. };
  1411. }(window.jQuery));
  1412. ;(function($) {
  1413. $.fn.bootstrapValidator.validators.remote = {
  1414. html5Attributes: ['message', 'url'],
  1415. /**
  1416. * Request a remote server to check the input value
  1417. *
  1418. * @param {BootstrapValidator} validator Plugin instance
  1419. * @param {jQuery} $field Field element
  1420. * @param {Object} options Can consist of the following keys:
  1421. * - url
  1422. * - data [optional]: By default, it will take the value
  1423. * {
  1424. * <fieldName>: <fieldValue>
  1425. * }
  1426. * - message: The invalid message
  1427. * @returns {Boolean|Deferred}
  1428. */
  1429. validate: function(validator, $field, options) {
  1430. var value = $field.val();
  1431. if (value == '') {
  1432. return true;
  1433. }
  1434. var name = $field.attr('data-bv-field'), data = options.data;
  1435. if (data == null) {
  1436. data = {};
  1437. }
  1438. // Support dynamic data
  1439. if ('function' == typeof data) {
  1440. data = data.call(this, validator);
  1441. }
  1442. data[name] = value;
  1443. var dfd = new $.Deferred();
  1444. var xhr = $.ajax({
  1445. type: 'POST',
  1446. url: options.url,
  1447. dataType: 'json',
  1448. data: data
  1449. });
  1450. xhr.then(function(response) {
  1451. dfd.resolve($field, 'remote', response.valid === true || response.valid === 'true');
  1452. });
  1453. dfd.fail(function() {
  1454. xhr.abort();
  1455. });
  1456. return dfd;
  1457. }
  1458. };
  1459. }(window.jQuery));
  1460. ;(function($) {
  1461. $.fn.bootstrapValidator.validators.step = {
  1462. /**
  1463. * Return true if the input value is valid step one
  1464. *
  1465. * @param {BootstrapValidator} validator The validator plugin instance
  1466. * @param {jQuery} $field Field element
  1467. * @param {Object} options Can consist of the following keys:
  1468. * - baseValue: The base value
  1469. * - step: The step
  1470. * - message: The invalid message
  1471. * @returns {Boolean}
  1472. */
  1473. validate: function(validator, $field, options) {
  1474. var value = $field.val();
  1475. if (value == '') {
  1476. return true;
  1477. }
  1478. options = $.extend({}, { baseValue: 0, step: 1 }, options);
  1479. value = parseFloat(value);
  1480. if (isNaN(value) || !isFinite(value)) {
  1481. return false;
  1482. }
  1483. var round = function(x, precision) {
  1484. var m = Math.pow(10, precision);
  1485. x = x * m;
  1486. var sign = (x > 0) | -(x < 0),
  1487. isHalf = (x % 1 === 0.5 * sign);
  1488. if (isHalf) {
  1489. return (Math.floor(x) + (sign > 0)) / m;
  1490. } else {
  1491. return Math.round(x) / m;
  1492. }
  1493. },
  1494. floatMod = function(x, y) {
  1495. if (y == 0.0) {
  1496. return 1.0;
  1497. }
  1498. var dotX = (x + '').split('.'),
  1499. dotY = (y + '').split('.'),
  1500. precision = ((dotX.length == 1) ? 0 : dotX[1].length) + ((dotY.length == 1) ? 0 : dotY[1].length);
  1501. return round(x - y * Math.floor(x / y), precision);
  1502. };
  1503. var mod = floatMod(value - options.baseValue, options.step);
  1504. return (mod == 0.0 || mod == options.step);
  1505. }
  1506. };
  1507. }(window.jQuery));
  1508. ;(function($) {
  1509. $.fn.bootstrapValidator.validators.stringLength = {
  1510. html5Attributes: ['message', 'min', 'max'],
  1511. enableByHtml5: function($field) {
  1512. var maxLength = $field.attr('maxlength');
  1513. if (maxLength) {
  1514. return {
  1515. max: parseInt(maxLength, 10)
  1516. };
  1517. }
  1518. return maxLength;
  1519. },
  1520. /**
  1521. * Check if the length of element value is less or more than given number
  1522. *
  1523. * @param {BootstrapValidator} validator The validator plugin instance
  1524. * @param {jQuery} $field Field element
  1525. * @param {Object} options Consists of following keys:
  1526. * - min
  1527. * - max
  1528. * At least one of two keys is required
  1529. * @returns {Boolean}
  1530. */
  1531. validate: function(validator, $field, options) {
  1532. var value = $field.val();
  1533. if (value == '') {
  1534. return true;
  1535. }
  1536. var length = $.trim(value).length;
  1537. if ((options.min && length < options.min) || (options.max && length > options.max)) {
  1538. return false;
  1539. }
  1540. return true;
  1541. }
  1542. };
  1543. }(window.jQuery));
  1544. ;(function($) {
  1545. $.fn.bootstrapValidator.validators.uri = {
  1546. enableByHtml5: function($field) {
  1547. return ('url' == $field.attr('type'));
  1548. },
  1549. /**
  1550. * Return true if the input value is a valid URL
  1551. *
  1552. * @param {BootstrapValidator} validator The validator plugin instance
  1553. * @param {jQuery} $field Field element
  1554. * @param {Object} options
  1555. * @returns {Boolean}
  1556. */
  1557. validate: function(validator, $field, options) {
  1558. var value = $field.val();
  1559. if (value == '') {
  1560. return true;
  1561. }
  1562. // Credit to https://gist.github.com/dperini/729294
  1563. //
  1564. // Regular Expression for URL validation
  1565. //
  1566. // Author: Diego Perini
  1567. // Updated: 2010/12/05
  1568. //
  1569. // the regular expression composed & commented
  1570. // could be easily tweaked for RFC compliance,
  1571. // it was expressly modified to fit & satisfy
  1572. // these test for an URL shortener:
  1573. //
  1574. // http://mathiasbynens.be/demo/url-regex
  1575. //
  1576. // Notes on possible differences from a standard/generic validation:
  1577. //
  1578. // - utf-8 char class take in consideration the full Unicode range
  1579. // - TLDs have been made mandatory so single names like "localhost" fails
  1580. // - protocols have been restricted to ftp, http and https only as requested
  1581. //
  1582. // Changes:
  1583. //
  1584. // - IP address dotted notation validation, range: 1.0.0.0 - 223.255.255.255
  1585. // first and last IP address of each class is considered invalid
  1586. // (since they are broadcast/network addresses)
  1587. //
  1588. // - Added exclusion of private, reserved and/or local networks ranges
  1589. //
  1590. // Compressed one-line versions:
  1591. //
  1592. // Javascript version
  1593. //
  1594. // /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i
  1595. //
  1596. // PHP version
  1597. //
  1598. // _^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:/[^\s]*)?$_iuS
  1599. var urlExp = new RegExp(
  1600. "^" +
  1601. // protocol identifier
  1602. "(?:(?:https?|ftp)://)" +
  1603. // user:pass authentication
  1604. "(?:\\S+(?::\\S*)?@)?" +
  1605. "(?:" +
  1606. // IP address exclusion
  1607. // private & local networks
  1608. "(?!10(?:\\.\\d{1,3}){3})" +
  1609. "(?!127(?:\\.\\d{1,3}){3})" +
  1610. "(?!169\\.254(?:\\.\\d{1,3}){2})" +
  1611. "(?!192\\.168(?:\\.\\d{1,3}){2})" +
  1612. "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" +
  1613. // IP address dotted notation octets
  1614. // excludes loopback network 0.0.0.0
  1615. // excludes reserved space >= 224.0.0.0
  1616. // excludes network & broacast addresses
  1617. // (first & last IP address of each class)
  1618. "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
  1619. "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
  1620. "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
  1621. "|" +
  1622. // host name
  1623. "(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)" +
  1624. // domain name
  1625. "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*" +
  1626. // TLD identifier
  1627. "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
  1628. ")" +
  1629. // port number
  1630. "(?::\\d{2,5})?" +
  1631. // resource path
  1632. "(?:/[^\\s]*)?" +
  1633. "$", "i"
  1634. );
  1635. return urlExp.test(value);
  1636. }
  1637. };
  1638. }(window.jQuery));
  1639. ;(function($) {
  1640. $.fn.bootstrapValidator.validators.zipCode = {
  1641. html5Attributes: ['message', 'country'],
  1642. /**
  1643. * Return true if and only if the input value is a valid country zip code
  1644. *
  1645. * @param {BootstrapValidator} validator The validator plugin instance
  1646. * @param {jQuery} $field Field element
  1647. * @param {Object} options Consist of key:
  1648. * - message: The invalid message
  1649. * - country: The ISO 3166 country code
  1650. *
  1651. * Currently it supports the following countries:
  1652. * - US (United State)
  1653. * - DK (Denmark)
  1654. * - SE (Sweden)
  1655. * @returns {Boolean}
  1656. */
  1657. validate: function(validator, $field, options) {
  1658. var value = $field.val();
  1659. if (value == '' || !options.country) {
  1660. return true;
  1661. }
  1662. options.country = options.country || 'US';
  1663. switch (options.country.toUpperCase()) {
  1664. case 'DK':
  1665. return /^(DK(-|\s)?)?\d{4}$/i.test(value);
  1666. case 'SE':
  1667. return /^(S-)?\d{3}\s?\d{2}$/i.test(value);
  1668. case 'US':
  1669. default:
  1670. return /^\d{5}([\-]\d{4})?$/.test(value);
  1671. }
  1672. }
  1673. };
  1674. }(window.jQuery));