grimen-validatious-on-rails 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +52 -0
- data/generators/validatious/templates/v2.standalone.full.min.js +7 -0
- data/generators/validatious/templates/validatious.config.js +83 -0
- data/generators/validatious/validatious_generator.rb +12 -0
- data/lib/validatious.rb +10 -0
- data/lib/validatious/form_helper.rb +67 -0
- data/lib/validatious/rails_validation.rb +168 -0
- data/rails/init.rb +2 -0
- data/test/test_helper.rb +60 -0
- data/test/validatious/form_helper_test.rb +62 -0
- data/test/validatious/rails_validation_test.rb +88 -0
- data/test/validatious_test.rb +6 -0
- metadata +80 -0
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
|
7
|
+
NAME = "validatious-on-rails"
|
8
|
+
SUMMARY = %Q{Rails plugin that maps model validations to class names on form elements to integrate with Validatious.}
|
9
|
+
HOMEPAGE = "http://github.com/grimen/#{NAME}"
|
10
|
+
AUTHORS = ["Christian Johansen", "Jonas Grimfelt"]
|
11
|
+
EMAIL = "christian@cjohansen.no"
|
12
|
+
SUPPORT_FILES = %w(README)
|
13
|
+
|
14
|
+
begin
|
15
|
+
gem 'technicalpickles-jeweler', '>= 1.2.1'
|
16
|
+
require 'jeweler'
|
17
|
+
Jeweler::Tasks.new do |gemspec|
|
18
|
+
gemspec.name = NAME
|
19
|
+
gemspec.summary = SUMMARY
|
20
|
+
gemspec.description = SUMMARY
|
21
|
+
gemspec.homepage = HOMEPAGE
|
22
|
+
gemspec.authors = AUTHORS
|
23
|
+
gemspec.email = EMAIL
|
24
|
+
|
25
|
+
gemspec.require_paths = %w{lib}
|
26
|
+
gemspec.files = SUPPORT_FILES << %w(Rakefile) <<
|
27
|
+
Dir.glob(File.join('{generators,lib,test,rails}', '**', '*').to_s).reject { |v| v =~ /\.log/i }
|
28
|
+
gemspec.executables = %w()
|
29
|
+
gemspec.extra_rdoc_files = SUPPORT_FILES
|
30
|
+
end
|
31
|
+
rescue LoadError
|
32
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
33
|
+
end
|
34
|
+
|
35
|
+
desc %Q{Default: Run unit tests for "#{NAME}".}
|
36
|
+
task :default => :test
|
37
|
+
|
38
|
+
desc %Q{Run unit tests for "#{NAME}".}
|
39
|
+
Rake::TestTask.new(:test) do |test|
|
40
|
+
test.libs << %w(lib test)
|
41
|
+
test.pattern = File.join('test', '**', '*_test.rb')
|
42
|
+
test.verbose = true
|
43
|
+
end
|
44
|
+
|
45
|
+
desc %Q{Generate documentation for "#{NAME}".}
|
46
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = NAME
|
49
|
+
rdoc.options << '--line-numbers' << '--inline-source' << '--charset=UTF-8'
|
50
|
+
rdoc.rdoc_files.include(SUPPORT_FILES)
|
51
|
+
rdoc.rdoc_files.include(File.join('lib', '**', '*.rb'))
|
52
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/**
|
2
|
+
* TERMS OF USE - Validatious 2.0
|
3
|
+
* Open source under the BSD License.
|
4
|
+
* Copyright 2008 Christian Johansen.
|
5
|
+
* All rights reserved.
|
6
|
+
*/
|
7
|
+
var addDOMLoadEvent=(function(){var F=[],A,E,C,B,D,G=function(){C=true;clearInterval(A);while(B=F.shift()){B()}if(E){E.onreadystatechange=""}};return function(H){if(C){return H()}if(!F[0]){if(document.addEventListener){document.addEventListener("DOMContentLoaded",G,false)}if(/WebKit/i.test(navigator.userAgent)){A=setInterval(function(){if(/loaded|complete/.test(document.readyState)){G()}},10)}D=window.onload;window.onload=function(){G();if(D){D()}}}F.push(H)}})();var Base=function(){};Base.extend=function(B,E){var F=Base.prototype.extend;Base._prototyping=true;var D=new this;F.call(D,B);delete Base._prototyping;var C=D.constructor;var A=D.constructor=function(){if(!Base._prototyping){if(this._constructing||this.constructor==A){this._constructing=true;C.apply(this,arguments);delete this._constructing}else{if(arguments[0]!=null){return(arguments[0].extend||F).call(arguments[0],D)}}}};A.ancestor=this;A.extend=this.extend;A.forEach=this.forEach;A.implement=this.implement;A.prototype=D;A.toString=this.toString;A.valueOf=function(G){return(G=="object")?A:C.valueOf()};F.call(A,E);if(typeof A.init=="function"){A.init()}return A};Base.prototype={extend:function(B,H){if(arguments.length>1){var E=this[B];if(E&&(typeof H=="function")&&(!E.valueOf||E.valueOf()!=H.valueOf())&&/\bbase\b/.test(H)){var A=H.valueOf();H=function(){var K=this.base||Base.prototype.base;this.base=E;var J=A.apply(this,arguments);this.base=K;return J};H.valueOf=function(J){return(J=="object")?H:A};H.toString=Base.toString}this[B]=H}else{if(B){var G=Base.prototype.extend;if(!Base._prototyping&&typeof this!="function"){G=this.extend||G}var D={toSource:null};var F=["constructor","toString","valueOf"];var C=Base._prototyping?0:1;while(I=F[C++]){if(B[I]!=D[I]){G.call(this,I,B[I])}}for(var I in B){if(!D[I]){G.call(this,I,B[I])}}}}return this},base:function(){}};Base=Base.extend({constructor:function(){this.extend(arguments[0])}},{ancestor:Object,version:"1.1",forEach:function(A,D,C){for(var B in A){if(this.prototype[B]===undefined){D.call(C,A[B],B,A)}}},implement:function(){for(var A=0;A<arguments.length;A++){if(typeof arguments[A]=="function"){arguments[A](this.prototype)}else{this.prototype.extend(arguments[A])}}return this},toString:function(){return String(this.valueOf())}});function addEvent(B,D,C){if(B.addEventListener){B.addEventListener(D,C,false)}else{if(!C.$$guid){C.$$guid=addEvent.guid++}if(!B.events){B.events={}}var A=B.events[D];if(!A){A=B.events[D]={};if(B["on"+D]){A[0]=B["on"+D]}}A[C.$$guid]=C;B["on"+D]=handleEvent}}addEvent.guid=1;function removeEvent(A,C,B){if(A.removeEventListener){A.removeEventListener(C,B,false)}else{if(A.events&&A.events[C]){delete A.events[C][B.$$guid]}}}function handleEvent(D){var C=true;D=D||fixEvent(((this.ownerDocument||this.document||this).parentWindow||window).event);var A=this.events[D.type];for(var B in A){this.$$handleEvent=A[B];if(this.$$handleEvent(D)===false){C=false}}return C}function fixEvent(A){A.preventDefault=fixEvent.preventDefault;A.stopPropagation=fixEvent.stopPropagation;return A}fixEvent.preventDefault=function(){this.returnValue=false};fixEvent.stopPropagation=function(){this.cancelBubble=true};if(typeof v2==="undefined"||v2===null){v2={}}v2.empty=function empty(A){return typeof A=="undefined"||A===null||A===""};v2.array=function array(C){var A=[];if(C&&typeof C.item==="function"){for(var B=0;B<C.length;B++){A[B]=C[B]}C=A}return v2.empty(C)?[]:(typeof C.shift=="undefined"?[C]:C)};v2.Object={extend:function(C,A,B){B=typeof B==="undefined"?false:B;for(var D in A){if(B&&typeof C[D]!=="undefined"){continue}if(A.hasOwnProperty(D)&&typeof A[D]!=="undefined"){C[D]=A[D]}}return C}};v2.Object.extend(String.prototype,{strip:function(){return this.replace(/^\s+|\s+$/,"")}});v2.Object.extend(Array.prototype,{indexOf:function(C,A){for(var B=0;B<this.length;B++){if(this[B]===C){return B}}return -1}});v2.$=function(A,C){if(typeof A=="string"){A=document.getElementById(A)}C=typeof C=="undefined"?true:C;if(A===null||typeof A.hide!="undefined"||!C){return A}for(var B in v2.Element){if(v2.Element.hasOwnProperty(B)){(function(){var D=B;var E={};E[D]=function(){var F=[A];for(var G=0;G<arguments.length;G++){F.push(arguments[G])}return v2.Element[D].apply(v2.Element,F)};v2.Object.extend(A,E,true)})()}}return A};v2.$$=function $$(E,N){N=N||document;if(document.querySelectorAll){v2.$$=function(Q,R){return(R||document).querySelectorAll(Q)};return v2.$$(E,N)}var O=E.split(",");var J,H,F,B,K,D,A,I,C,G,L,M;var P=[];for(J=0;(E=O[J]);J++){B=E.strip().split(/[^a-zA-Z]/)[0]||"*";K=E.replace(/^\./,"_.").split(/\./);C=[];G=[];for(H=1;H<K.length;H++){C.push(K[H].split(/[^a-zA-Z\-_]/)[0])}K=E.replace("][","].[").split(/[\[\]]/);for(H=0;H<K.length-1;H+=2){D=K[H+1].split("=");D[1]=D[1]||true;G.push(D)}A=N.getElementsByTagName(B);elementLoop:for(H=0;(I=A[H]);H++){for(F=0;F<C.length;F++){if(!v2.Element.hasClassName(I,C[F])){continue elementLoop}}for(F=0;F<G.length;F++){L=G[F][0];M=G[F][1];if(I.hasAttribute){if(!I.hasAttribute(L)||(M!==true&&I.getAttribute(L)!==M)){continue elementLoop}}else{L=L==="for"?"htmlFor":L;if(typeof I[L]==="undefined"||(M!==true&&I[L]!==M)){continue elementLoop}}}if(P.indexOf(I)<0){P.push(I)}}}return P};v2.Element={observe:function(B,C,A){addEvent(B,C,A)},computedStyle:function(A,C){var B="";if(document.defaultView&&document.defaultView.getComputedStyle){B=document.defaultView.getComputedStyle(A,"").getPropertyValue(C)}else{if(A.currentStyle){C=C.replace(/\-(\w)/g,function(D,E){return E.toUpperCase()});B=A.currentStyle[C]}}return B},visible:function(A){return v2.Element.computedStyle(A,"display")!="none"&&v2.Element.computedStyle(A,"visibility")!="hidden"&&(A.parentNode===null||A.parentNode.nodeType!=1||v2.Element.visible(A.parentNode))},hasClassName:function(B,A){return new RegExp("(^|\\s)"+A+"(\\s|$)").test(B.className)},addClassName:function(B,A){B.className+=v2.Element.hasClassName(B,A)?"":" "+A;B.className=B.className.replace(" "," ").replace(/^\s|\s$/,"");return B},removeClassName:function(B,A){var C=new RegExp("(^|\\s)"+A+"(\\s|$)");B.className=B.className.replace(C," ").replace(" "," ").replace(/^\s|\s$/,"");return B},position:function(A){var B={x:0,y:0};while(A!==null){B.x+=A.offsetLeft;B.y+=A.offsetTop;A=A.offsetParent}return B},scrollTo:function(A){var B=v2.Element.position(A);window.scrollTo(B.x,B.y)},previous:function(A){do{A=A.previousSibling}while(A&&A.nodeType!==1);return A}};v2.Object.extend(Function.prototype,{bind:function(B){var A=this;A.__cc=A.__cc||[];window.__coc=window.__coc||0;if(typeof B.__id=="undefined"){B.__id=window.__coc++}A.__cc[B.__id]=A.__cc[B.__id]||function(){try{return A.apply(B,arguments)}catch(C){}};return A.__cc[B.__id]}});if(typeof addDOMLoadEvent!="undefined"){v2.addDOMLoadEvent=addDOMLoadEvent}v2.CompositeFormItem=Base.extend({type:"generic",constructor:function(){if(v2.empty(this.__validators)){this.__validators=[]}if(v2.empty(this.__errors)){this.__errors=[]}this.__passOnAny=false;this.__message=null;this.parent=null},add:function(A){this.__validators.push(A);A.parent=this},get:function(A){return !v2.empty(A)?this.__validators[A]:this.__validators},validate:function(){this.__errors=[];var A=this.test("validate");if(A){this.__errors=[];this.onSuccess()}else{this.onFailure()}return A},test:function(C){var B,A,D=0;C=C||"test";for(B=0;(A=this.__validators[B]);B++){if(A[C]()){D++}else{this.__errors.push(A)}}return this.passOnAny()&&D>0||!this.passOnAny()&&D===this.__validators.length},getInvalid:function(){return this.__errors.length===0?null:this.__errors},setMessage:function(A){this.__message=A},getMessages:function(){if(!v2.empty(this.__message)){return[this.__message]}var C=[],B,A;for(B=0,A;(A=this.__errors[B]);B++){C=C.concat(A.getMessages())}return C},passOnAny:function(A){if(typeof A!=="undefined"){this.__passOnAny=!!A}return this.__passOnAny},onSuccess:function(){},onFailure:function(){}});v2.InputElement=Base.extend({constructor:function(B,A){this.__name=null;this.__events=v2.empty(A)?["blur"]:v2.array(A);this.__elements=v2.array(B)},monitor:function(D){this.__monitored=true;var C,A,B,E;for(C=0;(B=this.__elements[C]);C++){for(A=0;(E=this.__events[A]);A++){v2.Element.observe(B,E,D)}}},getValue:function(){return this.__elements[0].value},getLabel:function(){var B=this.__elements[0];var A=v2.$$("label[for="+(B.id||B.name)+"]",B.form);return A&&A[0]},getName:function(){if(this.__name){return this.__name}var A=this.getLabel();if(A){return A.title!==""?A.title:A.innerHTML}var B=this.__elements[0];return B.id||B.name},setName:function(A){this.__name=!!A?A:null;return this},getParent:function(){return this.__elements[0].parentNode},getElements:function(){return this.__elements},visible:function(){if(!v2.$(this.getParent()).visible()){return false}for(var A=0,B;(B=this.__elements[A]);A++){if(v2.Element.visible(B)){return true}}return false}},{__fields:{},get:function(B){if(B&&B.constructor===v2.InputElement){return B}var C=v2.$(B),H,G,F,A,D,E;if(!C){A="input$, select$, textarea$";F=v2.$$(A.replace(/\$/g,"[name="+B+"]"));C=F[0]}if(!C){throw new TypeError(B+" does not resolve to an HTML element!")}H=C.name||C.id;if((G=v2.InputElement.__fields[H])){return G}if(C.options){G=new v2.SelectElement(C)}else{if(C.tagName.toLowerCase()==="textarea"){G=new v2.TextareaElement(C)}else{if(C.type&&C.type=="radio"){F=v2.$$("input[type=radio][name="+C.name+"]",C.form);G=new v2.RadioElement(F)}else{if(C.type&&C.type=="checkbox"){D=C.className;E=/\bg_([^\s]*)\b/;F=E.test(D)?v2.$$("input[type=checkbox].g_"+D.match(E)[1],C.form):[C];G=new v2.CheckboxElement(F)}else{G=new v2.InputElement(C)}}}}return(v2.InputElement.__fields[H]=G)}});v2.$f=v2.InputElement.get;v2.RadioElement=v2.InputElement.extend({constructor:function(A){this.base(A,["click","change"])},getValue:function(){for(var B=0,A;(A=this.__elements[B]);B++){if(A.checked){return A.value}}return null},getLabel:function(){var B=this.__elements[0].parentNode;if(B.tagName.toLowerCase()==="li"){return v2.$(B.parentNode).previous()}var A=v2.$(this.__elements[0]).previous();return A||this.base()},getParent:function(){var A=this.__elements[0].parentNode;return A.tagName.toLowerCase()==="li"?A.parentNode.parentNode:A}});v2.SelectElement=v2.InputElement.extend({constructor:function(A){this.base([A],"change")},getValue:function(){var A=this.__elements[0];if(!A.multiple){return A.options[A.selectedIndex].value}var B=[];for(var C=0,D;(D=A.options[C]);C++){if(D.selected){B.push(D.value)}}return B}});v2.TextareaElement=v2.InputElement.extend({});v2.CheckboxElement=v2.RadioElement.extend({getValue:function(){var A=[],B,C;for(B=0,C;(C=this.__elements[B]);B++){if(C.checked){A.push(C.value)}}return A}});v2.Message=Base.extend({constructor:function(B,C,A){this.message=B;this.params=C||[];this.values=A||[]},copy:function(){return new v2.Message(this.message,this.params,this.values)},toString:function(){var C=this.message+"";for(var A=0,B=null;(B=this.params[A]);A++){C=C.replace("${"+B+"}",this.values[A])}return C}});v2.Validator=Base.extend({constructor:function(B,C,D,E,A){this.__name=B;this.__test=C;this.__message=new v2.Message(D||"${field} does not pass "+B+" validator",E);this.__aliases=v2.array(A);this.acceptEmpty=true},test:function(C,E,D){D=typeof D==="undefined"?false:D;var B=C.getValue();var A=(this.acceptEmpty&&B==="")||this.__test(C,B,E);return(A&&!D)||(!A&&D)},getName:function(){return this.__name},getMessage:function(){return this.__message},setMessage:function(A){this.__message.message=A}},{validators:{},add:function(B){if(!B.name||!B.fn){throw new TypeError("Options object should contain name and fn")}B=v2.Object.extend({params:[],aliases:[],acceptEmpty:true},B,false);var F=v2.array(B.params);var D=new v2.Validator(B.name,B.fn,B.message,F,B.aliases);D.acceptEmpty=B.acceptEmpty;var E=v2.array(B.aliases).concat([B.name]);for(var C=0,A;(A=E[C]);C++){v2.Validator.validators[A]=D}return D},reg:function(B,C,F,D,A,E){return v2.Validator.add({name:B,fn:C,message:D,params:F,aliases:A,acceptEmpty:E})},get:function(A){var B;if(A.constructor===v2.Validator){return A}if((B=v2.Validator.validators[A])){return B}return null}});v2.$v=function(A){return v2.Validator.get(A)};v2.$msg=function(){if(arguments.length===2){return v2.Validator.get(arguments[0]).setMessage(arguments[1])}for(var A in arguments[0]){try{v2.Validator.get(A).setMessage(arguments[0][A])}catch(B){}}};v2.Field=v2.CompositeFormItem.extend({validateHidden:false,instant:false,instantWhenValidated:true,type:"field",constructor:function(B,A,C){this.base();this.__monitored=false;this.element=v2.$f(B);this.instant=typeof A!=="undefined"?A:this.instant;this.instantWhenValidated=typeof C!=="undefined"?C:this.instantWhenValidated;this.__monitor(this.instant)},test:function(){if(!this.validateHidden&&!this.element.visible()){return true}return this.base()},validate:function(){this.__monitor(this.instantWhenValidated&&!this.__monitored);return this.base()},addValidator:function(A,E,C){var B=v2.$v(A);if(B===null){throw new Error(A+" is not a valid validator")}if(typeof C!=="undefined"&&C!==null){C=new v2.Message(C,B.getMessage().params)}var D=new v2.FieldValidator(this.element,B,v2.array(E),C);this.add(D);return D},getParent:function(){return this.element.getParent()},__monitor:function(C){if(!C||this.__monitored){return }this.__monitored=true;var A=this.parent&&this.parent.type==="fieldset"?this.parent:this;var B=A.validate.bind(this);this.element.monitor(function(D){B(D)})}});v2.Fieldset=v2.CompositeFormItem.extend({type:"fieldset",constructor:function(A){this.base();this.element=A},getParent:function(){return this.element}});v2.FieldValidator=Base.extend({invert:false,constructor:function(C,A,E,D){this.__field=C;this.__validator=A;this.__params=v2.array(E);this.__message=D||A.__message.copy();var B=this.__message.params;if(B.length<1||B[0]!=="field"){this.__message.params=["field"].concat(B)}this.__message.values=[this.__field.getName()].concat(this.__params)},test:function(){return this.__validator.test(this.__field,this.__params,this.invert)},validate:function(){return this.test()},getInvalid:function(){return !this.test()?this:null},setMessage:function(A){this.__message.message=A},getMessages:function(){return[this.__message.toString()]},add:function(){},remove:function(){},get:function(){},passOnAny:function(){},onSuccess:function(){},onFailure:function(){}});v2.Form=v2.CompositeFormItem.extend({type:"form",constructor:function(A){this.base();this.__form=v2.$(A);this.__form.observe("submit",this.validate.bind(this));this.__buttons=[];this.__activeButton=null},addButton:function(A){this.__buttons.push(A);v2.Element.observe(A,"click",(function(B){this.__activeButton=A}).bind(this))},validate:function(){var D=arguments.length>0?arguments[0]:null;var C=this.__buttons;var A=this.__activeButton;this.__activeButton=null;if(C.length>0&&C.indexOf(A)<0){return true}var B=this.base();if(!B&&D){D.preventDefault();D.returnValue=false}return B}},{forms:{},get:function(C){var B=v2.$(C),A;if(B===null||B.tagName.toLowerCase()!=="form"){throw new ArgumentError("idOrElement should represent a form element")}if(!v2.empty(A=v2.Form.forms[B.id])){return A}return(v2.Form.forms[B.id]=new v2.Form(B))}});(function(){var A=v2.Validator;A.reg("alpha",function(C,B,D){return/^[a-zA-Z\u00A1-\uFFFF]*$/.test(B)});A.reg("alphanum",function(C,B,D){return/^([a-zA-Z\u00A1-\uFFFF0-9])*$/.test(B)});A.reg("confirmation-of",function(C,B,D){return B===v2.$f(D[0]).getValue()},"field-id","${field} should be an exact match",null,false);A.reg("email",function(C,B,D){return/^[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(B)});A.reg("max-length",function(C,B,D){return B.length<D[0]},"max");A.reg("max-val",function(C,B,D){return B<=D[0]},"max");A.reg("min-length",function(C,B,D){return B.length>=D[0]},"min");A.reg("min-val",function(C,B,D){return B>=D[0]},"min");A.reg("numeric",function(C,B,D){return/^[0-9]*(\.[0-9]+)?$/.test(B)});A.reg("required",function(C,B,D){return !v2.empty(B)&&!(typeof B.length!=="undefined"&&B.length===0)},null,null,"not-empty",false);A.reg("url",function(C,B,D){return/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i.test(B)});A.reg("word",function(C,B,D){return/^([a-zA-Z\u00A1-\uFFFF0-9_\-\s\t])*$/.test(B)})})();v2.$msg({alpha:"${field} should only contain letters",alphanum:"${field} should only contain letters and numbers","car-regnum-nor":"${field} should be a valid norwegian auto registration number","confirmation-of":"${field} should be a confirmation of ${field-id}",email:"${field} should be a valid email address","max-length":"${field} should be no more than ${max} characters long","max-val":"${field} should be no bigger than ${min}","min-length":"${field} should be atleast ${min} characters long","min-val":"${field} should be atleast ${min}",numeric:"${field} should only contain numbers","phone-nor":"${field} should be a valid norwegian phone number",required:"${field} is required","ssn-nor":"${field} should be a valid norwegian social security number",url:"${field} should be a valid URL",word:"${field} should only contain letters, numbers and punctuation"});v2.ErrorReporting={displayErrors:-1,positionErrorsAbove:true,failureClass:"error",successClass:"",messagesClass:"messages",onFailure:function(){if(this.parent&&this.parent.type==="fieldset"){return }var I=this.onSuccess();var F="",C,G,A,J;var K=[];var B=this.getMessages();I.addClassName(this.failureClass);I.removeClassName(this.successClass);var D=this.displayErrors;var H=this.__errors.length;D=D<0||D>H?H:D;if(D===0){return }var E=document.createElement("ul");E.id=this.__getId();E.className=this.messagesClass;for(C=0;C<D;C++){G=B[C];if(!G||K.indexOf(G.toString())>=0){continue}K.push(G.toString());J=document.createElement("li");J.innerHTML=G.toString();E.appendChild(J)}if(this.positionErrorsAbove){I.insertBefore(E,I.firstChild)}else{I.appendChild(E)}},onSuccess:function(){if(this.parent&&this.parent.type==="fieldset"){return null}var A=v2.$(this.getParent());var B=v2.$(this.__getId());if(B&&A===B.parentNode){A.removeChild(B)}A.removeClassName(this.failureClass);A.addClassName(this.successClass);return A},__getId:function(){var A=this.element.getElements?this.element.getElements()[0]:null;var C=A||this.getParent();var B=C.className;var D=((C.id||C.name||B.replace(this.failureClass,""))+"_"+this.failureClass).replace(" ","_").replace(/_+/,"_");return D}};v2.Object.extend(v2.Field.prototype,v2.ErrorReporting);v2.Object.extend(v2.Fieldset.prototype,v2.ErrorReporting);v2.Object.extend(v2.Form.prototype,{scrollToFirstWhenFail:true,onFailure:function(){if(!this.scrollToFirstWhenFail){return }var B,A,D,C=this.__form;D=C.all||C.getElementsByTagName("*");for(B=0;(A=D[B]);B++){if(v2.Element.hasClassName(A,v2.ErrorReporting.failureClass)){v2.Element.scrollTo(A);return }}}});v2.Object.extend(v2.Validator,{prefix:""});v2.Object.extend(v2.Form,{autoValidateClass:"validate",actionButtonClass:"action"});v2.html={validateAnyClass:"validate_any",validateAllClass:"validate_all",validatorsFromString:function(I){var E=v2.Validator.prefix;var G=new RegExp("^"+E,"");var F,H,B,D,A,C=[];I=I.split(" ");for(F=0;(H=I[F]);F++){B=false;if(!v2.empty(E)&&!G.test(H)){continue}H=H.replace(G,"");if(/^not_/.test(H)){H=H.replace(/^not_/,"");B=true}D=H.split("_");A=D.shift();if(A&&(A=v2.$v(A))){C.push({validator:A,params:D,invert:B})}}return C},applyValidators:function(A,F,D){if(!v2.empty(D)){F.setMessage(D)}for(var C=0,B,E;(B=A[C]);C++){E=F.addValidator(B.validator,B.params);E.invert=B.invert}return F}};v2.html.Form=Base.extend({constructor:function(A){this.form=v2.Form.get(A);this.__parsed={};this.parseElement(A,this.form);this.form.passOnAny(v2.$(A).hasClassName(v2.html.validateAnyClass))},parseElement:function(C,K,E){var A=v2.$$("div, fieldset, input, select, textarea",C);var H,F,B,I,G,D,L,J;this.__parsed[C.id||C.name]=true;E=E||[];for(H=0;(G=A[H]);H++){if(E.length===0&&(/^\s*$/.test(G.className)||this.__parsed[G.id||G.name])){continue}D=G.tagName.toLowerCase();if(D==="input"&&v2.Element.hasClassName(G,v2.Form.actionButtonClass)){this.form.addButton(G);continue}if(D==="div"||D==="fieldset"){this.parseBlock(G,K);continue}J=E.concat(v2.html.validatorsFromString(G.className));if(J.length>0){L=new v2.Field(G);v2.html.applyValidators(J,L,G.title);this.__parsed[G.id||G.name]=true;K.add(L)}}},parseBlock:function(C,E){var D=new v2.Fieldset(C);var B=true;v2.$(C);if(C.hasClassName(v2.html.validateAnyClass)){}else{if(C.hasClassName(v2.html.validateAllClass)){B=false}else{return }}D.passOnAny(B);var A=v2.html.validatorsFromString(C.className);this.parseElement(C,D,A);if(!/^\s*$/.test(C.title)){D.setMessage(C.title)}if(D.get(0)){E.add(D)}}});v2.addDOMLoadEvent(function(){var A=document.getElementsByTagName("form");for(var B=0,C;(C=A[B]);B++){if(v2.Element.hasClassName(C,v2.Form.autoValidateClass)){new v2.html.Form(C)}}});v2.dsl={__validateTemplate:function(A){return function(){var F=arguments[0];var D=F.element||(F.item?F.item.element:null)||null;if(D===null){while(!!F&&!F.element){F=F.get(0)}}var E=new v2.dsl.Form(D.getElements()[0].form);E.item.passOnAny(A);for(var C=0,B;(B=arguments[C]);C++){E.item.add(B.item||B)}return E}},__andOr:function(A){return function(){var D=new v2.dsl.Collection();D.item.passOnAny(A);for(var C=0,B;(B=arguments[C]);C++){D.item.add(B.item)}return D}}};v2.dsl.expose=function(){var A=v2.dsl;v2.Object.extend(window,{validate:A.validate,validateAll:A.validateAll,validateAny:A.validateAny,and:A.and,or:A.or},false)};v2.dsl.validateAll=v2.dsl.validate=v2.dsl.__validateTemplate(false);v2.dsl.validateAny=v2.dsl.__validateTemplate(true);v2.dsl.and=v2.dsl.__andOr(false);v2.dsl.or=v2.dsl.__andOr(true);v2.Object.extend(String.prototype,{is:function(A,C){var B=new v2.dsl.Field(this.toString());return B.addValidator(A,C)}});(function(){var A=String.prototype;A.isA=A.isAn=A.has=A.hasA=A.hasAn=A.is})();v2.dsl.Field=Base.extend({__currentValidator:null,__and:null,constructor:function(A){this.item=new v2.Field(A)},addValidator:function(A,C,B){if(typeof B!=="undefined"){if(this.__and!==null&&this.__and!==B){throw new Error("Field previously set up with "+(this.__and?"AND":"OR")+", unable to shift")}this.__and=B;this.item.passOnAny(!B)}this.__currentValidator=this.item.addValidator(A,C);return this},and:function(A,B){if(!this.__currentValidator){throw new Error("Cannot add more validators when no validators are added yet")}return this.addValidator(A,B,true)},or:function(A,B){if(!!this.__currentValidator){throw new Error("Cannot add more validators when no validators are added yet")}return this.addValidator(A,B,false)},explain:function(A){if(!this.__currentValidator){throw new Error("No active field validator")}this.__currentValidator.setMessage(A);return this},help:function(A){this.item.setMessage(A);return this},withName:function(A){this.item.element.setName(A);return this}});(function(){var A=v2.dsl.Field.prototype;A.orIs=A.orIsA=A.orIsAn=A.orHas=A.orHasA=A.orHasAn=A.or;A.andIs=A.andIsA=A.andIsAn=A.andHas=A.andHasA=A.andHasAn=A.and})();v2.dsl.Collection=Base.extend({constructor:function(){this.item=new v2.CompositeFormItem()},explain:function(A){this.item.setMessage(A)}});v2.dsl.Form=Base.extend({constructor:function(A){this.item=v2.Form.get(A)},on:function(){var B,A;for(B=0;B<arguments.length;B++){A=v2.$(arguments[B]);this.item.addButton(A.tagName.toLowerCase()!=="input"?A.getElementsByTagName("input")[0]:A)}}});
|
@@ -0,0 +1,83 @@
|
|
1
|
+
// -------------------------------------------
|
2
|
+
// VALIDATIOUS 2.0: Configuration
|
3
|
+
// -------------------------------------------
|
4
|
+
//
|
5
|
+
// More: http://validatious.org/learn/references
|
6
|
+
//
|
7
|
+
|
8
|
+
// Auto-validate form with this class.
|
9
|
+
//
|
10
|
+
// v2.Form.autoValidateClass = 'validate';
|
11
|
+
|
12
|
+
// Trigger validation on action with this class.
|
13
|
+
//
|
14
|
+
v2.Form.actionButtonClass = 'commit'; // Formtastic: Use 'commit'
|
15
|
+
|
16
|
+
// Validate any/all of the validations in a block with this class.
|
17
|
+
//
|
18
|
+
// Example:
|
19
|
+
//
|
20
|
+
// <div class="validate_any">
|
21
|
+
// ...
|
22
|
+
// </div>
|
23
|
+
//
|
24
|
+
// v2.html.validateAnyClass = 'validate_any';
|
25
|
+
// v2.html.validateAnyClass = 'validate_all';
|
26
|
+
|
27
|
+
// Make generated validation classes namespaced to avoid clashes with other classes.
|
28
|
+
//
|
29
|
+
// v2.Validator.prefix = 'v2_';
|
30
|
+
|
31
|
+
// Validate instantly or on submit.
|
32
|
+
//
|
33
|
+
v2.Field.prototype.instant = true;
|
34
|
+
v2.Field.prototype.instantWhenValidated = true;
|
35
|
+
|
36
|
+
// Validate all hidden fields.
|
37
|
+
//
|
38
|
+
// v2.Field.prototype.validateHidden = false;
|
39
|
+
|
40
|
+
// Jump to first invalid field on error.
|
41
|
+
//
|
42
|
+
v2.Form.prototype.scrollToFirstWhenFail = true;
|
43
|
+
|
44
|
+
// Maximum number of errors at the same time.
|
45
|
+
//
|
46
|
+
// * -1, default value, display all messages
|
47
|
+
// * 0, display no messages, only append class names on failing elements
|
48
|
+
// * n, where n is any positive integer, display no more than this many messages
|
49
|
+
//
|
50
|
+
// v2.Field.prototype.displayErrors = 1;
|
51
|
+
|
52
|
+
// Position of errors.
|
53
|
+
//
|
54
|
+
v2.Field.prototype.positionErrorsAbove = false;
|
55
|
+
v2.Fieldset.prototype.positionErrorsAbove = false;
|
56
|
+
|
57
|
+
// Error classes.
|
58
|
+
//
|
59
|
+
// Example:
|
60
|
+
//
|
61
|
+
// <fieldset
|
62
|
+
// <div class="field error"
|
63
|
+
// <label for="name">Name</label
|
64
|
+
// <input type="text" name="name" id="name" class="required word"
|
65
|
+
// <ul class="errors"
|
66
|
+
// <li>Name is required</li
|
67
|
+
// </ul
|
68
|
+
// </div
|
69
|
+
// <div class="field error"
|
70
|
+
// <label for="email">E-mail</label
|
71
|
+
// <input type="text" name="email" id="email" class="email" value="name@"
|
72
|
+
// <ul class="errors"
|
73
|
+
// <li>E-mail should be a valid email address</li
|
74
|
+
// </ul
|
75
|
+
// </div
|
76
|
+
// </fieldset>
|
77
|
+
//
|
78
|
+
v2.Fieldset.prototype.messagesClass = 'errors'; // Formtastic: Use 'errors'
|
79
|
+
v2.Fieldset.prototype.failureClass = 'error'; // Formtastic: Use 'error'
|
80
|
+
v2.Fieldset.prototype.successClass = '';
|
81
|
+
v2.Field.prototype.messagesClass = 'errors'; // Formtastic: Use 'errors'
|
82
|
+
v2.Field.prototype.failureClass = 'error'; // Formtastic: Use 'error'
|
83
|
+
v2.Field.prototype.successClass = '';
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class ValidatiousGenerator < Rails::Generator::Base
|
4
|
+
|
5
|
+
def manifest
|
6
|
+
record do |m|
|
7
|
+
m.template 'v2.standalone.full.min.js', File.join('public', 'javascripts', 'v2.standalone.full.min.js')
|
8
|
+
m.template 'validatious_config.js', File.join('public', 'javascripts', 'validatious.config.js')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
data/lib/validatious.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Tap into the built-in form helpers to add validatious class names from
|
4
|
+
# model validations.
|
5
|
+
#
|
6
|
+
module ActionView
|
7
|
+
module Helpers
|
8
|
+
module FormHelper
|
9
|
+
|
10
|
+
#
|
11
|
+
# Add validation class names to: text-fields.
|
12
|
+
#
|
13
|
+
def text_field_with_validation(object_name, method, options = {})
|
14
|
+
options = Validatious::RailsValidation.options_for(object_name, method, options)
|
15
|
+
text_field_without_validation(object_name, method, options)
|
16
|
+
end
|
17
|
+
alias_method_chain :text_field, :validation
|
18
|
+
|
19
|
+
#
|
20
|
+
# Add validation class names to: password-fields.
|
21
|
+
#
|
22
|
+
def password_field_with_validation(object_name, method, options = {})
|
23
|
+
options = Validatious::RailsValidation.options_for(object_name, method, options)
|
24
|
+
password_field_without_validation(object_name, method, options)
|
25
|
+
end
|
26
|
+
alias_method_chain :password_field, :validation
|
27
|
+
|
28
|
+
#
|
29
|
+
# Add validation class names to: text-areas.
|
30
|
+
#
|
31
|
+
def text_area_with_validation(object_name, method, options = {})
|
32
|
+
options = Validatious::RailsValidation.options_for(object_name, method, options)
|
33
|
+
text_area_without_validation(object_name, method, options)
|
34
|
+
end
|
35
|
+
alias_method_chain :text_area, :validation
|
36
|
+
|
37
|
+
#
|
38
|
+
# Add validation class names to: check-boxes.
|
39
|
+
#
|
40
|
+
def check_box_with_validation(object_name, method, options = {}, checked_value = '1', unchecked_value = '0')
|
41
|
+
options = Validatious::RailsValidation.options_for(object_name, method, options)
|
42
|
+
check_box_without_validation(object_name, method, options)
|
43
|
+
end
|
44
|
+
alias_method_chain :check_box, :validation
|
45
|
+
|
46
|
+
#
|
47
|
+
# Add validation class names to: radio-buttons.
|
48
|
+
#
|
49
|
+
def radio_button_with_validation(object_name, method, tag_value, options = {})
|
50
|
+
options = Validatious::RailsValidation.options_for(object_name, method, options)
|
51
|
+
radio_button_without_validation(object_name, method, tag_value, options)
|
52
|
+
end
|
53
|
+
alias_method_chain :radio_button, :validation
|
54
|
+
|
55
|
+
#
|
56
|
+
# Adds the title attribute to label tags when there is no title
|
57
|
+
# set, and the label text is provided. The title is set to object_name.humanize
|
58
|
+
#
|
59
|
+
def label_with_title(object_name, method, text = nil, options = {})
|
60
|
+
options[:title] ||= method.to_s.humanize unless text.nil?
|
61
|
+
label_without_title(object_name, method, text, options)
|
62
|
+
end
|
63
|
+
alias_method_chain :label, :title
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
begin
|
3
|
+
require 'validation_reflection'
|
4
|
+
rescue LoadError
|
5
|
+
gem 'redinger-validation_reflection', '>= 0.3.2'
|
6
|
+
require 'validation_reflection'
|
7
|
+
end
|
8
|
+
|
9
|
+
#
|
10
|
+
# Force this, as it seems ValidationReflection don't do this correctly. =S
|
11
|
+
#
|
12
|
+
ActiveRecord::Base.class_eval do
|
13
|
+
include ::ActiveRecordExtensions::ValidationReflection
|
14
|
+
::ActiveRecordExtensions::ValidationReflection.load_config
|
15
|
+
::ActiveRecordExtensions::ValidationReflection.install(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Validatious-Rails validation translator.
|
20
|
+
#
|
21
|
+
module Validatious
|
22
|
+
class RailsValidation
|
23
|
+
class << self
|
24
|
+
|
25
|
+
# Reference: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html
|
26
|
+
|
27
|
+
#
|
28
|
+
# Generates form field helper options for a specified object-attribute to
|
29
|
+
# reflect on it's validations.
|
30
|
+
#
|
31
|
+
# Input may be an ActiveRecord class, a class name (string), or an object
|
32
|
+
# name along with a method/field.
|
33
|
+
#
|
34
|
+
def options_for(object_name, method, options = {})
|
35
|
+
validation = self.from_active_record(object_name, method)
|
36
|
+
|
37
|
+
# Loop validation and add/append pairs to options.
|
38
|
+
validation.each_pair do |attr, value|
|
39
|
+
options[attr] ||= ''
|
40
|
+
options[attr] << value
|
41
|
+
|
42
|
+
# Shake out duplicates.
|
43
|
+
options[attr] = options[attr].split.uniq.join(' ').strip
|
44
|
+
end
|
45
|
+
options
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Groks rails validations, and is able to convert a rails validation to
|
50
|
+
# a Validatious 2.0 compatible class string.
|
51
|
+
#
|
52
|
+
# Input may be an ActiveRecord class, a class name (string), or an object
|
53
|
+
# name along with a method/field.
|
54
|
+
#
|
55
|
+
# Returns a string that will be recognized by Validatious as a class name in
|
56
|
+
# form markup.
|
57
|
+
#
|
58
|
+
def from_active_record(object_or_class, method)
|
59
|
+
klass = object_or_class.to_s.classify.constantize
|
60
|
+
options = {:class => ''}
|
61
|
+
validation_classes = []
|
62
|
+
|
63
|
+
# Iterate thorugh the validations for the current class,
|
64
|
+
# and collect validation options.
|
65
|
+
klass.reflect_on_validations_for(method).each do |validation|
|
66
|
+
validation_options = self.send(validation.macro.to_s.sub(/^validates_/, ''), validation)
|
67
|
+
validation_classes << validation_options[:class]
|
68
|
+
end
|
69
|
+
options[:class] = [options[:class], validation_classes].flatten.compact.join(' ')
|
70
|
+
options
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
# Resolve validation from validates_acceptance_of.
|
75
|
+
#
|
76
|
+
# Note: acceptance_of <=> presence_of (for Validatious)
|
77
|
+
#
|
78
|
+
def acceptance_of(validation)
|
79
|
+
{:class => 'required'}
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Resolve validation from validates_associated.
|
84
|
+
#
|
85
|
+
def associated(validation)
|
86
|
+
{:class => ''}
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# TODO: Resolve validation from validates_confirmation_of.
|
91
|
+
#
|
92
|
+
# Note: Should be added to "#{field}_confirmation" instead of "#{field}", i.e. non-standard approach.
|
93
|
+
#
|
94
|
+
def confirmation_of(validation)
|
95
|
+
{:class => ''}
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# TODO: Resolve validation from validates_exclusion_of.
|
100
|
+
#
|
101
|
+
def exclusion_of(validation)
|
102
|
+
{:class => ''}
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# TODO: Resolve validation from validates_format_of.
|
107
|
+
#
|
108
|
+
# Note: Should be implemented using "Custom validators" - generated and attached to the form on render page.
|
109
|
+
#
|
110
|
+
def format_of(validation)
|
111
|
+
# format_expression = validation.options[:with]
|
112
|
+
# Old: {:class => validation.options.key?(:name) ? validation.options[:name] : ''}
|
113
|
+
{:class => ''}
|
114
|
+
end
|
115
|
+
|
116
|
+
#
|
117
|
+
# TODO: Resolve validation from validates_inclusion_of.
|
118
|
+
#
|
119
|
+
def inclusion_of(validation)
|
120
|
+
{:class => ''}
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# Resolve validation from validates_length_of.
|
125
|
+
#
|
126
|
+
def length_of(validation)
|
127
|
+
range = validation.options[:in] || validation.options[:within]
|
128
|
+
min, max = nil, nil
|
129
|
+
min, max = range.min, range.max if range
|
130
|
+
min ||= validation.options[:minimum] || validation.options[:is]
|
131
|
+
max ||= validation.options[:maximum] || validation.options[:is]
|
132
|
+
|
133
|
+
class_name = [
|
134
|
+
("min-length_#{min}" unless min.nil?),
|
135
|
+
("max-length_#{max}" unless max.nil?)
|
136
|
+
].compact.join(' ')
|
137
|
+
|
138
|
+
{:class => class_name}
|
139
|
+
end
|
140
|
+
|
141
|
+
#
|
142
|
+
# Resolve validation from validates_numericality_of.
|
143
|
+
#
|
144
|
+
def numericality_of(validation)
|
145
|
+
{:class => 'numeric'}
|
146
|
+
end
|
147
|
+
|
148
|
+
#
|
149
|
+
# Resolve validation from validates_presence_of.
|
150
|
+
#
|
151
|
+
# Note: acceptance_of <=> presence_of (for Validatious)
|
152
|
+
#
|
153
|
+
def presence_of(validation)
|
154
|
+
{:class => 'required'}
|
155
|
+
end
|
156
|
+
|
157
|
+
#
|
158
|
+
# TODO: Resolve validation from validates_uniqueness_of.
|
159
|
+
#
|
160
|
+
# Note: A bit tricky on the client-side - especially with many records.
|
161
|
+
#
|
162
|
+
def uniqueness_of(validation)
|
163
|
+
{:class => ''}
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
data/rails/init.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file loads up the in-memory database needed to run the tests, and adds a few
|
4
|
+
# convenience methods.
|
5
|
+
#
|
6
|
+
|
7
|
+
begin
|
8
|
+
require File.expand_path(File.join(File.dirname(__FILE__), *%w(.. .. .. .. config environment)))
|
9
|
+
rescue LoadError
|
10
|
+
require 'rubygems'
|
11
|
+
|
12
|
+
gem 'test-unit', '1.2.3'
|
13
|
+
gem 'activerecord', '>= 1.2.3'
|
14
|
+
gem 'actionpack', '>= 1.2.3'
|
15
|
+
gem 'sqlite3-ruby', '>= 1.2.0'
|
16
|
+
|
17
|
+
require 'test/unit'
|
18
|
+
require 'active_record'
|
19
|
+
require 'action_controller'
|
20
|
+
require 'action_controller'
|
21
|
+
require 'sqlite3'
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'acts_as_fu'
|
26
|
+
rescue LoadError
|
27
|
+
gem 'nakajima-acts_as_fu', '>= 0.0.5'
|
28
|
+
require 'acts_as_fu'
|
29
|
+
end
|
30
|
+
|
31
|
+
require 'validatious'
|
32
|
+
|
33
|
+
build_model :bogus_items do
|
34
|
+
string :url
|
35
|
+
string :name
|
36
|
+
string :email
|
37
|
+
string :num
|
38
|
+
string :num2
|
39
|
+
string :num3
|
40
|
+
|
41
|
+
text :body
|
42
|
+
boolean :signed
|
43
|
+
|
44
|
+
validates_presence_of :name, :body
|
45
|
+
validates_acceptance_of :signed
|
46
|
+
validates_format_of :url,
|
47
|
+
:with => /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i,
|
48
|
+
:name => 'url'
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# ValidationReflection seems to expect RAILS_ROOT to be defined, but it's not
|
53
|
+
# if it's tested outside of a Rails project. So, just set it to something random.
|
54
|
+
#
|
55
|
+
RAILS_ROOT = File.join(File.dirname(__FILE__)) unless defined?(RAILS_ROOT)
|
56
|
+
|
57
|
+
#
|
58
|
+
# Log file for testing only.
|
59
|
+
#
|
60
|
+
ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), 'debug.log'))
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper'))
|
3
|
+
|
4
|
+
module Test::Unit::Assertions
|
5
|
+
|
6
|
+
#
|
7
|
+
# Assert that a piece of HTML includes the class name.
|
8
|
+
#
|
9
|
+
def assert_has_class(class_name, html, message = nil)
|
10
|
+
classes = /class="([^"]*)"/.match(html)[1].split(" ")
|
11
|
+
full_message = build_message(message, "<?>\nexpected to include class(es) <?>.\n", html, class_name)
|
12
|
+
|
13
|
+
assert_block(full_message) do
|
14
|
+
class_name.split(" ").all? { |cname| classes.include?(cname) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class FormHelperTest < Test::Unit::TestCase
|
21
|
+
|
22
|
+
include ActionView::Helpers::FormHelper
|
23
|
+
|
24
|
+
def test_required_text_field
|
25
|
+
assert_has_class "required", text_field(:bogus_item, :name)
|
26
|
+
assert_has_class "required text", text_field(:bogus_item, :name, :class => "text")
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_required_password_field
|
30
|
+
assert_has_class "required", password_field(:bogus_item, :name)
|
31
|
+
assert_has_class "required text", password_field(:bogus_item, :name, :class => "text")
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_required_text_area
|
35
|
+
assert_has_class "required", text_field(:bogus_item, :body)
|
36
|
+
assert_has_class "required text", text_field(:bogus_item, :body, :class => "text")
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_required_check_box # a.k.a. "acceptance required"
|
40
|
+
assert_has_class "required", text_field(:bogus_item, :signed)
|
41
|
+
assert_has_class "required boolean", text_field(:bogus_item, :signed, :class => "boolean")
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_required_radio_button
|
45
|
+
# TODO
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_normal_label
|
49
|
+
assert_equal "<label for=\"bogus_item_name\">Name</label>", label(:bogus_item, :name)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_label_with_title
|
53
|
+
assert_equal "<label for=\"bogus_item_name\" title=\"craaazy\">Name</label>",
|
54
|
+
label(:bogus_item, :name, nil, :title => "craaazy")
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_label_without_title
|
58
|
+
assert_equal "<label for=\"bogus_item_name\" title=\"Name\">Your name</label>",
|
59
|
+
label(:bogus_item, :name, "Your name")
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper'))
|
3
|
+
|
4
|
+
class RailsValidationTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
include ActionView::Helpers::FormHelper
|
7
|
+
|
8
|
+
def test_acceptance_of
|
9
|
+
validation = Validatious::RailsValidation.presence_of(validation(:validates_acceptance_of))
|
10
|
+
assert_equal 'required', validation[:class]
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_associated
|
14
|
+
# TODO: not implemented
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_confirmation_of
|
18
|
+
# TODO: not implemented
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_exclusion_of
|
22
|
+
# TODO: not implemented
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_format_of
|
26
|
+
# pattern = /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i
|
27
|
+
# validation = Validatious::RailsValidation.format_of(validation(:validates_format_of, :with => pattern, :name => "email"))
|
28
|
+
# assert_equal 'email', validation[:class]
|
29
|
+
# TODO: Not fully supported really, should
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_inclusion_of
|
33
|
+
# TODO: not implemented
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_length_of_with_in
|
37
|
+
validation = Validatious::RailsValidation.length_of(validation(:validates_length_of, :in => 1..10))
|
38
|
+
assert_equal 'min-length_1 max-length_10', validation[:class]
|
39
|
+
|
40
|
+
validation = Validatious::RailsValidation.length_of(validation(:validates_length_of, :in => 1...10))
|
41
|
+
assert_equal 'min-length_1 max-length_9', validation[:class]
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_length_of_with_within
|
45
|
+
validation = Validatious::RailsValidation.length_of(validation(:validates_length_of, :within => 1..10))
|
46
|
+
assert_equal 'min-length_1 max-length_10', validation[:class]
|
47
|
+
|
48
|
+
validation = Validatious::RailsValidation.length_of(validation(:validates_length_of, :within => 1...10))
|
49
|
+
assert_equal 'min-length_1 max-length_9', validation[:class]
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_length_of_with_minimum
|
53
|
+
validation = Validatious::RailsValidation.length_of(validation(:validates_length_of, :minimum => 1))
|
54
|
+
assert_equal 'min-length_1', validation[:class]
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_length_of_with_maximum
|
58
|
+
validation = Validatious::RailsValidation.length_of(validation(:validates_length_of, :maximum => 1))
|
59
|
+
assert_equal 'max-length_1', validation[:class]
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_length_of_with_min_and_max
|
63
|
+
validation = Validatious::RailsValidation.length_of(validation(:validates_length_of, :minimum => 1, :maximum => 3))
|
64
|
+
assert_equal 'min-length_1 max-length_3', validation[:class]
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_numericality_of
|
68
|
+
validation = Validatious::RailsValidation.numericality_of(validation(:validates_numericality_of))
|
69
|
+
assert_equal 'numeric', validation[:class]
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_presence_of
|
73
|
+
validation = Validatious::RailsValidation.presence_of(validation(:validates_presence_of))
|
74
|
+
assert_equal 'required', validation[:class]
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_uniqueness_of
|
78
|
+
# TODO: not implemented
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# Simulate a validation
|
83
|
+
#
|
84
|
+
def validation(macro, options = {})
|
85
|
+
ActiveRecord::Reflection::MacroReflection.new(macro, :name, options, nil)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: grimen-validatious-on-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christian Johansen
|
8
|
+
- Jonas Grimfelt
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-09-27 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: Rails plugin that maps model validations to class names on form elements to integrate with Validatious.
|
18
|
+
email: christian@cjohansen.no
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- Rakefile
|
25
|
+
- generators/validatious/templates/v2.standalone.full.min.js
|
26
|
+
- generators/validatious/templates/validatious.config.js
|
27
|
+
- generators/validatious/validatious_generator.rb
|
28
|
+
- lib/validatious.rb
|
29
|
+
- lib/validatious/form_helper.rb
|
30
|
+
- lib/validatious/rails_validation.rb
|
31
|
+
- rails/init.rb
|
32
|
+
- test/test_helper.rb
|
33
|
+
- test/validatious/form_helper_test.rb
|
34
|
+
- test/validatious/rails_validation_test.rb
|
35
|
+
- test/validatious_test.rb
|
36
|
+
files:
|
37
|
+
- Rakefile
|
38
|
+
- generators/validatious/templates/v2.standalone.full.min.js
|
39
|
+
- generators/validatious/templates/validatious.config.js
|
40
|
+
- generators/validatious/validatious_generator.rb
|
41
|
+
- lib/validatious.rb
|
42
|
+
- lib/validatious/form_helper.rb
|
43
|
+
- lib/validatious/rails_validation.rb
|
44
|
+
- rails/init.rb
|
45
|
+
- test/test_helper.rb
|
46
|
+
- test/validatious/form_helper_test.rb
|
47
|
+
- test/validatious/rails_validation_test.rb
|
48
|
+
- test/validatious_test.rb
|
49
|
+
has_rdoc: false
|
50
|
+
homepage: http://github.com/grimen/validatious-on-rails
|
51
|
+
licenses:
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options:
|
54
|
+
- --charset=UTF-8
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
version:
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.3.5
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Rails plugin that maps model validations to class names on form elements to integrate with Validatious.
|
76
|
+
test_files:
|
77
|
+
- test/test_helper.rb
|
78
|
+
- test/validatious/form_helper_test.rb
|
79
|
+
- test/validatious/rails_validation_test.rb
|
80
|
+
- test/validatious_test.rb
|