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
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
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
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
10 years ago
9 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
9 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 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
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
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
10 years ago
  1. /*!
  2. * # Semantic UI 1.11.4 - 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', 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, 100);
  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 );