use vize_atelier_core::{DirectiveNode, ElementNode, RuntimeHelper};
use vize_carton::{String, cstr};
#[derive(Debug, Default, Clone)]
pub struct VModelModifiers {
pub lazy: bool,
pub number: bool,
pub trim: bool,
}
impl VModelModifiers {
pub fn from_directive(dir: &DirectiveNode<'_>) -> Self {
let mut modifiers = Self::default();
for modifier in dir.modifiers.iter() {
match modifier.content.as_str() {
"lazy" => modifiers.lazy = true,
"number" => modifiers.number = true,
"trim" => modifiers.trim = true,
_ => {}
}
}
modifiers
}
}
pub fn get_model_helper(tag: &str, input_type: Option<&str>) -> RuntimeHelper {
match tag {
"select" => RuntimeHelper::CreateElementVNode,
"textarea" => RuntimeHelper::CreateElementVNode,
"input" => {
if let Some(t) = input_type {
match t {
"checkbox" | "radio" => RuntimeHelper::CreateElementVNode,
_ => RuntimeHelper::CreateElementVNode,
}
} else {
RuntimeHelper::CreateElementVNode
}
}
_ => RuntimeHelper::CreateElementVNode,
}
}
pub fn get_model_event(tag: &str, modifiers: &VModelModifiers) -> &'static str {
match tag {
"select" => "change",
"textarea" => {
if modifiers.lazy {
"change"
} else {
"input"
}
}
"input" => {
if modifiers.lazy {
"change"
} else {
"input"
}
}
_ => "input",
}
}
pub fn get_model_prop(tag: &str, input_type: Option<&str>) -> &'static str {
match tag {
"input" => {
if let Some(t) = input_type {
match t {
"checkbox" => "checked",
"radio" => "checked",
_ => "value",
}
} else {
"value"
}
}
_ => "value",
}
}
pub fn generate_model_props(
_element: &ElementNode<'_>,
dir: &DirectiveNode<'_>,
) -> Vec<(String, String)> {
let modifiers = VModelModifiers::from_directive(dir);
let mut props = Vec::new();
if let Some(ref exp) = dir.exp
&& let vize_atelier_core::ExpressionNode::Simple(simple) = exp
{
let model_value = simple.content.clone();
props.push((String::from("value"), model_value.clone()));
let mut handler = cstr!("$event => (({model_value}) = $event.target.value)");
if modifiers.trim {
handler = cstr!("$event => (({model_value}) = $event.target.value.trim())");
}
if modifiers.number {
handler = cstr!("$event => (({model_value}) = Number($event.target.value))");
}
let event_name = if modifiers.lazy {
"onChange"
} else {
"onInput"
};
props.push((String::from(event_name), handler));
}
props
}
#[cfg(test)]
mod tests {
use super::{VModelModifiers, generate_model_props, get_model_event, get_model_prop};
#[test]
fn test_modifiers() {
let modifiers = VModelModifiers {
lazy: true,
number: false,
trim: true,
};
assert!(modifiers.lazy);
assert!(modifiers.trim);
assert!(!modifiers.number);
}
#[test]
fn test_model_event() {
let default_mods = VModelModifiers::default();
let lazy_mods = VModelModifiers {
lazy: true,
..Default::default()
};
assert_eq!(get_model_event("input", &default_mods), "input");
assert_eq!(get_model_event("input", &lazy_mods), "change");
assert_eq!(get_model_event("select", &default_mods), "change");
}
#[test]
fn test_model_prop() {
assert_eq!(get_model_prop("input", None), "value");
assert_eq!(get_model_prop("input", Some("text")), "value");
assert_eq!(get_model_prop("input", Some("checkbox")), "checked");
assert_eq!(get_model_prop("input", Some("radio")), "checked");
assert_eq!(get_model_prop("textarea", None), "value");
}
#[test]
fn test_textarea_event() {
let default_mods = VModelModifiers::default();
let lazy_mods = VModelModifiers {
lazy: true,
..Default::default()
};
assert_eq!(get_model_event("textarea", &default_mods), "input");
assert_eq!(get_model_event("textarea", &lazy_mods), "change");
}
#[test]
fn test_select_prop() {
assert_eq!(get_model_prop("select", None), "value");
}
#[test]
fn test_generate_model_props_basic() {
use vize_atelier_core::{
ElementNode, ExpressionNode, SimpleExpressionNode, SourceLocation,
};
use vize_carton::{Box, Bump};
let allocator = Bump::new();
let element = ElementNode::new(&allocator, "input", SourceLocation::STUB);
let mut dir =
vize_atelier_core::DirectiveNode::new(&allocator, "model", SourceLocation::STUB);
let exp_node = SimpleExpressionNode::new("modelValue", false, SourceLocation::STUB);
let boxed = Box::new_in(exp_node, &allocator);
dir.exp = Some(ExpressionNode::Simple(boxed));
let props = generate_model_props(&element, &dir);
assert_eq!(props.len(), 2);
assert_eq!(props[0].0.as_str(), "value");
assert_eq!(props[0].1.as_str(), "modelValue");
assert_eq!(props[1].0.as_str(), "onInput");
insta::assert_debug_snapshot!(props);
}
#[test]
fn test_generate_model_props_lazy() {
use vize_atelier_core::{
ElementNode, ExpressionNode, SimpleExpressionNode, SourceLocation,
};
use vize_carton::{Box, Bump};
let allocator = Bump::new();
let element = ElementNode::new(&allocator, "input", SourceLocation::STUB);
let mut dir =
vize_atelier_core::DirectiveNode::new(&allocator, "model", SourceLocation::STUB);
let exp_node = SimpleExpressionNode::new("msg", false, SourceLocation::STUB);
let boxed = Box::new_in(exp_node, &allocator);
dir.exp = Some(ExpressionNode::Simple(boxed));
let lazy_mod = SimpleExpressionNode::new("lazy", true, SourceLocation::STUB);
dir.modifiers.push(lazy_mod);
let props = generate_model_props(&element, &dir);
assert_eq!(props[1].0.as_str(), "onChange");
}
}