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.

1116 lines
35 KiB

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