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.

1118 lines
35 KiB

9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /*!
  2. * # Semantic UI 2.0.0 - Form Validation
  3. * http://github.com/semantic-org/semantic-ui/
  4. *
  5. *
  6. * Copyright 2014 Contributors
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. ;(function ( $, window, document, undefined ) {
  12. "use strict";
  13. $.fn.form = function(fields, parameters) {
  14. var
  15. $allModules = $(this),
  16. settings = $.extend(true, {}, $.fn.form.settings, parameters),
  17. validation = $.extend({}, $.fn.form.settings.defaults, fields),
  18. namespace = settings.namespace,
  19. metadata = settings.metadata,
  20. selector = settings.selector,
  21. className = settings.className,
  22. error = settings.error,
  23. eventNamespace = '.' + namespace,
  24. moduleNamespace = 'module-' + namespace,
  25. moduleSelector = $allModules.selector || '',
  26. time = new Date().getTime(),
  27. performance = [],
  28. query = arguments[0],
  29. methodInvoked = (typeof query == 'string'),
  30. queryArguments = [].slice.call(arguments, 1),
  31. returnedValue
  32. ;
  33. $allModules
  34. .each(function() {
  35. var
  36. $module = $(this),
  37. $field = $(this).find(selector.field),
  38. $group = $(this).find(selector.group),
  39. $message = $(this).find(selector.message),
  40. $prompt = $(this).find(selector.prompt),
  41. $submit = $(this).find(selector.submit),
  42. $clear = $(this).find(selector.clear),
  43. $reset = $(this).find(selector.reset),
  44. formErrors = [],
  45. keyHeldDown = false,
  46. element = this,
  47. instance = $module.data(moduleNamespace),
  48. module
  49. ;
  50. module = {
  51. initialize: function() {
  52. module.verbose('Initializing form validation', $module, validation, settings);
  53. module.bindEvents();
  54. module.set.defaults();
  55. module.instantiate();
  56. },
  57. instantiate: function() {
  58. module.verbose('Storing instance of module', module);
  59. instance = module;
  60. $module
  61. .data(moduleNamespace, module)
  62. ;
  63. },
  64. destroy: function() {
  65. module.verbose('Destroying previous module', instance);
  66. module.removeEvents();
  67. $module
  68. .removeData(moduleNamespace)
  69. ;
  70. },
  71. refresh: function() {
  72. module.verbose('Refreshing selector cache');
  73. $field = $module.find(selector.field);
  74. },
  75. submit: function() {
  76. module.verbose('Submitting form', $module);
  77. $module
  78. .submit()
  79. ;
  80. },
  81. attachEvents: function(selector, action) {
  82. action = action || 'submit';
  83. $(selector)
  84. .on('click' + eventNamespace, function(event) {
  85. module[action]();
  86. event.preventDefault();
  87. })
  88. ;
  89. },
  90. bindEvents: function() {
  91. if(settings.keyboardShortcuts) {
  92. $field
  93. .on('keydown' + eventNamespace, module.event.field.keydown)
  94. ;
  95. }
  96. $module
  97. .on('submit' + eventNamespace, module.validate.form)
  98. ;
  99. $field
  100. .on('blur' + eventNamespace, module.event.field.blur)
  101. ;
  102. // attach events to common elements
  103. module.attachEvents($submit, 'submit');
  104. module.attachEvents($reset, 'reset');
  105. module.attachEvents($clear, 'clear');
  106. $field
  107. .each(function() {
  108. var
  109. type = $(this).prop('type'),
  110. inputEvent = module.get.changeEvent(type)
  111. ;
  112. $(this)
  113. .on(inputEvent + eventNamespace, module.event.field.change)
  114. ;
  115. })
  116. ;
  117. },
  118. clear: function() {
  119. $field
  120. .each(function () {
  121. var
  122. $field = $(this),
  123. $element = $field.parent(),
  124. $fieldGroup = $field.closest($group),
  125. $prompt = $fieldGroup.find(selector.prompt),
  126. defaultValue = $field.data(metadata.defaultValue) || '',
  127. isCheckbox = $element.is(selector.uiCheckbox),
  128. isDropdown = $element.is(selector.uiDropdown),
  129. isErrored = $fieldGroup.hasClass(className.error)
  130. ;
  131. if(isErrored) {
  132. module.verbose('Resetting error on field', $fieldGroup);
  133. $fieldGroup.removeClass(className.error);
  134. $prompt.remove();
  135. }
  136. if(isDropdown) {
  137. module.verbose('Resetting dropdown value', $element, defaultValue);
  138. $element.dropdown('clear');
  139. }
  140. else if(isCheckbox) {
  141. $element.checkbox('uncheck');
  142. }
  143. else {
  144. module.verbose('Resetting field value', $field, defaultValue);
  145. $field.val('');
  146. }
  147. })
  148. ;
  149. },
  150. reset: function() {
  151. $field
  152. .each(function () {
  153. var
  154. $field = $(this),
  155. $element = $field.parent(),
  156. $fieldGroup = $field.closest($group),
  157. $prompt = $fieldGroup.find(selector.prompt),
  158. defaultValue = $field.data(metadata.defaultValue) || '',
  159. isCheckbox = $element.is(selector.uiCheckbox),
  160. isDropdown = $element.is(selector.uiDropdown),
  161. isErrored = $fieldGroup.hasClass(className.error)
  162. ;
  163. if(isErrored) {
  164. module.verbose('Resetting error on field', $fieldGroup);
  165. $fieldGroup.removeClass(className.error);
  166. $prompt.remove();
  167. }
  168. if(isDropdown) {
  169. module.verbose('Resetting dropdown value', $element, defaultValue);
  170. $element.dropdown('restore defaults');
  171. }
  172. else if(isCheckbox) {
  173. module.verbose('Resetting checkbox value', $element, defaultValue);
  174. if(defaultValue === true) {
  175. $element.checkbox('check');
  176. }
  177. else {
  178. $element.checkbox('uncheck');
  179. }
  180. }
  181. else {
  182. module.verbose('Resetting field value', $field, defaultValue);
  183. $field.val(defaultValue);
  184. }
  185. })
  186. ;
  187. },
  188. removeEvents: function() {
  189. $module
  190. .off(eventNamespace)
  191. ;
  192. $field
  193. .off(eventNamespace)
  194. ;
  195. $submit
  196. .off(eventNamespace)
  197. ;
  198. $field
  199. .off(eventNamespace)
  200. ;
  201. },
  202. event: {
  203. field: {
  204. keydown: function(event) {
  205. var
  206. $field = $(this),
  207. key = event.which,
  208. keyCode = {
  209. enter : 13,
  210. escape : 27
  211. }
  212. ;
  213. if( key == keyCode.escape) {
  214. module.verbose('Escape key pressed blurring field');
  215. $field
  216. .blur()
  217. ;
  218. }
  219. if(!event.ctrlKey && key == keyCode.enter && $field.is(selector.input) && $field.not(selector.checkbox).length > 0 ) {
  220. $submit
  221. .addClass(className.pressed)
  222. ;
  223. if(!keyHeldDown) {
  224. $field
  225. .one('keyup' + eventNamespace, module.event.field.keyup)
  226. ;
  227. module.submit();
  228. module.debug('Enter pressed on input submitting form');
  229. }
  230. keyHeldDown = true;
  231. }
  232. },
  233. keyup: function() {
  234. keyHeldDown = false;
  235. $submit.removeClass(className.pressed);
  236. },
  237. blur: function() {
  238. var
  239. $field = $(this),
  240. $fieldGroup = $field.closest($group)
  241. ;
  242. if( $fieldGroup.hasClass(className.error) ) {
  243. module.debug('Revalidating field', $field, module.get.validation($field));
  244. module.validate.field( module.get.validation($field) );
  245. }
  246. else if(settings.on == 'blur' || settings.on == 'change') {
  247. module.validate.field( module.get.validation($field) );
  248. }
  249. },
  250. change: function() {
  251. var
  252. $field = $(this),
  253. $fieldGroup = $field.closest($group)
  254. ;
  255. if(settings.on == 'change' || ( $fieldGroup.hasClass(className.error) && settings.revalidate) ) {
  256. clearTimeout(module.timer);
  257. module.timer = setTimeout(function() {
  258. module.debug('Revalidating field', $field, module.get.validation($field));
  259. module.validate.field( module.get.validation($field) );
  260. }, settings.delay);
  261. }
  262. }
  263. }
  264. },
  265. get: {
  266. changeEvent: function(type) {
  267. if(type == 'checkbox' || type == 'radio' || type == 'hidden') {
  268. return 'change';
  269. }
  270. else {
  271. return module.get.inputEvent();
  272. }
  273. },
  274. inputEvent: function() {
  275. return (document.createElement('input').oninput !== undefined)
  276. ? 'input'
  277. : (document.createElement('input').onpropertychange !== undefined)
  278. ? 'propertychange'
  279. : 'keyup'
  280. ;
  281. },
  282. field: function(identifier) {
  283. module.verbose('Finding field with identifier', identifier);
  284. if( $field.filter('#' + identifier).length > 0 ) {
  285. return $field.filter('#' + identifier);
  286. }
  287. else if( $field.filter('[name="' + identifier +'"]').length > 0 ) {
  288. return $field.filter('[name="' + identifier +'"]');
  289. }
  290. else if( $field.filter('[name="' + identifier +'[]"]').length > 0 ) {
  291. return $field.filter('[name="' + identifier +'[]"]');
  292. }
  293. else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').length > 0 ) {
  294. return $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]');
  295. }
  296. return $('<input/>');
  297. },
  298. fields: function(fields) {
  299. var
  300. $fields = $()
  301. ;
  302. $.each(fields, function(index, name) {
  303. $fields = $fields.add( module.get.field(name) );
  304. });
  305. return $fields;
  306. },
  307. validation: function($field) {
  308. var
  309. rules
  310. ;
  311. $.each(validation, function(fieldName, field) {
  312. if( module.get.field(field.identifier).get(0) == $field.get(0) ) {
  313. rules = field;
  314. }
  315. });
  316. return rules || false;
  317. },
  318. value: function (field) {
  319. var
  320. fields = [],
  321. results
  322. ;
  323. fields.push(field);
  324. results = module.get.values.call(element, fields);
  325. return results[field];
  326. },
  327. values: function (fields) {
  328. var
  329. $fields = $.isArray(fields)
  330. ? module.get.fields(fields)
  331. : $field,
  332. values = {}
  333. ;
  334. $fields.each(function(index, field) {
  335. var
  336. $field = $(field),
  337. type = $field.prop('type'),
  338. name = $field.prop('name'),
  339. value = $field.val(),
  340. isCheckbox = $field.is(selector.checkbox),
  341. isRadio = $field.is(selector.radio),
  342. isMultiple = (name.indexOf('[]') !== -1),
  343. isChecked = (isCheckbox)
  344. ? $field.is(':checked')
  345. : false
  346. ;
  347. if(name) {
  348. if(isMultiple) {
  349. name = name.replace('[]', '');
  350. if(!values[name]) {
  351. values[name] = [];
  352. }
  353. if(isCheckbox) {
  354. if(isChecked) {
  355. values[name].push(value)
  356. }
  357. else {
  358. module.debug('Omitted unchecked checkbox', $field);
  359. return true;
  360. }
  361. }
  362. else {
  363. values[name].push(value);
  364. }
  365. }
  366. else {
  367. if(isRadio) {
  368. if(isChecked) {
  369. values[name] = value;
  370. }
  371. }
  372. else if(isCheckbox) {
  373. if(isChecked) {
  374. values[name] = true;
  375. }
  376. else {
  377. module.debug('Omitted unchecked checkbox', $field);
  378. return true;
  379. }
  380. }
  381. else {
  382. values[name] = value;
  383. }
  384. }
  385. }
  386. });
  387. return values;
  388. }
  389. },
  390. has: {
  391. field: function(identifier) {
  392. module.verbose('Checking for existence of a field with identifier', identifier);
  393. if( $field.filter('#' + identifier).length > 0 ) {
  394. return true;
  395. }
  396. else if( $field.filter('[name="' + identifier +'"]').length > 0 ) {
  397. return true;
  398. }
  399. else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').length > 0 ) {
  400. return true;
  401. }
  402. return false;
  403. }
  404. },
  405. add: {
  406. prompt: function(identifier, errors) {
  407. var
  408. $field = module.get.field(identifier),
  409. $fieldGroup = $field.closest($group),
  410. $prompt = $fieldGroup.children(selector.prompt),
  411. promptExists = ($prompt.length !== 0)
  412. ;
  413. errors = (typeof errors == 'string')
  414. ? [errors]
  415. : errors
  416. ;
  417. module.verbose('Adding field error state', identifier);
  418. $fieldGroup
  419. .addClass(className.error)
  420. ;
  421. if(settings.inline) {
  422. if(!promptExists) {
  423. $prompt = settings.templates.prompt(errors);
  424. $prompt
  425. .appendTo($fieldGroup)
  426. ;
  427. }
  428. $prompt
  429. .html(errors[0])
  430. ;
  431. if(!promptExists) {
  432. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  433. module.verbose('Displaying error with css transition', settings.transition);
  434. $prompt.transition(settings.transition + ' in', settings.duration);
  435. }
  436. else {
  437. module.verbose('Displaying error with fallback javascript animation');
  438. $prompt
  439. .fadeIn(settings.duration)
  440. ;
  441. }
  442. }
  443. else {
  444. module.verbose('Inline errors are disabled, no inline error added', identifier);
  445. }
  446. }
  447. },
  448. errors: function(errors) {
  449. module.debug('Adding form error messages', errors);
  450. $message
  451. .html( settings.templates.error(errors) )
  452. ;
  453. }
  454. },
  455. remove: {
  456. prompt: function(field) {
  457. var
  458. $field = module.get.field(field.identifier),
  459. $fieldGroup = $field.closest($group),
  460. $prompt = $fieldGroup.children(selector.prompt)
  461. ;
  462. $fieldGroup
  463. .removeClass(className.error)
  464. ;
  465. if(settings.inline && $prompt.is(':visible')) {
  466. module.verbose('Removing prompt for field', field);
  467. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  468. $prompt.transition(settings.transition + ' out', settings.duration, function() {
  469. $prompt.remove();
  470. });
  471. }
  472. else {
  473. $prompt
  474. .fadeOut(settings.duration, function(){
  475. $prompt.remove();
  476. })
  477. ;
  478. }
  479. }
  480. }
  481. },
  482. set: {
  483. success: function() {
  484. $module
  485. .removeClass(className.error)
  486. .addClass(className.success)
  487. ;
  488. },
  489. defaults: function () {
  490. $field
  491. .each(function () {
  492. var
  493. $field = $(this),
  494. isCheckbox = ($field.filter(selector.checkbox).length > 0),
  495. value = (isCheckbox)
  496. ? $field.is(':checked')
  497. : $field.val()
  498. ;
  499. $field.data(metadata.defaultValue, value);
  500. })
  501. ;
  502. },
  503. error: function() {
  504. $module
  505. .removeClass(className.success)
  506. .addClass(className.error)
  507. ;
  508. },
  509. value: function (field, value) {
  510. var
  511. fields = {}
  512. ;
  513. fields[field] = value;
  514. return module.set.values.call(element, fields);
  515. },
  516. values: function (fields) {
  517. if($.isEmptyObject(fields)) {
  518. return;
  519. }
  520. $.each(fields, function(key, value) {
  521. var
  522. $field = module.get.field(key),
  523. $element = $field.parent(),
  524. isMultiple = $.isArray(value),
  525. isCheckbox = $element.is(selector.uiCheckbox),
  526. isDropdown = $element.is(selector.uiDropdown),
  527. isRadio = ($field.is(selector.radio) && isCheckbox),
  528. fieldExists = ($field.length > 0),
  529. $multipleField
  530. ;
  531. if(fieldExists) {
  532. if(isMultiple && isCheckbox) {
  533. module.verbose('Selecting multiple', value, $field);
  534. $element.checkbox('uncheck');
  535. $.each(value, function(index, value) {
  536. $multipleField = $field.filter('[value="' + value + '"]');
  537. $element = $multipleField.parent();
  538. if($multipleField.length > 0) {
  539. $element.checkbox('check');
  540. }
  541. });
  542. }
  543. else if(isRadio) {
  544. module.verbose('Selecting radio value', value, $field);
  545. $field.filter('[value="' + value + '"]')
  546. .parent(selector.uiCheckbox)
  547. .checkbox('check')
  548. ;
  549. }
  550. else if(isCheckbox) {
  551. module.verbose('Setting checkbox value', value, $element);
  552. if(value === true) {
  553. $element.checkbox('check');
  554. }
  555. else {
  556. $element.checkbox('uncheck');
  557. }
  558. }
  559. else if(isDropdown) {
  560. module.verbose('Setting dropdown value', value, $element);
  561. $element.dropdown('set selected', value);
  562. }
  563. else {
  564. module.verbose('Setting field value', value, $field);
  565. $field.val(value);
  566. }
  567. }
  568. });
  569. module.validate.form();
  570. }
  571. },
  572. validate: {
  573. form: function(event) {
  574. var
  575. allValid = true,
  576. apiRequest
  577. ;
  578. // input keydown event will fire submit repeatedly by browser default
  579. if(keyHeldDown) {
  580. return false;
  581. }
  582. // reset errors
  583. formErrors = [];
  584. $.each(validation, function(fieldName, field) {
  585. if( !( module.validate.field(field) ) ) {
  586. allValid = false;
  587. }
  588. });
  589. if(allValid) {
  590. module.debug('Form has no validation errors, submitting');
  591. module.set.success();
  592. return settings.onSuccess.call(element, event);
  593. }
  594. else {
  595. module.debug('Form has errors');
  596. module.set.error();
  597. if(!settings.inline) {
  598. module.add.errors(formErrors);
  599. }
  600. // prevent ajax submit
  601. if($module.data('moduleApi') !== undefined) {
  602. event.stopImmediatePropagation();
  603. }
  604. return settings.onFailure.call(element, formErrors);
  605. }
  606. },
  607. // takes a validation object and returns whether field passes validation
  608. field: function(field) {
  609. var
  610. $field = module.get.field(field.identifier),
  611. fieldValid = true,
  612. fieldErrors = []
  613. ;
  614. if($field.prop('disabled')) {
  615. module.debug('Field is disabled. Skipping', field.identifier);
  616. fieldValid = true;
  617. }
  618. else if(field.optional && $.trim($field.val()) === ''){
  619. module.debug('Field is optional and empty. Skipping', field.identifier);
  620. fieldValid = true;
  621. }
  622. else if(field.rules !== undefined) {
  623. $.each(field.rules, function(index, rule) {
  624. if( module.has.field(field.identifier) && !( module.validate.rule(field, rule) ) ) {
  625. module.debug('Field is invalid', field.identifier, rule.type);
  626. fieldErrors.push(rule.prompt);
  627. fieldValid = false;
  628. }
  629. });
  630. }
  631. if(fieldValid) {
  632. module.remove.prompt(field, fieldErrors);
  633. settings.onValid.call($field);
  634. }
  635. else {
  636. formErrors = formErrors.concat(fieldErrors);
  637. module.add.prompt(field.identifier, fieldErrors);
  638. settings.onInvalid.call($field, fieldErrors);
  639. return false;
  640. }
  641. return true;
  642. },
  643. // takes validation rule and returns whether field passes rule
  644. rule: function(field, validation) {
  645. var
  646. $field = module.get.field(field.identifier),
  647. type = validation.type,
  648. value = $.trim($field.val() + ''),
  649. bracketRegExp = /\[(.*)\]/i,
  650. bracket = bracketRegExp.exec(type),
  651. isValid = true,
  652. ancillary,
  653. functionType
  654. ;
  655. // if bracket notation is used, pass in extra parameters
  656. if(bracket !== undefined && bracket !== null) {
  657. ancillary = '' + bracket[1];
  658. functionType = type.replace(bracket[0], '');
  659. isValid = settings.rules[functionType].call(element, value, ancillary);
  660. }
  661. // normal notation
  662. else {
  663. isValid = settings.rules[type].call($field, value);
  664. }
  665. return isValid;
  666. }
  667. },
  668. setting: function(name, value) {
  669. if( $.isPlainObject(name) ) {
  670. $.extend(true, settings, name);
  671. }
  672. else if(value !== undefined) {
  673. settings[name] = value;
  674. }
  675. else {
  676. return settings[name];
  677. }
  678. },
  679. internal: function(name, value) {
  680. if( $.isPlainObject(name) ) {
  681. $.extend(true, module, name);
  682. }
  683. else if(value !== undefined) {
  684. module[name] = value;
  685. }
  686. else {
  687. return module[name];
  688. }
  689. },
  690. debug: function() {
  691. if(settings.debug) {
  692. if(settings.performance) {
  693. module.performance.log(arguments);
  694. }
  695. else {
  696. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  697. module.debug.apply(console, arguments);
  698. }
  699. }
  700. },
  701. verbose: function() {
  702. if(settings.verbose && settings.debug) {
  703. if(settings.performance) {
  704. module.performance.log(arguments);
  705. }
  706. else {
  707. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  708. module.verbose.apply(console, arguments);
  709. }
  710. }
  711. },
  712. error: function() {
  713. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  714. module.error.apply(console, arguments);
  715. },
  716. performance: {
  717. log: function(message) {
  718. var
  719. currentTime,
  720. executionTime,
  721. previousTime
  722. ;
  723. if(settings.performance) {
  724. currentTime = new Date().getTime();
  725. previousTime = time || currentTime;
  726. executionTime = currentTime - previousTime;
  727. time = currentTime;
  728. performance.push({
  729. 'Name' : message[0],
  730. 'Arguments' : [].slice.call(message, 1) || '',
  731. 'Element' : element,
  732. 'Execution Time' : executionTime
  733. });
  734. }
  735. clearTimeout(module.performance.timer);
  736. module.performance.timer = setTimeout(module.performance.display, 500);
  737. },
  738. display: function() {
  739. var
  740. title = settings.name + ':',
  741. totalTime = 0
  742. ;
  743. time = false;
  744. clearTimeout(module.performance.timer);
  745. $.each(performance, function(index, data) {
  746. totalTime += data['Execution Time'];
  747. });
  748. title += ' ' + totalTime + 'ms';
  749. if(moduleSelector) {
  750. title += ' \'' + moduleSelector + '\'';
  751. }
  752. if($allModules.length > 1) {
  753. title += ' ' + '(' + $allModules.length + ')';
  754. }
  755. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  756. console.groupCollapsed(title);
  757. if(console.table) {
  758. console.table(performance);
  759. }
  760. else {
  761. $.each(performance, function(index, data) {
  762. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  763. });
  764. }
  765. console.groupEnd();
  766. }
  767. performance = [];
  768. }
  769. },
  770. invoke: function(query, passedArguments, context) {
  771. var
  772. object = instance,
  773. maxDepth,
  774. found,
  775. response
  776. ;
  777. passedArguments = passedArguments || queryArguments;
  778. context = element || context;
  779. if(typeof query == 'string' && object !== undefined) {
  780. query = query.split(/[\. ]/);
  781. maxDepth = query.length - 1;
  782. $.each(query, function(depth, value) {
  783. var camelCaseValue = (depth != maxDepth)
  784. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  785. : query
  786. ;
  787. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  788. object = object[camelCaseValue];
  789. }
  790. else if( object[camelCaseValue] !== undefined ) {
  791. found = object[camelCaseValue];
  792. return false;
  793. }
  794. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  795. object = object[value];
  796. }
  797. else if( object[value] !== undefined ) {
  798. found = object[value];
  799. return false;
  800. }
  801. else {
  802. return false;
  803. }
  804. });
  805. }
  806. if( $.isFunction( found ) ) {
  807. response = found.apply(context, passedArguments);
  808. }
  809. else if(found !== undefined) {
  810. response = found;
  811. }
  812. if($.isArray(returnedValue)) {
  813. returnedValue.push(response);
  814. }
  815. else if(returnedValue !== undefined) {
  816. returnedValue = [returnedValue, response];
  817. }
  818. else if(response !== undefined) {
  819. returnedValue = response;
  820. }
  821. return found;
  822. }
  823. };
  824. if(methodInvoked) {
  825. if(instance === undefined) {
  826. module.initialize();
  827. }
  828. module.invoke(query);
  829. }
  830. else {
  831. if(instance !== undefined) {
  832. instance.invoke('destroy');
  833. }
  834. module.initialize();
  835. }
  836. })
  837. ;
  838. return (returnedValue !== undefined)
  839. ? returnedValue
  840. : this
  841. ;
  842. };
  843. $.fn.form.settings = {
  844. name : 'Form',
  845. namespace : 'form',
  846. debug : false,
  847. verbose : true,
  848. performance : true,
  849. keyboardShortcuts : true,
  850. on : 'submit',
  851. inline : false,
  852. delay : 200,
  853. revalidate : true,
  854. transition : 'scale',
  855. duration : 200,
  856. onValid : function() {},
  857. onInvalid : function() {},
  858. onSuccess : function() { return true; },
  859. onFailure : function() { return false; },
  860. metadata : {
  861. defaultValue : 'default',
  862. validate : 'validate'
  863. },
  864. selector : {
  865. checkbox : 'input[type="checkbox"], input[type="radio"]',
  866. clear : '.clear',
  867. field : 'input, textarea, select',
  868. group : '.field',
  869. input : 'input',
  870. message : '.error.message',
  871. prompt : '.prompt.label',
  872. radio : 'input[type="radio"]',
  873. reset : '.reset',
  874. submit : '.submit',
  875. uiCheckbox : '.ui.checkbox',
  876. uiDropdown : '.ui.dropdown'
  877. },
  878. className : {
  879. error : 'error',
  880. label : 'ui prompt label',
  881. pressed : 'down',
  882. success : 'success'
  883. },
  884. error: {
  885. method : 'The method you called is not defined.'
  886. },
  887. templates: {
  888. // template that produces error message
  889. error: function(errors) {
  890. var
  891. html = '<ul class="list">'
  892. ;
  893. $.each(errors, function(index, value) {
  894. html += '<li>' + value + '</li>';
  895. });
  896. html += '</ul>';
  897. return $(html);
  898. },
  899. // template that produces label
  900. prompt: function(errors) {
  901. return $('<div/>')
  902. .addClass('ui red pointing prompt label')
  903. .html(errors[0])
  904. ;
  905. }
  906. },
  907. rules: {
  908. // checkbox checked
  909. checked: function() {
  910. return ($(this).filter(':checked').length > 0);
  911. },
  912. // value contains text (insensitive)
  913. contains: function(value, text) {
  914. // escape regex characters
  915. text = text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
  916. return (value.search( new RegExp(text, 'i') ) !== -1);
  917. },
  918. // value contains text (case sensitive)
  919. containsExactly: function(value, text) {
  920. // escape regex characters
  921. text = text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
  922. return (value.search( new RegExp(text) ) !== -1);
  923. },
  924. // is most likely an email
  925. email: function(value){
  926. var
  927. emailRegExp = new RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", "i")
  928. ;
  929. return emailRegExp.test(value);
  930. },
  931. // is not empty or blank string
  932. empty: function(value) {
  933. return !(value === undefined || '' === value);
  934. },
  935. // is valid integer
  936. integer: function(value, range) {
  937. var
  938. intRegExp = /^\-?\d+$/,
  939. min,
  940. max,
  941. parts
  942. ;
  943. if(range === undefined || range === '' || range === '..') {
  944. // do nothing
  945. }
  946. else if(range.indexOf('..') == -1) {
  947. if(intRegExp.test(range)) {
  948. min = max = range - 0;
  949. }
  950. }
  951. else {
  952. parts = range.split('..', 2);
  953. if(intRegExp.test(parts[0])) {
  954. min = parts[0] - 0;
  955. }
  956. if(intRegExp.test(parts[1])) {
  957. max = parts[1] - 0;
  958. }
  959. }
  960. return (
  961. intRegExp.test(value) &&
  962. (min === undefined || value >= min) &&
  963. (max === undefined || value <= max)
  964. );
  965. },
  966. // is value (case insensitive)
  967. is: function(value, text) {
  968. text = (typeof text == 'string')
  969. ? text.toLowerCase()
  970. : text
  971. ;
  972. value = (typeof value == 'string')
  973. ? value.toLowerCase()
  974. : value
  975. ;
  976. return (value == text);
  977. },
  978. // is value
  979. isExactly: function(value, text) {
  980. return (value == text);
  981. },
  982. // is at least string length
  983. length: function(value, requiredLength) {
  984. return (value !== undefined)
  985. ? (value.length >= requiredLength)
  986. : false
  987. ;
  988. },
  989. // matches another field
  990. match: function(value, fieldIdentifier) {
  991. // use either id or name of field
  992. var
  993. $form = $(this),
  994. matchingValue
  995. ;
  996. if($form.find('#' + fieldIdentifier).length > 0) {
  997. matchingValue = $form.find('#' + fieldIdentifier).val();
  998. }
  999. else if($form.find('[name="' + fieldIdentifier +'"]').length > 0) {
  1000. matchingValue = $form.find('[name="' + fieldIdentifier + '"]').val();
  1001. }
  1002. else if( $form.find('[data-validate="'+ fieldIdentifier +'"]').length > 0 ) {
  1003. matchingValue = $form.find('[data-validate="'+ fieldIdentifier +'"]').val();
  1004. }
  1005. return (matchingValue !== undefined)
  1006. ? ( value.toString() == matchingValue.toString() )
  1007. : false
  1008. ;
  1009. },
  1010. // string length is less than max length
  1011. maxLength: function(value, maxLength) {
  1012. return (value !== undefined)
  1013. ? (value.length <= maxLength)
  1014. : false
  1015. ;
  1016. },
  1017. // value is not value (case insensitive)
  1018. not: function(value, notValue) {
  1019. value = (typeof value == 'string')
  1020. ? value.toLowerCase()
  1021. : value
  1022. ;
  1023. notValue = (typeof notValue == 'string')
  1024. ? notValue.toLowerCase()
  1025. : notValue
  1026. ;
  1027. return (value != notValue);
  1028. },
  1029. // value is not value (case sensitive)
  1030. notExactly: function(value, notValue) {
  1031. return (value != notValue);
  1032. },
  1033. // value is most likely url
  1034. url: function(value) {
  1035. var
  1036. urlRegExp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
  1037. ;
  1038. return urlRegExp.test(value);
  1039. }
  1040. }
  1041. };
  1042. })( jQuery, window , document );