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

Handle classes within Node #92

Merged
merged 7 commits into from
Oct 6, 2023

Conversation

Kiyoshika
Copy link
Member

@Kiyoshika Kiyoshika commented Oct 3, 2023

This PR introduces utility methods to work with class names within a node according to this issue and this discussion. This will be useful for user agents / renderers to check which/if classes need to be applied to a given element and will also be used in a future PR for querying the DOM by class name.

Note that I am not doing any "error handling" in ElementClass since this mimics the behaviour when using javascript.

For instance, if you try

var element = document.getElementById("myDIV");
element.classList.toggle("mystyle");

on a class that doesn't exist, it will essentially do nothing (at least, from the end user's perspective.) I'm not sure if it's worth it to throw an actual error if trying to remove/edit a class that doesn't exist, so for now they are silent (but intentional) errors.

From the parser, when a new node is created & added to the document, we check if a class attribute exists and take its string which is split on whitespace (extra whitespaces are ignored) and an ElementClass struct is created to hold the classes which is stored inside the Node struct. We can then toggle/add/remove classes from the node using the interface provided.

EDIT: this also simplifies the Node::get_attribute and Node::get_mut_attribute methods to return an Option instead of a Result<Option>. Even though this is an unrelated change, I don't think it was worth creating an entirely separate PR for this and snuck it into this one

@Kiyoshika
Copy link
Member Author

I just realised I pulled off of my outdated main (hence the conflict), going to rebase before continuing

@Kiyoshika
Copy link
Member Author

re-synced fork, added some starter tests but didn't have much time today to work on it, hopefully can make more progress tomorrow

didn't have time to really work on this today, just some small fixes
TODO: integrate new struct into Node struct
Got classes added when node is created from parser, but need to do some cleanup such as removing the unwraps() and adding some tests in the node itself. But ran out of time and need to head out to dinner with some people
We should now have a usable API for handling classes (at least, the bare minimum) for element nodes
@Kiyoshika Kiyoshika marked this pull request as ready for review October 5, 2023 03:28
@Kiyoshika
Copy link
Member Author

PR finished and ready to review


/// Count the number of classes (active or inactive)
/// assigned to an element
pub fn count(&self) -> usize {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't it be better to stick with the Rust style here and use len as the method name? Especially because there is an is_empty method, which gets suggested by clippy when doing any comparison to zero, e.g. list.len() == 0.

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, good suggestion. i'm still not entirely familiar with all of Rust's conventions yet. Will fix now

Copy link
Member Author

Choose a reason for hiding this comment

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

updated in 98e6130

}

let mut value: Option<&String> = None;
if let NodeData::Element { attributes, .. } = &self.data {
value = attributes.get(name);
}

Ok(value)
value
Copy link
Collaborator

Choose a reason for hiding this comment

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

We'll have to keep our eye on whether there are error cases in CSS that need to be handled. But this change feels like a good next step. I'm thinking we can backfill error handling when we discover that it's needed.

// however, map.insert will update a key if it exists
// and we don't want to overwrite an inactive class to make it active unintentionally
// so we ignore this operation if the class already exists
if !self.contains(name) {
Copy link
Collaborator

@emwalker emwalker Oct 5, 2023

Choose a reason for hiding this comment

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

Probably want to keep an eye on this kind of substring matching. Might be fine indefinitely, or might cause problems later on.

I see we're using a HashMap.

let mut parser = Html5Parser::new(&mut stream);
let (doc, _) = parser.parse();

assert_eq!(doc.get_root().classes.is_none(), true);
Copy link
Collaborator

@emwalker emwalker Oct 5, 2023

Choose a reason for hiding this comment

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

This and elsewhere would be

assert!(doc.get_root().classes.is_none());

I wonder whether you would get this automatically by running cargo clippy --fix.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll add the suggestions this and others, although cargo clippy --fix doesn't complain about anything for me (cargo 1.72.1, MacOS 13.5)

Copy link
Member Author

Choose a reason for hiding this comment

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

Although going forward for boolean tests I will just use assert!

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, now I understand how it works, it just made the changes for me


assert_eq!(classes.is_active("one"), true);
assert_eq!(classes.is_active("two"), true);
assert_eq!(classes.is_active("three"), true);
Copy link
Collaborator

Choose a reason for hiding this comment

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

See comment above.

Copy link
Collaborator

@emwalker emwalker left a comment

Choose a reason for hiding this comment

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

LGTM with suggestions

this also adjusted others outside of my code changes but it's probably better to stay consistent
@Kiyoshika
Copy link
Member Author

@emwalker I ran clippy fix which also adjusted some assertions outside my original changes but thought it's probably best to stay consistent. I'll get your final sign off before merging

@emwalker
Copy link
Collaborator

emwalker commented Oct 6, 2023

@Kiyoshika I'm thinking you have the ability to merge when you're ready. Let me know if you don't.

@emwalker
Copy link
Collaborator

emwalker commented Oct 6, 2023

Looks like our PRs overlapped, so there's a conflict you'll have to fix.

@Kiyoshika Kiyoshika merged commit 5781a42 into gosub-io:main Oct 6, 2023
4 checks passed
@Kiyoshika Kiyoshika deleted the feat/handle-node-classes branch October 6, 2023 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants