Skip to content

Instantly share code, notes, and snippets.

@drewlesueur
Created May 22, 2010 07:54
Show Gist options
  • Save drewlesueur/409898 to your computer and use it in GitHub Desktop.
Save drewlesueur/409898 to your computer and use it in GitHub Desktop.
Readable Validator
<!doctype>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script src="jquery.readable-validator.js"></script>
<script>
$(document).ready(function(){
$('form').readable_validator({
labels: {
"Name" : "name",
"Phone" : "phone",
"Twitter" : "twitter"
},
ruleSelector: "#rules",
outputSelector: "#errors"
}).css('font-family', 'courier');
})
</script>
</head>
<body>
<div id="errors"></div>
<form>
name<input type="text" id="name" name="name">
<br>
phone<input type="text" id="phone" name="phone">
<br>
twitter<input type="text" id="twitter" name="twitter">
<br>
Like Programming? <input type="radio" name="like" id="like_yes" value="1"><input type="radio" name="like" id="like_no" value="0">
<br>
<input type="submit" value="submit">
</form>
<textarea id="rules" style="display:none;">
"Name" is "Drew"
//"Name" is required
//or
//"Name" must be filled in
If "Twitter" is "drewlesueur" then say "drew, sorry you can't register"
"Phone" must be a date if "Twitter" is "kylelesueur"
//If "Twitter" is filled in then "Name" must be "hello" //not working yet
If "Twitter" is filled in then say "twitter is filled in"
If "Phone" is empty then "Twitter" must be filled in
</textarea>
</body>
(function($) {
function tokenize(line) {
line = line.split("");
i = 0;
var state = "out";
var cur_token = []
var tokens = [];
var last_chr = "";
while (i < line.length) {
chr = line[i];
if (chr == " " && state == "out") {
tokens.push(cur_token.join(""))
cur_token = []
} else if (chr == '"' && state == "out") {
state = "in";
cur_token.push("'")
} else if (chr == '"' && state == "in" && last_chr != "\\") {
state = "out";
} else if (chr.match(/:/) && state == "out") {
tokens.push(cur_token.join(""))
tokens.push(chr)
cur_token = []
} else {
cur_token.push(chr)
}
last_chr = chr;
i++
}
if (cur_token.length > 0) {
tokens.push(cur_token.join(""))
}
return tokens
}
function array_split(splitter, arr) {
var ret = []
var cur = []
var word;
for (var i in arr) {
word = arr[i];
if (word == splitter) {
if (cur.length > 0) {
ret.push(cur)
}
cur = []
} else {
cur.push(word)
}
}
if (cur.length > 0) {
ret.push(cur)
}
return ret;
}
//counting keys in an object
function count(foo) {
var count = 0;
for (var k in foo) {
if (foo.hasOwnProperty(k) && k != "toJSON") {
++count;
}
}
return count;
}
function _s(val, start, end) {
var need_to_join = false;
var ret = []
if (typeof val == "string") {
val = val.split("")
need_to_join = true;
}
if (start >= 0) {
} else {
start = val.length + start
}
if (end == null) {
ret = val.slice(start)
} else {
if (end < 0) {
end = val.length + end;
} else {
end = end + start
}
ret = val.slice(start, end)
}
if (need_to_join) {
return ret.join("")
} else {
return ret;
}
}
function required(value, label, field) {
if (value != "") {
return true;
} else {
var ret = {}
ret[field] = label + " is required";
return ret;
}
}
var validators = {
"required" : required,
"filled_in" : required,
a_date: function(x, label, field) {
if (x.match(/[\d]{2}\/[\d]{2}\/[\d]{4}/)) {
return true;
} else {
var ret = {}
ret[field] = label + " must be in the format mm/dd/yyyy";
return ret;
}
}
}
$.fn.readable_validator = function(settings) {
var config = {
"alternateValues" : {},
"lables" : {},
"validators" : validators,
"ruleSelector" : "",
"outputSelector" : ""
};
if (settings) $.extend(true, config, settings); //deep extend
this.each(function() {
$(this).submit(function(e){
var raw = $(this).serializeArray()
var fields = {}
for (var i in raw) {
fields[raw[i]['name']] = raw[i]['value']
}
var label_values = config.labels
var alter_values = config.alternateValues
var validators = config.validators
var rules = $(config.ruleSelector).html().split("\n");
var rule;
var errors = {};
var error_i = 0;
function validate(rule) {
rule = $.trim(rule);
if (_s(rule,-1) == ".") {
rule = _s(rule,0,-1);
}
rule = tokenize(rule)
function handle_expression(expr) {
var field = expr[0]
if (field == "say") {
error_i = error_i + 1;
var ret = {}
ret[error_i] = _s(expr[1],1)
return ret;
}
var operation = _s(expr,1,1)
var next_one = 2;
if (operation == "must") {
next_one = 3
operation = operation + " " + _s(expr,2,1);
}
var value = _s(expr, next_one).join(" ");
label = _s(field,1)
field = label_values[label];
if (_s(value,0,1) == "'") {
operation = operation + " literal";
value = _s(value, 1);
if (field in alter_values) {
value = alter_values[field](value);
}
}
if (operation == "must be") {
operation = "is";
}
real_value = fields[field];
if (operation == "is literal") {
console.log(value + "_", real_value + "_", operation + "-")
var ret = real_value == value;
return ret
} else if (operation == "isn't literal") {
var ret = real_value != value;
return ret;
} else if (operation == "is") {
value = value.replace(/ /g,"_");
if (value in validators) {
return validators[value](real_value, label, field);
} else {
return false;
}
} else if (operation == "isn't") {
value = value.replace(/ /g,"_");
if (value in validators) {
return validators[value](real_value, label, field);
} else {
return false;
}
}
}
function handle_if() {
rule = rule.slice(1)
rule = array_split("then", rule);
var left = rule[0];
var right = rule[1];
left = array_split("and", left);
right = array_split("and", right);
for (var i in left) {
var ret = true;
var expr = left[i]
if (expr == "true") {
break;
}
var handled_expression = handle_expression(expr);
if (handled_expression !== true) {
handled_expression = false;
}
ret = ret && handled_expression
if (ret == false) {
break;
}
}
if (ret == true) {
for (var i in right) {
var expr = right[i];
var ret = handle_expression(expr);
if (ret != true) {
for (var i in ret) {
errors[i] = ret[i]
}
}
}
} else {
//alert('good')
}
}
if (rule[0] == "If") {
handle_if();
} else {
var first = rule[0];
if (!first) {
return;
}
if (_s(first,0,2) == "//") {
return
}
rule = array_split("if", rule)
if (rule.length == 1) {
rule = rule[0];
rule.splice(0,0, "if", "true", "then");
handle_if();
} else { // "Packet Sent Date" is required if "something" is a date
new_rule = ["If"]
for (var i in rule[1]) {
new_rule.push(rule[1][i])
}
new_rule.push('then')
for (var i in rule[0]) {
new_rule.push(rule[0][i])
}
rule = new_rule;
handle_if();
}
}
}
for (var i in rules) {
rule = rules[i]
validate(rule)
}
if (count(errors) > 0) {
$(config.outputSelector).empty()
for (var i in errors) {
if (i == "toJSON") {
continue;
}
$(config.outputSelector).append("<di"+"v>"+errors[i]+"<"+"/d"+"iv>")
window.scroll(0,0)
}
e.preventDefault();
} else {
}
})
});
return this;
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment