Personal portfolio website created with bootstrap.
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.

912 lines
35 KiB

  1. /* jqBootstrapValidation
  2. * A plugin for automating validation on Twitter Bootstrap formatted forms.
  3. *
  4. * v1.3.6
  5. *
  6. * License: MIT <http://opensource.org/licenses/mit-license.php> - see LICENSE file
  7. *
  8. * http://ReactiveRaven.github.com/jqBootstrapValidation/
  9. */
  10. (function( $ ){
  11. var createdElements = [];
  12. var defaults = {
  13. options: {
  14. prependExistingHelpBlock: false,
  15. sniffHtml: true, // sniff for 'required', 'maxlength', etc
  16. preventSubmit: true, // stop the form submit event from firing if validation fails
  17. submitError: false, // function called if there is an error when trying to submit
  18. submitSuccess: false, // function called just before a successful submit event is sent to the server
  19. semanticallyStrict: false, // set to true to tidy up generated HTML output
  20. autoAdd: {
  21. helpBlocks: true
  22. },
  23. filter: function () {
  24. // return $(this).is(":visible"); // only validate elements you can see
  25. return true; // validate everything
  26. }
  27. },
  28. methods: {
  29. init : function( options ) {
  30. var settings = $.extend(true, {}, defaults);
  31. settings.options = $.extend(true, settings.options, options);
  32. var $siblingElements = this;
  33. var uniqueForms = $.unique(
  34. $siblingElements.map( function () {
  35. return $(this).parents("form")[0];
  36. }).toArray()
  37. );
  38. $(uniqueForms).bind("submit", function (e) {
  39. var $form = $(this);
  40. var warningsFound = 0;
  41. var $inputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter);
  42. $inputs.trigger("submit.validation").trigger("validationLostFocus.validation");
  43. $inputs.each(function (i, el) {
  44. var $this = $(el),
  45. $controlGroup = $this.parents(".control-group").first();
  46. if (
  47. $controlGroup.hasClass("warning")
  48. ) {
  49. $controlGroup.removeClass("warning").addClass("error");
  50. warningsFound++;
  51. }
  52. });
  53. $inputs.trigger("validationLostFocus.validation");
  54. if (warningsFound) {
  55. if (settings.options.preventSubmit) {
  56. e.preventDefault();
  57. }
  58. $form.addClass("error");
  59. if ($.isFunction(settings.options.submitError)) {
  60. settings.options.submitError($form, e, $inputs.jqBootstrapValidation("collectErrors", true));
  61. }
  62. } else {
  63. $form.removeClass("error");
  64. if ($.isFunction(settings.options.submitSuccess)) {
  65. settings.options.submitSuccess($form, e);
  66. }
  67. }
  68. });
  69. return this.each(function(){
  70. // Get references to everything we're interested in
  71. var $this = $(this),
  72. $controlGroup = $this.parents(".control-group").first(),
  73. $helpBlock = $controlGroup.find(".help-block").first(),
  74. $form = $this.parents("form").first(),
  75. validatorNames = [];
  76. // create message container if not exists
  77. if (!$helpBlock.length && settings.options.autoAdd && settings.options.autoAdd.helpBlocks) {
  78. $helpBlock = $('<div class="help-block" />');
  79. $controlGroup.find('.controls').append($helpBlock);
  80. createdElements.push($helpBlock[0]);
  81. }
  82. // =============================================================
  83. // SNIFF HTML FOR VALIDATORS
  84. // =============================================================
  85. // *snort sniff snuffle*
  86. if (settings.options.sniffHtml) {
  87. var message = "";
  88. // ---------------------------------------------------------
  89. // PATTERN
  90. // ---------------------------------------------------------
  91. if ($this.attr("pattern") !== undefined) {
  92. message = "Not in the expected format<!-- data-validation-pattern-message to override -->";
  93. if ($this.data("validationPatternMessage")) {
  94. message = $this.data("validationPatternMessage");
  95. }
  96. $this.data("validationPatternMessage", message);
  97. $this.data("validationPatternRegex", $this.attr("pattern"));
  98. }
  99. // ---------------------------------------------------------
  100. // MAX
  101. // ---------------------------------------------------------
  102. if ($this.attr("max") !== undefined || $this.attr("aria-valuemax") !== undefined) {
  103. var max = ($this.attr("max") !== undefined ? $this.attr("max") : $this.attr("aria-valuemax"));
  104. message = "Too high: Maximum of '" + max + "'<!-- data-validation-max-message to override -->";
  105. if ($this.data("validationMaxMessage")) {
  106. message = $this.data("validationMaxMessage");
  107. }
  108. $this.data("validationMaxMessage", message);
  109. $this.data("validationMaxMax", max);
  110. }
  111. // ---------------------------------------------------------
  112. // MIN
  113. // ---------------------------------------------------------
  114. if ($this.attr("min") !== undefined || $this.attr("aria-valuemin") !== undefined) {
  115. var min = ($this.attr("min") !== undefined ? $this.attr("min") : $this.attr("aria-valuemin"));
  116. message = "Too low: Minimum of '" + min + "'<!-- data-validation-min-message to override -->";
  117. if ($this.data("validationMinMessage")) {
  118. message = $this.data("validationMinMessage");
  119. }
  120. $this.data("validationMinMessage", message);
  121. $this.data("validationMinMin", min);
  122. }
  123. // ---------------------------------------------------------
  124. // MAXLENGTH
  125. // ---------------------------------------------------------
  126. if ($this.attr("maxlength") !== undefined) {
  127. message = "Too long: Maximum of '" + $this.attr("maxlength") + "' characters<!-- data-validation-maxlength-message to override -->";
  128. if ($this.data("validationMaxlengthMessage")) {
  129. message = $this.data("validationMaxlengthMessage");
  130. }
  131. $this.data("validationMaxlengthMessage", message);
  132. $this.data("validationMaxlengthMaxlength", $this.attr("maxlength"));
  133. }
  134. // ---------------------------------------------------------
  135. // MINLENGTH
  136. // ---------------------------------------------------------
  137. if ($this.attr("minlength") !== undefined) {
  138. message = "Too short: Minimum of '" + $this.attr("minlength") + "' characters<!-- data-validation-minlength-message to override -->";
  139. if ($this.data("validationMinlengthMessage")) {
  140. message = $this.data("validationMinlengthMessage");
  141. }
  142. $this.data("validationMinlengthMessage", message);
  143. $this.data("validationMinlengthMinlength", $this.attr("minlength"));
  144. }
  145. // ---------------------------------------------------------
  146. // REQUIRED
  147. // ---------------------------------------------------------
  148. if ($this.attr("required") !== undefined || $this.attr("aria-required") !== undefined) {
  149. message = settings.builtInValidators.required.message;
  150. if ($this.data("validationRequiredMessage")) {
  151. message = $this.data("validationRequiredMessage");
  152. }
  153. $this.data("validationRequiredMessage", message);
  154. }
  155. // ---------------------------------------------------------
  156. // NUMBER
  157. // ---------------------------------------------------------
  158. if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "number") {
  159. message = settings.builtInValidators.number.message;
  160. if ($this.data("validationNumberMessage")) {
  161. message = $this.data("validationNumberMessage");
  162. }
  163. $this.data("validationNumberMessage", message);
  164. }
  165. // ---------------------------------------------------------
  166. // EMAIL
  167. // ---------------------------------------------------------
  168. if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "email") {
  169. message = "Not a valid email address<!-- data-validator-validemail-message to override -->";
  170. if ($this.data("validationValidemailMessage")) {
  171. message = $this.data("validationValidemailMessage");
  172. } else if ($this.data("validationEmailMessage")) {
  173. message = $this.data("validationEmailMessage");
  174. }
  175. $this.data("validationValidemailMessage", message);
  176. }
  177. // ---------------------------------------------------------
  178. // MINCHECKED
  179. // ---------------------------------------------------------
  180. if ($this.attr("minchecked") !== undefined) {
  181. message = "Not enough options checked; Minimum of '" + $this.attr("minchecked") + "' required<!-- data-validation-minchecked-message to override -->";
  182. if ($this.data("validationMincheckedMessage")) {
  183. message = $this.data("validationMincheckedMessage");
  184. }
  185. $this.data("validationMincheckedMessage", message);
  186. $this.data("validationMincheckedMinchecked", $this.attr("minchecked"));
  187. }
  188. // ---------------------------------------------------------
  189. // MAXCHECKED
  190. // ---------------------------------------------------------
  191. if ($this.attr("maxchecked") !== undefined) {
  192. message = "Too many options checked; Maximum of '" + $this.attr("maxchecked") + "' required<!-- data-validation-maxchecked-message to override -->";
  193. if ($this.data("validationMaxcheckedMessage")) {
  194. message = $this.data("validationMaxcheckedMessage");
  195. }
  196. $this.data("validationMaxcheckedMessage", message);
  197. $this.data("validationMaxcheckedMaxchecked", $this.attr("maxchecked"));
  198. }
  199. }
  200. // =============================================================
  201. // COLLECT VALIDATOR NAMES
  202. // =============================================================
  203. // Get named validators
  204. if ($this.data("validation") !== undefined) {
  205. validatorNames = $this.data("validation").split(",");
  206. }
  207. // Get extra ones defined on the element's data attributes
  208. $.each($this.data(), function (i, el) {
  209. var parts = i.replace(/([A-Z])/g, ",$1").split(",");
  210. if (parts[0] === "validation" && parts[1]) {
  211. validatorNames.push(parts[1]);
  212. }
  213. });
  214. // =============================================================
  215. // NORMALISE VALIDATOR NAMES
  216. // =============================================================
  217. var validatorNamesToInspect = validatorNames;
  218. var newValidatorNamesToInspect = [];
  219. do // repeatedly expand 'shortcut' validators into their real validators
  220. {
  221. // Uppercase only the first letter of each name
  222. $.each(validatorNames, function (i, el) {
  223. validatorNames[i] = formatValidatorName(el);
  224. });
  225. // Remove duplicate validator names
  226. validatorNames = $.unique(validatorNames);
  227. // Pull out the new validator names from each shortcut
  228. newValidatorNamesToInspect = [];
  229. $.each(validatorNamesToInspect, function(i, el) {
  230. if ($this.data("validation" + el + "Shortcut") !== undefined) {
  231. // Are these custom validators?
  232. // Pull them out!
  233. $.each($this.data("validation" + el + "Shortcut").split(","), function(i2, el2) {
  234. newValidatorNamesToInspect.push(el2);
  235. });
  236. } else if (settings.builtInValidators[el.toLowerCase()]) {
  237. // Is this a recognised built-in?
  238. // Pull it out!
  239. var validator = settings.builtInValidators[el.toLowerCase()];
  240. if (validator.type.toLowerCase() === "shortcut") {
  241. $.each(validator.shortcut.split(","), function (i, el) {
  242. el = formatValidatorName(el);
  243. newValidatorNamesToInspect.push(el);
  244. validatorNames.push(el);
  245. });
  246. }
  247. }
  248. });
  249. validatorNamesToInspect = newValidatorNamesToInspect;
  250. } while (validatorNamesToInspect.length > 0)
  251. // =============================================================
  252. // SET UP VALIDATOR ARRAYS
  253. // =============================================================
  254. var validators = {};
  255. $.each(validatorNames, function (i, el) {
  256. // Set up the 'override' message
  257. var message = $this.data("validation" + el + "Message");
  258. var hasOverrideMessage = (message !== undefined);
  259. var foundValidator = false;
  260. message =
  261. (
  262. message
  263. ? message
  264. : "'" + el + "' validation failed <!-- Add attribute 'data-validation-" + el.toLowerCase() + "-message' to input to change this message -->"
  265. )
  266. ;
  267. $.each(
  268. settings.validatorTypes,
  269. function (validatorType, validatorTemplate) {
  270. if (validators[validatorType] === undefined) {
  271. validators[validatorType] = [];
  272. }
  273. if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) {
  274. validators[validatorType].push(
  275. $.extend(
  276. true,
  277. {
  278. name: formatValidatorName(validatorTemplate.name),
  279. message: message
  280. },
  281. validatorTemplate.init($this, el)
  282. )
  283. );
  284. foundValidator = true;
  285. }
  286. }
  287. );
  288. if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) {
  289. var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]);
  290. if (hasOverrideMessage) {
  291. validator.message = message;
  292. }
  293. var validatorType = validator.type.toLowerCase();
  294. if (validatorType === "shortcut") {
  295. foundValidator = true;
  296. } else {
  297. $.each(
  298. settings.validatorTypes,
  299. function (validatorTemplateType, validatorTemplate) {
  300. if (validators[validatorTemplateType] === undefined) {
  301. validators[validatorTemplateType] = [];
  302. }
  303. if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) {
  304. $this.data("validation" + el + formatValidatorName(validatorTemplate.name), validator[validatorTemplate.name.toLowerCase()]);
  305. validators[validatorType].push(
  306. $.extend(
  307. validator,
  308. validatorTemplate.init($this, el)
  309. )
  310. );
  311. foundValidator = true;
  312. }
  313. }
  314. );
  315. }
  316. }
  317. if (! foundValidator) {
  318. $.error("Cannot find validation info for '" + el + "'");
  319. }
  320. });
  321. // =============================================================
  322. // STORE FALLBACK VALUES
  323. // =============================================================
  324. $helpBlock.data(
  325. "original-contents",
  326. (
  327. $helpBlock.data("original-contents")
  328. ? $helpBlock.data("original-contents")
  329. : $helpBlock.html()
  330. )
  331. );
  332. $helpBlock.data(
  333. "original-role",
  334. (
  335. $helpBlock.data("original-role")
  336. ? $helpBlock.data("original-role")
  337. : $helpBlock.attr("role")
  338. )
  339. );
  340. $controlGroup.data(
  341. "original-classes",
  342. (
  343. $controlGroup.data("original-clases")
  344. ? $controlGroup.data("original-classes")
  345. : $controlGroup.attr("class")
  346. )
  347. );
  348. $this.data(
  349. "original-aria-invalid",
  350. (
  351. $this.data("original-aria-invalid")
  352. ? $this.data("original-aria-invalid")
  353. : $this.attr("aria-invalid")
  354. )
  355. );
  356. // =============================================================
  357. // VALIDATION
  358. // =============================================================
  359. $this.bind(
  360. "validation.validation",
  361. function (event, params) {
  362. var value = getValue($this);
  363. // Get a list of the errors to apply
  364. var errorsFound = [];
  365. $.each(validators, function (validatorType, validatorTypeArray) {
  366. if (value || value.length || (params && params.includeEmpty) || (!!settings.validatorTypes[validatorType].blockSubmit && params && !!params.submitting)) {
  367. $.each(validatorTypeArray, function (i, validator) {
  368. if (settings.validatorTypes[validatorType].validate($this, value, validator)) {
  369. errorsFound.push(validator.message);
  370. }
  371. });
  372. }
  373. });
  374. return errorsFound;
  375. }
  376. );
  377. $this.bind(
  378. "getValidators.validation",
  379. function () {
  380. return validators;
  381. }
  382. );
  383. // =============================================================
  384. // WATCH FOR CHANGES
  385. // =============================================================
  386. $this.bind(
  387. "submit.validation",
  388. function () {
  389. return $this.triggerHandler("change.validation", {submitting: true});
  390. }
  391. );
  392. $this.bind(
  393. [
  394. "keyup",
  395. "focus",
  396. "blur",
  397. "click",
  398. "keydown",
  399. "keypress",
  400. "change"
  401. ].join(".validation ") + ".validation",
  402. function (e, params) {
  403. var value = getValue($this);
  404. var errorsFound = [];
  405. $controlGroup.find("input,textarea,select").each(function (i, el) {
  406. var oldCount = errorsFound.length;
  407. $.each($(el).triggerHandler("validation.validation", params), function (j, message) {
  408. errorsFound.push(message);
  409. });
  410. if (errorsFound.length > oldCount) {
  411. $(el).attr("aria-invalid", "true");
  412. } else {
  413. var original = $this.data("original-aria-invalid");
  414. $(el).attr("aria-invalid", (original !== undefined ? original : false));
  415. }
  416. });
  417. $form.find("input,select,textarea").not($this).not("[name=\"" + $this.attr("name") + "\"]").trigger("validationLostFocus.validation");
  418. errorsFound = $.unique(errorsFound.sort());
  419. // Were there any errors?
  420. if (errorsFound.length) {
  421. // Better flag it up as a warning.
  422. $controlGroup.removeClass("success error").addClass("warning");
  423. // How many errors did we find?
  424. if (settings.options.semanticallyStrict && errorsFound.length === 1) {
  425. // Only one? Being strict? Just output it.
  426. $helpBlock.html(errorsFound[0] +
  427. ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
  428. } else {
  429. // Multiple? Being sloppy? Glue them together into an UL.
  430. $helpBlock.html("<ul role=\"alert\"><li>" + errorsFound.join("</li><li>") + "</li></ul>" +
  431. ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
  432. }
  433. } else {
  434. $controlGroup.removeClass("warning error success");
  435. if (value.length > 0) {
  436. $controlGroup.addClass("success");
  437. }
  438. $helpBlock.html($helpBlock.data("original-contents"));
  439. }
  440. if (e.type === "blur") {
  441. $controlGroup.removeClass("success");
  442. }
  443. }
  444. );
  445. $this.bind("validationLostFocus.validation", function () {
  446. $controlGroup.removeClass("success");
  447. });
  448. });
  449. },
  450. destroy : function( ) {
  451. return this.each(
  452. function() {
  453. var
  454. $this = $(this),
  455. $controlGroup = $this.parents(".control-group").first(),
  456. $helpBlock = $controlGroup.find(".help-block").first();
  457. // remove our events
  458. $this.unbind('.validation'); // events are namespaced.
  459. // reset help text
  460. $helpBlock.html($helpBlock.data("original-contents"));
  461. // reset classes
  462. $controlGroup.attr("class", $controlGroup.data("original-classes"));
  463. // reset aria
  464. $this.attr("aria-invalid", $this.data("original-aria-invalid"));
  465. // reset role
  466. $helpBlock.attr("role", $this.data("original-role"));
  467. // remove all elements we created
  468. if (createdElements.indexOf($helpBlock[0]) > -1) {
  469. $helpBlock.remove();
  470. }
  471. }
  472. );
  473. },
  474. collectErrors : function(includeEmpty) {
  475. var errorMessages = {};
  476. this.each(function (i, el) {
  477. var $el = $(el);
  478. var name = $el.attr("name");
  479. var errors = $el.triggerHandler("validation.validation", {includeEmpty: true});
  480. errorMessages[name] = $.extend(true, errors, errorMessages[name]);
  481. });
  482. $.each(errorMessages, function (i, el) {
  483. if (el.length === 0) {
  484. delete errorMessages[i];
  485. }
  486. });
  487. return errorMessages;
  488. },
  489. hasErrors: function() {
  490. var errorMessages = [];
  491. this.each(function (i, el) {
  492. errorMessages = errorMessages.concat(
  493. $(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", {submitting: true}) : []
  494. );
  495. });
  496. return (errorMessages.length > 0);
  497. },
  498. override : function (newDefaults) {
  499. defaults = $.extend(true, defaults, newDefaults);
  500. }
  501. },
  502. validatorTypes: {
  503. callback: {
  504. name: "callback",
  505. init: function ($this, name) {
  506. return {
  507. validatorName: name,
  508. callback: $this.data("validation" + name + "Callback"),
  509. lastValue: $this.val(),
  510. lastValid: true,
  511. lastFinished: true
  512. };
  513. },
  514. validate: function ($this, value, validator) {
  515. if (validator.lastValue === value && validator.lastFinished) {
  516. return !validator.lastValid;
  517. }
  518. if (validator.lastFinished === true)
  519. {
  520. validator.lastValue = value;
  521. validator.lastValid = true;
  522. validator.lastFinished = false;
  523. var rrjqbvValidator = validator;
  524. var rrjqbvThis = $this;
  525. executeFunctionByName(
  526. validator.callback,
  527. window,
  528. $this,
  529. value,
  530. function (data) {
  531. if (rrjqbvValidator.lastValue === data.value) {
  532. rrjqbvValidator.lastValid = data.valid;
  533. if (data.message) {
  534. rrjqbvValidator.message = data.message;
  535. }
  536. rrjqbvValidator.lastFinished = true;
  537. rrjqbvThis.data("validation" + rrjqbvValidator.validatorName + "Message", rrjqbvValidator.message);
  538. // Timeout is set to avoid problems with the events being considered 'already fired'
  539. setTimeout(function () {
  540. rrjqbvThis.trigger("change.validation");
  541. }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
  542. }
  543. }
  544. );
  545. }
  546. return false;
  547. }
  548. },
  549. ajax: {
  550. name: "ajax",
  551. init: function ($this, name) {
  552. return {
  553. validatorName: name,
  554. url: $this.data("validation" + name + "Ajax"),
  555. lastValue: $this.val(),
  556. lastValid: true,
  557. lastFinished: true
  558. };
  559. },
  560. validate: function ($this, value, validator) {
  561. if (""+validator.lastValue === ""+value && validator.lastFinished === true) {
  562. return validator.lastValid === false;
  563. }
  564. if (validator.lastFinished === true)
  565. {
  566. validator.lastValue = value;
  567. validator.lastValid = true;
  568. validator.lastFinished = false;
  569. $.ajax({
  570. url: validator.url,
  571. data: "value=" + value + "&field=" + $this.attr("name"),
  572. dataType: "json",
  573. success: function (data) {
  574. if (""+validator.lastValue === ""+data.value) {
  575. validator.lastValid = !!(data.valid);
  576. if (data.message) {
  577. validator.message = data.message;
  578. }
  579. validator.lastFinished = true;
  580. $this.data("validation" + validator.validatorName + "Message", validator.message);
  581. // Timeout is set to avoid problems with the events being considered 'already fired'
  582. setTimeout(function () {
  583. $this.trigger("change.validation");
  584. }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
  585. }
  586. },
  587. failure: function () {
  588. validator.lastValid = true;
  589. validator.message = "ajax call failed";
  590. validator.lastFinished = true;
  591. $this.data("validation" + validator.validatorName + "Message", validator.message);
  592. // Timeout is set to avoid problems with the events being considered 'already fired'
  593. setTimeout(function () {
  594. $this.trigger("change.validation");
  595. }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
  596. }
  597. });
  598. }
  599. return false;
  600. }
  601. },
  602. regex: {
  603. name: "regex",
  604. init: function ($this, name) {
  605. return {regex: regexFromString($this.data("validation" + name + "Regex"))};
  606. },
  607. validate: function ($this, value, validator) {
  608. return (!validator.regex.test(value) && ! validator.negative)
  609. || (validator.regex.test(value) && validator.negative);
  610. }
  611. },
  612. required: {
  613. name: "required",
  614. init: function ($this, name) {
  615. return {};
  616. },
  617. validate: function ($this, value, validator) {
  618. return !!(value.length === 0 && ! validator.negative)
  619. || !!(value.length > 0 && validator.negative);
  620. },
  621. blockSubmit: true
  622. },
  623. match: {
  624. name: "match",
  625. init: function ($this, name) {
  626. var element = $this.parents("form").first().find("[name=\"" + $this.data("validation" + name + "Match") + "\"]").first();
  627. element.bind("validation.validation", function () {
  628. $this.trigger("change.validation", {submitting: true});
  629. });
  630. return {"element": element};
  631. },
  632. validate: function ($this, value, validator) {
  633. return (value !== validator.element.val() && ! validator.negative)
  634. || (value === validator.element.val() && validator.negative);
  635. },
  636. blockSubmit: true
  637. },
  638. max: {
  639. name: "max",
  640. init: function ($this, name) {
  641. return {max: $this.data("validation" + name + "Max")};
  642. },
  643. validate: function ($this, value, validator) {
  644. return (parseFloat(value, 10) > parseFloat(validator.max, 10) && ! validator.negative)
  645. || (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative);
  646. }
  647. },
  648. min: {
  649. name: "min",
  650. init: function ($this, name) {
  651. return {min: $this.data("validation" + name + "Min")};
  652. },
  653. validate: function ($this, value, validator) {
  654. return (parseFloat(value) < parseFloat(validator.min) && ! validator.negative)
  655. || (parseFloat(value) >= parseFloat(validator.min) && validator.negative);
  656. }
  657. },
  658. maxlength: {
  659. name: "maxlength",
  660. init: function ($this, name) {
  661. return {maxlength: $this.data("validation" + name + "Maxlength")};
  662. },
  663. validate: function ($this, value, validator) {
  664. return ((value.length > validator.maxlength) && ! validator.negative)
  665. || ((value.length <= validator.maxlength) && validator.negative);
  666. }
  667. },
  668. minlength: {
  669. name: "minlength",
  670. init: function ($this, name) {
  671. return {minlength: $this.data("validation" + name + "Minlength")};
  672. },
  673. validate: function ($this, value, validator) {
  674. return ((value.length < validator.minlength) && ! validator.negative)
  675. || ((value.length >= validator.minlength) && validator.negative);
  676. }
  677. },
  678. maxchecked: {
  679. name: "maxchecked",
  680. init: function ($this, name) {
  681. var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
  682. elements.bind("click.validation", function () {
  683. $this.trigger("change.validation", {includeEmpty: true});
  684. });
  685. return {maxchecked: $this.data("validation" + name + "Maxchecked"), elements: elements};
  686. },
  687. validate: function ($this, value, validator) {
  688. return (validator.elements.filter(":checked").length > validator.maxchecked && ! validator.negative)
  689. || (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative);
  690. },
  691. blockSubmit: true
  692. },
  693. minchecked: {
  694. name: "minchecked",
  695. init: function ($this, name) {
  696. var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
  697. elements.bind("click.validation", function () {
  698. $this.trigger("change.validation", {includeEmpty: true});
  699. });
  700. return {minchecked: $this.data("validation" + name + "Minchecked"), elements: elements};
  701. },
  702. validate: function ($this, value, validator) {
  703. return (validator.elements.filter(":checked").length < validator.minchecked && ! validator.negative)
  704. || (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative);
  705. },
  706. blockSubmit: true
  707. }
  708. },
  709. builtInValidators: {
  710. email: {
  711. name: "Email",
  712. type: "shortcut",
  713. shortcut: "validemail"
  714. },
  715. validemail: {
  716. name: "Validemail",
  717. type: "regex",
  718. regex: "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\.[A-Za-z]{2,4}",
  719. message: "Not a valid email address<!-- data-validator-validemail-message to override -->"
  720. },
  721. passwordagain: {
  722. name: "Passwordagain",
  723. type: "match",
  724. match: "password",
  725. message: "Does not match the given password<!-- data-validator-paswordagain-message to override -->"
  726. },
  727. positive: {
  728. name: "Positive",
  729. type: "shortcut",
  730. shortcut: "number,positivenumber"
  731. },
  732. negative: {
  733. name: "Negative",
  734. type: "shortcut",
  735. shortcut: "number,negativenumber"
  736. },
  737. number: {
  738. name: "Number",
  739. type: "regex",
  740. regex: "([+-]?\\\d+(\\\.\\\d*)?([eE][+-]?[0-9]+)?)?",
  741. message: "Must be a number<!-- data-validator-number-message to override -->"
  742. },
  743. integer: {
  744. name: "Integer",
  745. type: "regex",
  746. regex: "[+-]?\\\d+",
  747. message: "No decimal places allowed<!-- data-validator-integer-message to override -->"
  748. },
  749. positivenumber: {
  750. name: "Positivenumber",
  751. type: "min",
  752. min: 0,
  753. message: "Must be a positive number<!-- data-validator-positivenumber-message to override -->"
  754. },
  755. negativenumber: {
  756. name: "Negativenumber",
  757. type: "max",
  758. max: 0,
  759. message: "Must be a negative number<!-- data-validator-negativenumber-message to override -->"
  760. },
  761. required: {
  762. name: "Required",
  763. type: "required",
  764. message: "This is required<!-- data-validator-required-message to override -->"
  765. },
  766. checkone: {
  767. name: "Checkone",
  768. type: "minchecked",
  769. minchecked: 1,
  770. message: "Check at least one option<!-- data-validation-checkone-message to override -->"
  771. }
  772. }
  773. };
  774. var formatValidatorName = function (name) {
  775. return name
  776. .toLowerCase()
  777. .replace(
  778. /(^|\s)([a-z])/g ,
  779. function(m,p1,p2) {
  780. return p1+p2.toUpperCase();
  781. }
  782. )
  783. ;
  784. };
  785. var getValue = function ($this) {
  786. // Extract the value we're talking about
  787. var value = $this.val();
  788. var type = $this.attr("type");
  789. if (type === "checkbox") {
  790. value = ($this.is(":checked") ? value : "");
  791. }
  792. if (type === "radio") {
  793. value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? value : "");
  794. }
  795. return value;
  796. };
  797. function regexFromString(inputstring) {
  798. return new RegExp("^" + inputstring + "$");
  799. }
  800. /**
  801. * Thanks to Jason Bunting via StackOverflow.com
  802. *
  803. * http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string#answer-359910
  804. * Short link: http://tinyurl.com/executeFunctionByName
  805. **/
  806. function executeFunctionByName(functionName, context /*, args*/) {
  807. var args = Array.prototype.slice.call(arguments).splice(2);
  808. var namespaces = functionName.split(".");
  809. var func = namespaces.pop();
  810. for(var i = 0; i < namespaces.length; i++) {
  811. context = context[namespaces[i]];
  812. }
  813. return context[func].apply(this, args);
  814. }
  815. $.fn.jqBootstrapValidation = function( method ) {
  816. if ( defaults.methods[method] ) {
  817. return defaults.methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
  818. } else if ( typeof method === 'object' || ! method ) {
  819. return defaults.methods.init.apply( this, arguments );
  820. } else {
  821. $.error( 'Method ' + method + ' does not exist on jQuery.jqBootstrapValidation' );
  822. return null;
  823. }
  824. };
  825. $.jqBootstrapValidation = function (options) {
  826. $(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments);
  827. };
  828. })( jQuery );