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};