Skip to content

Commit bbf7b3a

Browse files
committed
browser-rs: add attributes to DOM tree
1 parent 96cd40a commit bbf7b3a

File tree

3 files changed

+110
-9
lines changed

3 files changed

+110
-9
lines changed

app/browser-rs/src/renderer/dom.rs

+72-7
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,20 @@ pub enum NodeKind {
6767
/// https://dom.spec.whatwg.org/#interface-element
6868
pub struct Element {
6969
kind: ElementKind,
70-
//id: String,
71-
//class_name: String,
70+
attributes: Vec<Attribute>,
7271
}
7372

7473
impl Element {
7574
pub fn new(kind: ElementKind) -> Self {
7675
Self {
7776
kind,
78-
//id: String::new(),
79-
//class_name: String::new(),
77+
attributes: Vec::new(),
8078
}
8179
}
80+
81+
pub fn set_attribute(&mut self, name: String, value: String) {
82+
self.attributes.push(Attribute::new(name, value));
83+
}
8284
}
8385

8486
#[allow(dead_code)]
@@ -89,6 +91,8 @@ pub enum ElementKind {
8991
Html,
9092
/// https://html.spec.whatwg.org/multipage/semantics.html#the-head-element
9193
Head,
94+
/// https://html.spec.whatwg.org/multipage/semantics.html#the-link-element
95+
Link,
9296
/// https://html.spec.whatwg.org/multipage/sections.html#the-body-element
9397
Body,
9498
/// https://html.spec.whatwg.org/multipage/grouping-content.html#the-ul-element
@@ -97,6 +101,20 @@ pub enum ElementKind {
97101
Li,
98102
}
99103

104+
#[allow(dead_code)]
105+
#[derive(Debug, Clone, PartialEq, Eq)]
106+
/// https://dom.spec.whatwg.org/#attr
107+
pub struct Attribute {
108+
name: String,
109+
value: String,
110+
}
111+
112+
impl Attribute {
113+
pub fn new(name: String, value: String) -> Self {
114+
Self { name, value }
115+
}
116+
}
117+
100118
#[allow(dead_code)]
101119
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
102120
pub enum InsertionMode {
@@ -147,6 +165,8 @@ impl Parser {
147165
return self.create_element(ElementKind::Html);
148166
} else if tag == "head" {
149167
return self.create_element(ElementKind::Head);
168+
} else if tag == "link" {
169+
return self.create_element(ElementKind::Link);
150170
} else if tag == "body" {
151171
return self.create_element(ElementKind::Body);
152172
} else if tag == "ul" {
@@ -241,19 +261,45 @@ impl Parser {
241261
self.stack_of_open_elements.push(node);
242262
}
243263

264+
/// Sets an attribute to the current node.
265+
fn set_attribute_to_current_node(&mut self, name: String, value: String) {
266+
let current = match self.stack_of_open_elements.last() {
267+
Some(n) => n,
268+
None => &self.root,
269+
};
270+
271+
match current.borrow_mut().kind {
272+
NodeKind::Element(ref mut elem) => {
273+
elem.set_attribute(name, value);
274+
return;
275+
}
276+
_ => {}
277+
}
278+
}
279+
244280
/// Returns true if the current node's kind is same as NodeKind::Element::<element_kind>.
245281
fn pop_current_node(&mut self, element_kind: ElementKind) -> bool {
246282
let current = match self.stack_of_open_elements.last() {
247283
Some(n) => n,
248284
None => return false,
249285
};
250286

251-
if current.borrow().kind == NodeKind::Element(Element::new(element_kind)) {
287+
let ok = match current.borrow().kind {
288+
NodeKind::Element(ref elem) => {
289+
if elem.kind == element_kind {
290+
true
291+
} else {
292+
false
293+
}
294+
}
295+
_ => false,
296+
};
297+
298+
if ok {
252299
self.stack_of_open_elements.pop();
253-
return true;
254300
}
255301

256-
false
302+
ok
257303
}
258304

259305
/// Pops nodes until a node with `element_kind` comes.
@@ -392,6 +438,25 @@ impl Parser {
392438
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inhead
393439
InsertionMode::InHead => {
394440
match token {
441+
Some(Token::StartTag {
442+
ref tag,
443+
self_closing: _,
444+
ref attributes,
445+
}) => {
446+
if tag == "link" {
447+
self.insert_element("link");
448+
for attr in attributes {
449+
self.set_attribute_to_current_node(
450+
attr.name.clone(),
451+
attr.value.clone(),
452+
);
453+
}
454+
// Immediately pop the current node off the stack of open elements.
455+
assert!(self.pop_current_node(ElementKind::Link));
456+
token = self.t.next();
457+
continue;
458+
}
459+
}
395460
Some(Token::EndTag {
396461
ref tag,
397462
self_closing: _,

app/browser-rs/src/renderer/tokenizer.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ pub enum Token {
5757

5858
#[derive(Debug, Clone, PartialEq, Eq)]
5959
pub struct Attribute {
60-
name: String,
61-
value: String,
60+
pub name: String,
61+
pub value: String,
6262
}
6363

6464
impl Attribute {

app/browser-rs/tests/dom.rs

+36
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
extern crate alloc;
88

9+
use crate::alloc::string::ToString;
910
use alloc::rc::Rc;
1011
use alloc::string::String;
1112
use core::cell::RefCell;
@@ -375,3 +376,38 @@ fn list2() {
375376

376377
run_test!("<html><head></head><body><ul><li></li><li></li></ul><ul><li></li><li></li></ul></body></html>", Some(root));
377378
}
379+
380+
#[test_case]
381+
fn list() {
382+
// root (Document)
383+
// └── html
384+
// └── head
385+
// └── link
386+
// └── body
387+
let root = create_base_dom_tree();
388+
let head = root
389+
.borrow_mut()
390+
.first_child()
391+
.unwrap()
392+
.borrow_mut()
393+
.first_child()
394+
.unwrap();
395+
let mut link_element = Element::new(ElementKind::Link);
396+
link_element.set_attribute("rel".to_string(), "stylesheet".to_string());
397+
link_element.set_attribute("href".to_string(), "styles.css".to_string());
398+
399+
let link = Rc::new(RefCell::new(Node::new(NodeKind::Element(link_element))));
400+
401+
// head <--> link
402+
{
403+
head.borrow_mut().first_child = Some(link.clone());
404+
}
405+
{
406+
link.borrow_mut().parent = Some(Rc::downgrade(&head));
407+
}
408+
409+
run_test!(
410+
"<html><head><link rel='stylesheet' href=\"styles.css\"></head></html>",
411+
Some(root)
412+
);
413+
}

0 commit comments

Comments
 (0)