1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
//! Library to validate and generate HTML forms. //! //! ```rust //! use es_htmlform::{HtmlForm, FormError, ValidationError}; //! use es_htmlform::value::ValueMap; //! use es_htmlform::types::{InputType, Method, Constraint as Cons, Attr}; //! //! // simple form with 1 field //! fn searchform() -> Result<HtmlForm<'static>, FormError> { //! Ok(HtmlForm::new(".", Method::Get) //! .input( //! InputType::Text, "q", "Search", true, //! vec![], vec![Attr::Placeholder("enter query")])? //! .submit(None, "go!", vec![])?) //! } //! //! // more elaborate example, with validation (both client- and //! // server-side) and custom attributes //! fn userform() -> Result<HtmlForm<'static>, FormError> { //! Ok(HtmlForm::new(".", Method::Post) //! .input( //! InputType::Text, "username", "Username", true, //! vec![ //! Cons::MinLength(5), Cons::MaxLength(16), //! Cons::Pattern(r"^\w+$")], //! vec![])? //! .input( //! InputType::Text, "name", "Full name", true, //! vec![Cons::MinLength(0), Cons::MaxLength(64)], vec![])? //! .input( //! InputType::Password, "password", "Password", true, //! vec![ //! Cons::MinLength(6), Cons::MaxLength(64), //! Cons::Pattern(r"(\d.*[^\w\s\d]|[^\w\s\d].*\d)"), //! ], //! vec![Attr::Title( //! "Must contain 1 number and 1 non-word character")])? //! .input( //! InputType::Number, "age", "Age", true, //! vec![Cons::MinNumber(18.0)], //! vec![Attr::StepInt(1), Attr::Any("id", "age")])? //! .textarea("message", "Message", false, vec![], vec![])? //! .hidden( //! "csrf", Some("foo"), true, //! vec![Cons::Func(Box::new(|v| { //! if v.as_string().as_str() != "foo" { //! Err(ValidationError::new("invalid CSRF token")) //! } else { //! Ok(()) //! } //! }))], //! vec![])? //! .submit(None, "Submit", vec![])? //! ) //! } //! //! fn main() { //! let values = ValueMap::from_urlencoded(b"q=foo").unwrap(); //! let mut form = searchform().unwrap(); //! form.update(&values, true); //! //! println!("{}", serde_json::to_string_pretty(&form).unwrap()); //! assert_eq!(form.errors.len(), 0); //! assert_eq!(form.get_string("q").unwrap(), "foo"); //! assert_eq!( //! serde_json::to_string_pretty(&form).unwrap(), //! r#"{ //! "action": ".", //! "method": "get", //! "errors": {}, //! "fields": [ //! { //! "name": "q", //! "label": "Search", //! "element": "input", //! "type": "text", //! "required": true, //! "multi": false, //! "choices": [], //! "attributes": { //! "placeholder": "enter query" //! }, //! "value": "foo" //! }, //! { //! "name": "", //! "label": "go!", //! "element": "input", //! "type": "submit", //! "required": false, //! "multi": false, //! "choices": [], //! "attributes": {}, //! "value": "" //! } //! ] //! }"#); //! //! let values = ValueMap::from_urlencoded( //! b"username=johnny&name=Johnny&password=foobar-123&age=46&csrf=bar" //! ).unwrap(); //! let mut form = userform().unwrap(); //! form.update(&values, true); //! //! assert_eq!(form.errors.len(), 1); //! assert_eq!( //! form.errors.get("csrf").unwrap(), "invalid CSRF token"); //! assert_eq!(form.get_string("username").unwrap(), "johnny"); //! assert_eq!(form.get_string("password").unwrap(), "foobar-123"); //! assert_eq!(form.get_string("csrf").unwrap(), "bar"); //! } //! ``` mod error; mod htmlform; pub mod value; pub mod types; mod serde; pub use crate::error::{FormError, ValidationError}; pub use crate::htmlform::{HtmlForm, Field};