Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handling of boolean attributes #840

Merged
merged 5 commits into from
Jan 6, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions crates/macro/src/html_tree/html_tag/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ impl ToTokens for HtmlTag {
let TagAttributes {
classes,
attributes,
booleans,
kind,
value,
checked,
disabled,
selected,
node_ref,
href,
Expand All @@ -106,6 +106,14 @@ impl ToTokens for HtmlTag {
let label_str = label.to_string();
quote_spanned! {value.span() => (#label_str.to_owned(), (#value).to_string()) }
});
let set_booleans = booleans.iter().map(|TagAttribute { label, value }| {
let label_str = label.to_string();
quote_spanned! {value.span() =>
if #value {
#vtag.add_attribute(&#label_str, &#label_str);
}
}
});
let set_kind = kind.iter().map(|kind| {
quote_spanned! {kind.span()=> #vtag.set_kind(&(#kind)); }
});
Expand All @@ -121,13 +129,6 @@ impl ToTokens for HtmlTag {
let set_checked = checked.iter().map(|checked| {
quote_spanned! {checked.span()=> #vtag.set_checked(#checked); }
});
let add_disabled = disabled.iter().map(|disabled| {
quote_spanned! {disabled.span()=>
if #disabled {
#vtag.add_attribute("disabled", &"true");
}
}
});
let add_selected = selected.iter().map(|selected| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need special handling for selected with your change. Can you please remove the special handling and ensure that selected works properly as a boolean attribute?

quote_spanned! {selected.span()=>
if #selected {
Expand Down Expand Up @@ -167,7 +168,7 @@ impl ToTokens for HtmlTag {
#(#set_value)*
#(#add_href)*
#(#set_checked)*
#(#add_disabled)*
#(#set_booleans)*
#(#add_selected)*
#(#set_classes)*
#(#set_node_ref)*
Expand Down
67 changes: 64 additions & 3 deletions crates/macro/src/html_tree/html_tag/tag_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ pub struct TagAttributes {
pub attributes: Vec<TagAttribute>,
pub listeners: Vec<TagAttribute>,
pub classes: Option<ClassesForm>,
pub booleans: Vec<TagAttribute>,
pub value: Option<Expr>,
pub kind: Option<Expr>,
pub checked: Option<Expr>,
pub disabled: Option<Expr>,
pub selected: Option<Expr>,
pub node_ref: Option<Expr>,
pub href: Option<Expr>,
Expand All @@ -24,6 +24,53 @@ pub enum ClassesForm {
Single(Expr),
}

lazy_static! {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add a comment saying what the source of this list is?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this list is not totally correct, see this comment: https://gist.github.com/ArjanSchouten/0b8574a6ad7f5065a5e7#gistcomment-2717606

static ref BOOLEAN_SET: HashSet<&'static str> = {
HashSet::from_iter(
vec![
"async",
"autocomplete",
"autofocus",
"autoplay",
"border",
"challenge",
"checked",
"compact",
"contenteditable",
"controls",
"default",
"defer",
"disabled",
"formNoValidate",
"frameborder",
"hidden",
"indeterminate",
"ismap",
"loop",
"multiple",
"muted",
"nohref",
"noresize",
"noshade",
"novalidate",
"nowrap",
"open",
"readonly",
"required",
"reversed",
"scoped",
"scrolling",
"seamless",
"selected",
"sortable",
"spellcheck",
"translate",
]
.into_iter(),
)
};
}

lazy_static! {
static ref LISTENER_SET: HashSet<&'static str> = {
HashSet::from_iter(
Expand Down Expand Up @@ -92,6 +139,20 @@ impl TagAttributes {
drained
}

fn drain_boolean(attrs: &mut Vec<TagAttribute>) -> Vec<TagAttribute> {
let mut i = 0;
let mut drained = Vec::new();
while i < attrs.len() {
let name_str = attrs[i].label.to_string();
if BOOLEAN_SET.contains(&name_str.as_str()) {
drained.push(attrs.remove(i));
} else {
i += 1;
}
}
drained
}

fn remove_attr(attrs: &mut Vec<TagAttribute>, name: &str) -> Option<Expr> {
let mut i = 0;
while i < attrs.len() {
Expand Down Expand Up @@ -142,13 +203,13 @@ impl Parse for TagAttributes {
}
i += 1;
}
let booleans = TagAttributes::drain_boolean(&mut attributes);

let classes =
TagAttributes::remove_attr(&mut attributes, "class").map(TagAttributes::map_classes);
let value = TagAttributes::remove_attr(&mut attributes, "value");
let kind = TagAttributes::remove_attr(&mut attributes, "type");
let checked = TagAttributes::remove_attr(&mut attributes, "checked");
let disabled = TagAttributes::remove_attr(&mut attributes, "disabled");
let selected = TagAttributes::remove_attr(&mut attributes, "selected");
let node_ref = TagAttributes::remove_attr(&mut attributes, "ref");
let href = TagAttributes::remove_attr(&mut attributes, "href");
Expand All @@ -157,10 +218,10 @@ impl Parse for TagAttributes {
attributes,
classes,
listeners,
booleans,
value,
kind,
checked,
disabled,
selected,
node_ref,
href,
Expand Down