PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/js/veto.js

https://bitbucket.org/jscott1989/veto
JavaScript | 1122 lines | 750 code | 206 blank | 166 comment | 243 complexity | 6fadf23c666fffab4c7de4f6f555efef MD5 | raw file
  1. var default_vtform_configuration = {
  2. error_display_section: false
  3. ,error_display_inline: true
  4. ,error_display_inline_position: 'prefix'
  5. ,error_display_alert: false
  6. ,error_class: 'vtError'
  7. ,focus: 'first_error_field' // May be 'first_error_field', 'error_section', or false for no focus
  8. ,date_format: 'DD/MM/YYYY'
  9. };
  10. function vtForm(name, configuration) {
  11. // If it's being called as a function - call the constructor
  12. // (allow for shorthand)
  13. if (this.window) return new vtForm(name, configuration);
  14. // Member variables
  15. this.sets = new Array();
  16. this.fields = new Array();
  17. this.errors = new Array();
  18. // end member variables
  19. // Constructor
  20. this.name = name;
  21. this.form_name = name;
  22. this.full_name = name;
  23. this.configuration = array_merge(default_vtform_configuration, (configuration || new Array())) ;
  24. // end constructor
  25. // Functions
  26. this.add = function(field) {
  27. if (typeof(field.required) == 'function') // Assume Required will never be removed or renamed - it is pretty basic
  28. return this.addField(field);
  29. else // Assume set
  30. return this.addSet(field);
  31. };
  32. this.addField = function(field) {
  33. this.fields.push(field);
  34. return this;
  35. }
  36. this.addSet = function(set) {
  37. this.sets.push(set);
  38. set.form_name = this.name;
  39. set.full_name = this.name + '-' + set.name;
  40. set.configuration = this.configuration; // Pass it down for now - temporary! TODO Change this so it checks if it is already default
  41. return this;
  42. }
  43. this.validateSets = function() {
  44. var errors = new Object();
  45. if (this.sets) {
  46. for (set in this.sets) {
  47. this.sets[set].validate();
  48. errors = array_merge_recursive(errors, this.sets[set].errors);
  49. }
  50. }
  51. return errors;
  52. }
  53. this.validate = function(fields, focus) {
  54. var errors = new Object();
  55. if (!fields) {
  56. fields = [];
  57. for (f in this.fields) {
  58. fields.push(this.fields[f]);
  59. }
  60. }
  61. // Remove error class from block
  62. if (this.configuration.error_display_section) {
  63. remove_class(document.getElementById(this.full_name + '-errors'), 'vtErrors');
  64. remove_class(document.getElementById(this.full_name + '-errors'), 'vtNoErrors');
  65. }
  66. for(f in fields) {
  67. var field = fields[f];
  68. // Clear the errors
  69. remove_class(document.getElementsByName(this.form_name + '[' + field.name +']')[0], this.configuration.error_class);
  70. if (document.getElementById('vt_' + this.form_name + '_' + field.name + '-error')) {
  71. document.getElementById('vt_' + this.form_name + '_' + field.name + '-error').innerHTML = '';
  72. remove_class(document.getElementById('vt_' + this.form_name + '_' + field.name + '-error'), 'vtErrors');
  73. add_class(document.getElementById('vt_' + this.form_name + '_' + field.name + '-error'), 'vtNoErrors');
  74. }
  75. // Load the new errors into the array
  76. errors = array_merge_recursive(errors, field.validate(document.getElementById('vt_' + this.form_name), this.configuration));
  77. }
  78. this.errors = errors;
  79. var set_errors = this.validateSets();
  80. if (is_empty(errors) && is_empty(set_errors)) {
  81. if (this.configuration.error_display_section) add_class(document.getElementById(this.full_name + '-errors'), 'vtNoErrors');
  82. return true;
  83. }
  84. // Output the errors
  85. if (this.configuration.error_display_section) var error_display_section = '<ul>';
  86. if (this.configuration.error_display_alert) var error_display_alert = '';
  87. for(field in errors) {
  88. add_class(document.getElementsByName(this.form_name + '[' + field + ']')[0], this.configuration.error_class);
  89. if (is_array(errors[field])) {
  90. for(error in errors[field]) {
  91. if (this.configuration.error_display_section) error_display_section += '<li>' + errors[field][error] + '</li>';
  92. if (this.configuration.error_display_alert) error_display_alert += errors[field][error] + '\n';
  93. if (document.getElementById('vt_' + this.form_name + '_' + field + '-error')) {
  94. document.getElementById('vt_' + this.form_name + '_' + field + '-error').innerHTML = errors[field][error];
  95. remove_class(document.getElementById('vt_' + this.form_name + '_' + field + '-error'), 'vtNoErrors');
  96. add_class(document.getElementById('vt_' + this.form_name + '_' + field + '-error'), 'vtErrors');
  97. }
  98. }
  99. } else {
  100. if (this.configuration.error_display_section) error_display_section += '<li>' + errors[field] + '</li>';
  101. if (this.configuration.error_display_alert) error_display_alert += errors[field] + '\n';
  102. if (document.getElementById('vt_' + this.name + '_' + field + '-error')) {
  103. document.getElementById('vt_' + this.name + '_' + field + '-error').innerHTML = errors[field];
  104. remove_class(document.getElementById('vt_' + this.name + '_' + field + '-error'), 'vtNoErrors');
  105. add_class(document.getElementById('vt_' + this.name + '_' + field + '-error'), 'vtErrors');
  106. }
  107. }
  108. }
  109. if (this.configuration.error_display_section && document.getElementById(this.full_name + '-errors')) {
  110. add_class(document.getElementById(this.full_name + '-errors'), 'vtErrors');
  111. document.getElementById(this.full_name + '-errors').innerHTML = error_display_section + '</ul>';
  112. }
  113. if (this.configuration.error_display_alert)
  114. alert(error_display_alert);
  115. if (!focus) {
  116. focus = this.configuration.focus;
  117. }
  118. if (focus == 'first_error_field')
  119. // Get the first key - TODO there must be a better way than this
  120. for (var field in errors) {
  121. document.getElementsByName(this.form_name + '[' + field + ']')[0].focus();
  122. break;
  123. }
  124. else if (focus == 'error_section')
  125. window.location = '#' + this.form_name + '-errors';
  126. return false;
  127. }
  128. // end functions
  129. return this;
  130. }
  131. vtSet = vtForm;
  132. function vtField(name) {
  133. // If it's being called as a function - call the constructor
  134. // (allow for shorthand)
  135. if (this.window) return new vtField(name);
  136. // Member variables
  137. this.validations = new Array();
  138. // end member variables
  139. // Constructor
  140. this.name = name;
  141. // end constructor
  142. // Functions
  143. this.add = function(validation) {
  144. this.validations.push(validation);
  145. return this;
  146. };
  147. this.validate = function(form, configuration) {
  148. var errors = new Object();
  149. for(validation in this.validations) {
  150. errors = array_merge_recursive(errors, this.validations[validation].validate(form, this.name, configuration));
  151. }
  152. return errors;
  153. }
  154. // Shorthand
  155. this.required = function(options, error) {
  156. return this.add(vtRequired(options, error));
  157. }
  158. this.matches= function(regex, options, error) {
  159. return this.add(vtMatches(regex, options, error));
  160. }
  161. this.lengthBetween = function(min, max, options, error) {
  162. return this.add(vtLengthBetween(min, max, options, error));
  163. }
  164. this.minimumLength = function(min, options, error) {
  165. return this.add(vtMinimumLength(min, options, error));
  166. }
  167. this.maximumLength = function(max, options, error) {
  168. return this.add(vtMaximumLength(max, options, error));
  169. }
  170. this.number = function(options, error) {
  171. return this.add(vtNumber(options, error));
  172. }
  173. this.between = function(min, max, options, error) {
  174. return this.add(vtBetween(min, max, options, error));
  175. }
  176. this.minimum = function(min, options, error) {
  177. return this.add(vtMinimum(min, options, error));
  178. }
  179. this.maximum = function(max, options, error) {
  180. return this.add(vtMaximum(max, options, error));
  181. }
  182. this.options = function(options, _options, error) {
  183. return this.add(vtOptions(options, _options, error));
  184. }
  185. this.notOptions = function(options, _options, error) {
  186. return this.add(vtNotOptions(options, _options, error));
  187. }
  188. this.notEqual = function(to, options, error) {
  189. return this.add(vtNotEqual(to, options, error))
  190. }
  191. this.email = function(options, error) {
  192. return this.add(vtEmail(options, error));
  193. }
  194. this.date = function(options, error) {
  195. return this.add(vtDate(options, error));
  196. }
  197. this.dateBetween = function(earliest, latest, options, error) {
  198. return this.add(vtDateBetween(earliest, latest, options, error));
  199. }
  200. this.dateEarliest = function(earliest, options, error) {
  201. return this.add(vtDateEarliest(earliest, options, error));
  202. }
  203. this.dateLatest = function(latest, options, error) {
  204. return this.add(vtDateLatest(latest, options, error));
  205. }
  206. this.custom = function(javascript_function, javascript_array) {
  207. return this.add(vtCustom(javascript_function, javascript_array));
  208. }
  209. this.sameAs = function(other_function, options, error) {
  210. return this.add(vtSameAs(other_function, options, error));
  211. }
  212. // end shorthand
  213. // end functions
  214. return this;
  215. }
  216. // Validations
  217. function vtRequiredValidation(options, error) {
  218. // If it's being called as a function - call the constructor
  219. // (allow for shorthand)
  220. if (this.window) return new vtRequiredValidation(options, error);
  221. // Member variables
  222. // end member variables
  223. // Constructor
  224. if (is_string(options)) {
  225. error = options
  226. options = new Object()
  227. }
  228. this.options = options
  229. this.error = error || '%n is required';
  230. // end constructor
  231. // Functions
  232. this.validate = function(form, key, configuration) {
  233. if (getValueFromField(form.name + '[' + key + ']').length == 0) {
  234. var ret = new Object();
  235. ret[key] = [this.error.replace(/%n/, labelize(key))];
  236. return ret;
  237. }
  238. return {};
  239. };
  240. // end functions
  241. return this;
  242. }
  243. var vtRequired = vtRequiredValidation;
  244. function vtRegularExpressionValidation(regex, options, error) {
  245. // If it's being called as a function - call the constructor
  246. // (allow for shorthand)
  247. if (this.window) return new vtRegularExpressionValidation(regex, options, error);
  248. // Member variables
  249. // end member variables
  250. // Constructor
  251. if (is_string(options)) {
  252. error = options
  253. options = new Object()
  254. }
  255. this.options = options
  256. this.error = error || '%n must match ' + regex;
  257. this.regex = new RegExp(regex);
  258. // end constructor
  259. // Functions
  260. this.validate = function(form, key, configuration) {
  261. if (getValueFromField(form.name + '[' + key + ']').length == 0) return {};
  262. if (getValueFromField(form.name + '[' + key + ']').match(this.regex)) return {};
  263. else {
  264. var ret = new Object();
  265. ret[key] = [this.error.replace(/%n/, labelize(key))];
  266. return ret;
  267. }
  268. };
  269. // end functions
  270. return this;
  271. }
  272. var vtRegexValidation = vtRegularExpressionValidation;
  273. var vtMatches = vtRegexValidation;
  274. function vtEmailAddressValidation(options, error) {
  275. // If it's being called as a function - call the constructor
  276. // (allow for shorthand)
  277. if (this.window) return new vtEmailAddressValidation(options, error);
  278. // Member variables
  279. // end member variables
  280. // Constructor
  281. if (is_string(options)) {
  282. error = options
  283. options = new Object()
  284. }
  285. this.options = options
  286. this.error = error || '%n must be a valid email address'
  287. // end constructor
  288. // Functions
  289. this.validate = function(form, key, configuration) {
  290. if (getValueFromField(form.name + '[' + key + ']').length == 0) return {};
  291. if (getValueFromField(form.name + '[' + key + ']').match(/^.*@.*\..*$/)) return {};
  292. else {
  293. var ret = new Object();
  294. ret[key] = [this.error.replace(/%n/, labelize(key))];
  295. return ret;
  296. }
  297. };
  298. // end functions
  299. return this;
  300. }
  301. var vtEmailValidation = vtEmailAddressValidation;
  302. var vtEmail = vtEmailValidation;
  303. function vtNumberValidation(options, error) {
  304. // If it's being called as a function - call the constructor
  305. // (allow for shorthand)
  306. if (this.window) return new vtNumberValidation(options, error);
  307. // Member variables
  308. // end member variables
  309. // Constructor
  310. if (is_string(options)) {
  311. error = options
  312. options = new Object()
  313. }
  314. this.options = options
  315. this.error = error || '%n must be a number';
  316. var number_characters = '\\d'
  317. if (this.options.separator != undefined) {
  318. if (this.options.separator === true) {
  319. // Default to comma separator
  320. number_characters = '[\\d,]';
  321. } else {
  322. number_characters = '[\\d' + RegExp.escape(this.options.separator) + ']';
  323. }
  324. }
  325. var regex_start = '^';
  326. if (this.options.negative != undefined) {
  327. if (this.options.negative === true) {
  328. // Default to - negative
  329. regex_start = '^-?';
  330. } else {
  331. regex_start = '^' + RegExp.escape(this.options.negative) + '?';
  332. }
  333. }
  334. var regex_middle = number_characters + '+';
  335. if (this.options.decimal) {
  336. if (this.options.decimal === true) {
  337. // Default to . decimal
  338. regex_middle = number_characters + '+(\\.' + number_characters + '+)?';
  339. } else {
  340. regex_middle = number_characters + '+(' + RegExp.escape(this.options.decimal) + number_characters + '+)?';
  341. }
  342. }
  343. this.regex = new RegExp(regex_start + regex_middle + '$');
  344. // end constructor
  345. // Functions
  346. this.validate = function(form, key, configuration) {
  347. if (getValueFromField(form.name + '[' + key + ']').length == 0) return {};
  348. if (getValueFromField(form.name + '[' + key + ']').match(this.regex)) return {};
  349. else {
  350. var ret = new Object();
  351. ret[key] = [this.error.replace(/%n/, labelize(key))];
  352. return ret;
  353. }
  354. };
  355. // end functions
  356. return this;
  357. }
  358. var vtNumber = vtNumberValidation;
  359. function vtLengthValidation(min, max, options, error) {
  360. // If it's being called as a function - call the constructor
  361. // (allow for shorthand)
  362. if (this.window) return new vtLengthValidation(min, max, options, error);
  363. // Member variables
  364. // end member variables
  365. // Constructor
  366. if (is_string(options)) {
  367. error = options
  368. options = new Object()
  369. }
  370. this.options = options
  371. if (min && max) var default_error = '%n must be between ' + min + ' and ' + max + ' characters long';
  372. else if (min) var default_error = '%n must be at least ' + min + ' characters long';
  373. else var default_error = '%n must be at most ' + max + ' characters long';
  374. this.error = error || default_error;
  375. this.min = min;
  376. this.max = max;
  377. // end constructor
  378. // Functions
  379. this.validate = function(form, key, configuration) {
  380. if (getValueFromField(form.name + '[' + key + ']').length == 0) return {};
  381. var data = getValueFromField(form.name + '[' + key + ']');
  382. if (this.options.ignore != undefined) {
  383. if (is_array(this.options.ignore)) {
  384. for (i in this.options.ignore) {
  385. data = data.replace(new RegExp(RegExp.escape(this.options.ignore[i]), "g"), '');
  386. }
  387. } else {
  388. for (var i = 0; i < this.options.ignore.length; i++)
  389. data = data.replace(new RegExp(RegExp.escape(this.options.ignore.substr(i, i+1)), "g"), '');
  390. }
  391. }
  392. if (this.min && data.length < this.min || this.max && data.length > this.max) {
  393. var ret = new Object();
  394. ret[key] = [this.error.replace(/%n/, labelize(key))];
  395. return ret;
  396. } else return {};
  397. };
  398. // end functions
  399. return this;
  400. }
  401. var vtLengthBetween = vtLengthValidation;
  402. var vtMinimumLength = function(min, error) { return vtLengthBetween(min, null, error); };
  403. var vtMaximumLength = function(max, error) { return vtLengthBetween(null, max, error); };
  404. function vtOptionsValidation(options, _options, error) {
  405. // If it's being called as a function - call the constructor
  406. // (allow for shorthand)
  407. if (this.window) return new vtOptionsValidation(options, _options, error);
  408. // Member variables
  409. // end member variables
  410. // Constructor
  411. if (is_string(_options)) {
  412. error = _options
  413. _options = new Object()
  414. }
  415. this._options = _options
  416. if (_options.should_be_in == undefined) _options.should_be_in = true;
  417. if (_options.should_be_in) var default_error = '%n must be in the options';
  418. else var default_error = '%n must not be in the options';
  419. this.error = error || default_error;
  420. this.options = options;
  421. // end constructor
  422. // Functions
  423. this.validate = function(form, key, configuration) {
  424. if (getValueFromField(form.name + '[' + key + ']').length == 0) return {};
  425. var value = getValueFromField(form.name + '[' + key + ']');
  426. for (var option in this.options){
  427. if (value == this.options[option]) {
  428. if (this._options.should_be_in) return {}
  429. else {
  430. var ret = new Object();
  431. ret[key] = [this.error.replace(/%n/, labelize(key))];
  432. return ret;
  433. }
  434. }
  435. }
  436. if (this._options.should_be_in) {
  437. var ret = new Object();
  438. ret[key] = [this.error.replace(/%n/, labelize(key))];
  439. return ret;
  440. } else return {}
  441. };
  442. // end functions
  443. return this;
  444. }
  445. var vtOptions = vtOptionsValidation;
  446. var vtNotOptions = function(options, _options, error) { return vtOptions(options, array_merge({should_be_in: false}, _options), error); };
  447. function vtNumberRangeValidation(min, max, options, error) {
  448. // If it's being called as a function - call the constructor
  449. // (allow for shorthand)
  450. if (this.window) return new vtNumberRangeValidation(min, max, options, error);
  451. // Member variables
  452. // end member variables
  453. // Constructor
  454. if (is_string(options)) {
  455. error = options
  456. options = new Object()
  457. }
  458. this.options = options
  459. if (min && max) var default_error = '%n must be between ' + min + ' and ' + max;
  460. else if (min) var default_error = '%n must be at least ' + min;
  461. else var default_error = '%n must be at most ' + max;
  462. this.error = error || default_error;
  463. this.min = min;
  464. this.max = max;
  465. // end constructor
  466. // Functions
  467. this.validate = function(form, key, configuration) {
  468. if (getValueFromField(form.name + '[' + key + ']').length == 0) return {};
  469. if (this.min && parseInt(getValueFromField(form.name + '[' + key + ']')) < this.min || this.max && parseInt(getValueFromField(form.name + '[' + key + ']')) > this.max) {
  470. var ret = new Object();
  471. ret[key] = [this.error.replace(/%n/, labelize(key))];
  472. return ret;
  473. } else return {};
  474. };
  475. // end functions
  476. return this;
  477. }
  478. var vtBetween = vtNumberRangeValidation;
  479. var vtMinimum = function(min, options, error) { return vtBetween(min, null, options, error); };
  480. var vtMaximum = function(max, options, error) { return vtBetween(null, max, options, error); };
  481. function vtDateValidation(options, error) {
  482. // If it's being called as a function - call the constructor
  483. // (allow for shorthand)
  484. if (this.window) return new vtDateValidation(options, error);
  485. // Member variables
  486. // end member variables
  487. // Constructor
  488. if (is_string(options)) {
  489. error = options
  490. options = new Object()
  491. }
  492. this.options = options
  493. this.error = error || '%n must be a date';
  494. // end constructor
  495. // Functions
  496. this.validate = function(form, key, configuration) {
  497. if (getValueFromField(form.name + '[' + key + ']').length == 0) return {};
  498. // First check the format
  499. date = extract_date(getValueFromField(form.name + '[' + key + ']'), configuration.date_format);
  500. if (!date) {
  501. var ret = new Object();
  502. ret[key] = [this.error.replace(/%n/, labelize(key))];
  503. return ret;
  504. }
  505. if (checkdate(date.month, date.day, date.year)) return {}
  506. var ret = new Object();
  507. ret[key] = [this.error.replace(/%n/, labelize(key))];
  508. return ret;
  509. };
  510. // end functions
  511. return this;
  512. }
  513. var vtDate = vtDateValidation;
  514. function vtDateRangeValidation(earliest, latest, options, error) {
  515. // If it's being called as a function - call the constructor
  516. // (allow for shorthand)
  517. if (this.window) return new vtDateRangeValidation(earliest, latest, options, error);
  518. // Member variables
  519. // end member variables
  520. // Constructor
  521. if (is_string(options)) {
  522. error = options
  523. options = new Object()
  524. }
  525. this.options = options
  526. if (earliest && latest) var default_error = '%n must be between ' + earliest + ' and ' + latest;
  527. else if (earliest) var default_error = '%n must be at least ' + earliest;
  528. else var default_error = '%n must be at most ' + latest;
  529. this.error = error || default_error;
  530. this.earliest = earliest;
  531. this.latest = latest;
  532. // end constructor
  533. // Functions
  534. this.validate = function(form, key, configuration) {
  535. if (getValueFromField(form.name + '[' + key + ']').length == 0) return {};
  536. date = extract_date(getValueFromField(form.name + '[' + key + ']'), configuration.date_format);
  537. // Only validate if it is a date
  538. if (!date) return {};
  539. var date_object = new Date();
  540. date_object.setFullYear(date.year, date.month, date.day);
  541. if (this.earliest) {
  542. var earliest_date = extract_date(this.earliest, configuration.date_format);
  543. if (!earliest_date) return {};
  544. earliest_date_object = new Date()
  545. earliest_date_object.setFullYear(earliest_date.year, earliest_date.month, earliest_date.day);
  546. if (date_object.getTime() < earliest_date_object.getTime()) {
  547. var ret = new Object();
  548. ret[key] = [this.error.replace(/%n/, labelize(key))];
  549. return ret;
  550. }
  551. }
  552. if (this.latest) {
  553. var latest_date = extract_date(this.latest, configuration.date_format);
  554. if (!latest_date) return {};
  555. latest_date_object = new Date()
  556. latest_date_object.setFullYear(latest_date.year, latest_date.month, latest_date.day);
  557. if (date_object.getTime() > latest_date_object.getTime()) {
  558. var ret = new Object();
  559. ret[key] = [this.error.replace(/%n/, labelize(key))];
  560. return ret;
  561. }
  562. }
  563. return {};
  564. };
  565. // end functions
  566. return this;
  567. }
  568. var vtDateBetween = vtDateRangeValidation;
  569. var vtDateEarliest = function(earliest, options, error) { return vtBetween(earliest, null, options, error); };
  570. var vtDateLatest = function(latest, options, error) { return vtBetween(null, latest, options, error); };
  571. function vtCustomValidation(javascript_function, javascript_array) {
  572. // If it's being called as a function - call the constructor
  573. // (allow for shorthand)
  574. if (this.window) return new vtCustomValidation(javascript_function, javascript_array);
  575. // Member variables
  576. // end member variables
  577. // Constructor
  578. this.javascript_function = javascript_function;
  579. this.javascript_array = javascript_array
  580. // end constructor
  581. // Functions
  582. // The custom function gets given the form name, the current key, and configuration
  583. // To get the value use getValueFromField(form.name + '[' + key + ']')
  584. // Return an "associative array" like:
  585. // var ret = new Object();
  586. // ret[key] = "ERROR!";
  587. // return ret;
  588. // if there is an error, otherwise return {}
  589. this.validate = function(form, key, configuration) {
  590. if (getValueFromField(form.name + '[' + key + ']').length == 0) return {};
  591. return window[this.javascript_function](form, key, configuration, this.javascript_array);
  592. };
  593. // end functions
  594. return this;
  595. }
  596. var vtCustom = vtCustomValidation;
  597. function vtSameAsValidation(other_field, options, error) {
  598. // If it's being called as a function - call the constructor
  599. // (allow for shorthand)
  600. if (this.window) return new vtSameAsValidation(other_field, options, error);
  601. // Member variables
  602. // end member variables
  603. // Constructor
  604. if (is_string(options)) {
  605. error = options
  606. options = new Object()
  607. }
  608. this.options = options
  609. this.other_field = other_field;
  610. this.error = error || '%n must be the same as ' + labelize(other_field);
  611. // end constructor
  612. // Functions
  613. this.validate = function(form, key, configuration) {
  614. if (getValueFromField(form.name + '[' + key + ']') == document.getElementsByName(form.name + '[' + this.other_field + ']')[0].value) {
  615. return {};
  616. }
  617. var ret = new Object();
  618. ret[key] = [this.error.replace(/%n/, labelize(key))];
  619. return ret;
  620. };
  621. // end functions
  622. return this;
  623. }
  624. var vtSameAs = vtSameAsValidation;
  625. function vtOptionalValidation(validation, field, requirement) {
  626. // If it's being called as a function - call the constructor
  627. // (allow for shorthand)
  628. if (this.window) return new vtOptionalValidation(validation, field, requirement);
  629. // Member variables
  630. // end member variables
  631. // Constructor
  632. this.validation = validation;
  633. this.field = field;
  634. this.requirement = requirement;
  635. // end constructor
  636. // Functions
  637. this.validate = function(form, key, configuration) {
  638. if (!is_empty(this.requirement.validate(form, this.field, configuration))) {
  639. return this.validation.validate(form, key, configuration);
  640. }
  641. return [];
  642. };
  643. // end functions
  644. return this;
  645. }
  646. var vtOptional = vtOptionalValidation;
  647. function vtReverseValidation(validation, error) {
  648. // If it's being called as a function - call the constructor
  649. // (allow for shorthand)
  650. if (this.window) return new vtReverseValidation(validation, error);
  651. // Member variables
  652. // end member variables
  653. // Constructor
  654. this.validation = validation;
  655. this.error = error || "%n failed the reverse validation" // TODO: better error
  656. // end constructor
  657. // Functions
  658. this.validate = function(form, key, configuration) {
  659. if (!is_empty(this.validation.validate(form, key, configuration))) {
  660. return [];
  661. }
  662. var ret = new Object();
  663. ret[key] = [this.error.replace(/%n/, labelize(key))];
  664. return ret;
  665. };
  666. // end functions
  667. return this;
  668. }
  669. var vtReverse = vtReverseValidation;
  670. // end validations
  671. function labelize(string) {
  672. return ucwords(string.replace(/_/g,' '));
  673. }
  674. function is_empty(o) {
  675. var i, v;
  676. if (typeof(o) === 'object') {
  677. for (i in o) {
  678. v = o[i];
  679. if (v !== undefined && typeof(v) !== 'function') {
  680. return false;
  681. }
  682. }
  683. }
  684. return true;
  685. }
  686. // TODO: The following three functions may just be hiding coding problems
  687. // look into them and determine if they can be improved
  688. function has_class(element,value) {
  689. if (element !== undefined && element.className !== undefined)
  690. return element.className.match(new RegExp('(\\s|^)'+value+'(\\s|$)'));
  691. }
  692. function add_class(element, value) {
  693. if (element && element !== undefined && element.className !== undefined)
  694. if (!has_class(element,value)) element.className += " "+value;
  695. }
  696. function remove_class(element, value) {
  697. if (element && element != undefined && element.className !== undefined) {
  698. if (has_class(element,value)) {
  699. var reg = new RegExp('(\\s|^)+'+value+'(\\s|$)+');
  700. element.className=element.className.replace(reg,' ');
  701. }
  702. }
  703. }
  704. function extract_date(date, format) {
  705. var regex = new RegExp(format.replace("DD", "(\\d+)").replace("MM", "(\\d+)").replace("YYYY", "(\\d+)"));
  706. // To get around javascripts lack of named parameters - figure out the order
  707. // todo: make this more efficient - this is a stupid way there must be something easier
  708. var dd_pos = format.indexOf('DD');
  709. var mm_pos = format.indexOf('MM');
  710. var yyyy_pos = format.indexOf('YYYY');
  711. var matches = regex.exec(date);
  712. if (!matches) return null;
  713. if (dd_pos < mm_pos) {
  714. if (mm_pos < yyyy_pos) {
  715. // DD - MM - YYYY
  716. var day = matches[1];
  717. var month = matches[2];
  718. var year = matches[3];
  719. } else {
  720. if (dd_pos < yyyy_pos) {
  721. // DD - YYYY - MM
  722. var day = matches[1];
  723. var month = matches[3];
  724. var year = matches[2];
  725. } else {
  726. // YYYY - DD - MM
  727. var day = matches[2];
  728. var month = matches[3];
  729. var year = matches[1];
  730. }
  731. }
  732. } else {
  733. if (dd_post < yyyy_pos) {
  734. // MM - DD - YYYY
  735. var day = matches[2];
  736. var month = matches[1];
  737. var year = matches[3];
  738. } else {
  739. if (mm_pos < yyyy_pos) {
  740. // MM - YYYY - DD
  741. var day = matches[3];
  742. var month = matches[1];
  743. var year = matches[2];
  744. } else {
  745. // YYYY - MM - DD
  746. var day = matches[3];
  747. var month = matches[2];
  748. var year = matches[1];
  749. }
  750. }
  751. }
  752. var ret = new Object();
  753. ret.month = month;
  754. ret.day = day;
  755. ret.year = year;
  756. return ret;
  757. }
  758. /**
  759. * Escape Regular Expressions
  760. */
  761. RegExp.escape = function(text) {
  762. if (!arguments.callee.sRE) {
  763. var specials = [
  764. '/', '.', '*', '+', '?', '|',
  765. '(', ')', '[', ']', '{', '}', '\\'
  766. ];
  767. arguments.callee.sRE = new RegExp(
  768. '(\\' + specials.join('|\\') + ')', 'g'
  769. );
  770. }
  771. return text.replace(arguments.callee.sRE, '\\$1');
  772. }
  773. /**
  774. * The following functions are taken from the MIT licensed PHP.js
  775. * The license is available in licenses/php.js.txt
  776. */
  777. function ucwords(string) {
  778. return string.replace(/^(.)|\s(.)/g, function (letter) {
  779. return letter.toUpperCase();
  780. }
  781. );
  782. }
  783. function array_merge_recursive (arr1, arr2){
  784. var idx = '';
  785. if ((arr1 && (arr1 instanceof Array)) && (arr2 && (arr2 instanceof Array))) {
  786. for (idx in arr2) {
  787. arr1.push(arr2[idx]);
  788. }
  789. } else if ((arr1 && (arr1 instanceof Object)) && (arr2 && (arr2 instanceof Object))) {
  790. for (idx in arr2) {
  791. if (idx in arr1) {
  792. if (typeof arr1[idx] == 'object' && typeof arr2 == 'object') {
  793. arr1[idx] = array_merge(arr1[idx], arr2[idx]);
  794. } else {
  795. arr1[idx] = arr2[idx];
  796. }
  797. } else {
  798. arr1[idx] = arr2[idx];
  799. }
  800. }
  801. }
  802. return arr1;
  803. }
  804. function array_merge() {
  805. var args = Array.prototype.slice.call(arguments);
  806. var retObj = {}, k, j = 0, i = 0;
  807. var retArr;
  808. for (i=0, retArr=true; i < args.length; i++) {
  809. if (!(args[i] instanceof Array)) {
  810. retArr=false;
  811. break;
  812. }
  813. }
  814. if (retArr) {
  815. return args;
  816. }
  817. var ct = 0;
  818. for (i=0, ct=0; i < args.length; i++) {
  819. if (args[i] instanceof Array) {
  820. for (j=0; j < args[i].length; j++) {
  821. retObj[ct++] = args[i][j];
  822. }
  823. } else {
  824. for (k in args[i]) {
  825. if (this.is_int(k)) {
  826. retObj[ct++] = args[i][k];
  827. } else {
  828. retObj[k] = args[i][k];
  829. }
  830. }
  831. }
  832. }
  833. return retObj;
  834. }
  835. function is_int( mixed_var ) {
  836. if (typeof mixed_var !== 'number') {
  837. return false;
  838. }
  839. if (parseFloat(mixed_var) != parseInt(mixed_var, 10)) {
  840. return false;
  841. }
  842. return true;
  843. }
  844. function is_string( mixed_var ) {
  845. return (typeof(mixed_var) == 'string');
  846. }
  847. function is_array( mixed_var ) {
  848. var key = '';
  849. var getFuncName = function (fn) {
  850. var name = (/\W*function\s+([\w\$]+)\s*\(/).exec(fn);
  851. if(!name) {
  852. return '(Anonymous)';
  853. }
  854. return name[1];
  855. };
  856. if (!mixed_var) {
  857. return false;
  858. }
  859. // BEGIN REDUNDANT
  860. this.php_js = this.php_js || {};
  861. this.php_js.ini = this.php_js.ini || {};
  862. // END REDUNDANT
  863. if (typeof mixed_var === 'object') {
  864. if (this.php_js.ini['phpjs.objectsAsArrays'] && // Strict checking for being a JavaScript array (only check this way if call ini_set('phpjs.objectsAsArrays', 0) to disallow objects as arrays)
  865. (
  866. (this.php_js.ini['phpjs.objectsAsArrays'].local_value.toLowerCase &&
  867. this.php_js.ini['phpjs.objectsAsArrays'].local_value.toLowerCase() === 'off') ||
  868. parseInt(this.php_js.ini['phpjs.objectsAsArrays'].local_value, 10) === 0)
  869. ) {
  870. return mixed_var.hasOwnProperty('length') && // Not non-enumerable because of being on parent class
  871. !mixed_var.propertyIsEnumerable('length') && // Since is own property, if not enumerable, it must be a built-in function
  872. getFuncName(mixed_var.constructor) !== 'String'; // exclude String()
  873. }
  874. if (mixed_var.hasOwnProperty) {
  875. for (key in mixed_var) {
  876. // Checks whether the object has the specified property
  877. // if not, we figure it's not an object in the sense of a php-associative-array.
  878. if (false === mixed_var.hasOwnProperty(key)) {
  879. return false;
  880. }
  881. }
  882. }
  883. // Read discussion at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_is_array/
  884. return true;
  885. }
  886. return false;
  887. }
  888. function checkdate(month, day, year) {
  889. var myDate = new Date();
  890. myDate.setFullYear( year, (month - 1), day );
  891. return ((myDate.getMonth()+1) == month && day<32);
  892. }
  893. function getValueFromField(name) {
  894. // Get a value from a field name, regardless of the field type
  895. // This works for radio buttons and anything with a .value
  896. // TODO: make this work for selectboxes
  897. var inputs = document.getElementsByName(name);
  898. if (inputs[0].type == 'radio') {
  899. for(var i = 0; i < inputs.length; i++) {
  900. if (inputs[i].checked) return inputs[i].value;
  901. }
  902. return '';
  903. }
  904. return inputs[0].value;
  905. }
  906. function vt_ajax_validate(form, key, configuration, validation) {
  907. if (!(jQuery)) {
  908. console.log('jQuery must be available to have ajax validation')
  909. }
  910. return jQuery.parseJSON(jQuery.ajax({
  911. type: 'GET',
  912. url: window.location,
  913. data: {"vt_action": "ajax_validation", "validation": validation, "vt_field_name": key, "vt_data": document.getElementsByName(form.name + '[' + key + ']')[0].value},
  914. async: false
  915. }).responseText);
  916. }