2020-08-09 05:13:34 +03:00
|
|
|
module html
|
|
|
|
|
2020-12-09 22:08:15 +03:00
|
|
|
import strings
|
2023-01-18 20:00:46 +03:00
|
|
|
import datatypes
|
2020-12-09 22:08:15 +03:00
|
|
|
|
2020-08-09 05:13:34 +03:00
|
|
|
enum CloseTagType {
|
|
|
|
in_name
|
|
|
|
new_tag
|
|
|
|
}
|
|
|
|
|
2020-12-09 22:08:15 +03:00
|
|
|
// Tag holds the information of an HTML tag.
|
2021-02-13 17:52:01 +03:00
|
|
|
[heap]
|
2020-08-09 05:13:34 +03:00
|
|
|
pub struct Tag {
|
2020-08-18 02:08:58 +03:00
|
|
|
pub mut:
|
|
|
|
name string
|
|
|
|
content string
|
|
|
|
children []&Tag
|
2020-08-09 05:13:34 +03:00
|
|
|
attributes map[string]string // attributes will be like map[name]value
|
2020-08-18 02:08:58 +03:00
|
|
|
last_attribute string
|
2023-01-18 20:00:46 +03:00
|
|
|
class_set datatypes.Set[string]
|
2022-09-15 07:59:31 +03:00
|
|
|
parent &Tag = unsafe { nil }
|
2020-09-09 15:14:44 +03:00
|
|
|
position_in_parent int
|
2020-09-09 16:34:41 +03:00
|
|
|
closed bool
|
2020-08-09 05:13:34 +03:00
|
|
|
close_type CloseTagType = .in_name
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (mut tag Tag) add_parent(t &Tag, position int) {
|
|
|
|
tag.position_in_parent = position
|
|
|
|
tag.parent = t
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (mut tag Tag) add_child(t &Tag) int {
|
2020-12-09 22:08:15 +03:00
|
|
|
tag.children << t
|
2020-08-09 05:13:34 +03:00
|
|
|
return tag.children.len
|
|
|
|
}
|
|
|
|
|
2020-12-09 22:08:15 +03:00
|
|
|
// text returns the text contents of the tag.
|
2020-08-09 05:13:34 +03:00
|
|
|
pub fn (tag Tag) text() string {
|
2020-12-09 22:08:15 +03:00
|
|
|
if tag.name.len >= 2 && tag.name[..2] == 'br' {
|
2020-08-09 05:13:34 +03:00
|
|
|
return '\n'
|
|
|
|
}
|
2020-12-09 22:08:15 +03:00
|
|
|
mut text_str := strings.new_builder(200)
|
2023-02-03 01:32:03 +03:00
|
|
|
text_str.write_string(tag.content)
|
2020-12-09 22:08:15 +03:00
|
|
|
for child in tag.children {
|
2021-02-22 14:18:11 +03:00
|
|
|
text_str.write_string(child.text())
|
2020-08-09 05:13:34 +03:00
|
|
|
}
|
2020-12-09 22:08:15 +03:00
|
|
|
return text_str.str()
|
2020-08-09 05:13:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (tag &Tag) str() string {
|
2020-12-09 22:08:15 +03:00
|
|
|
mut html_str := strings.new_builder(200)
|
2022-11-15 16:53:13 +03:00
|
|
|
html_str.write_string('<${tag.name}')
|
2020-12-09 22:08:15 +03:00
|
|
|
for key, value in tag.attributes {
|
2022-11-15 16:53:13 +03:00
|
|
|
html_str.write_string(' ${key}')
|
2020-08-09 05:13:34 +03:00
|
|
|
if value.len > 0 {
|
2022-11-15 16:53:13 +03:00
|
|
|
html_str.write_string('="${value}"')
|
2020-08-09 05:13:34 +03:00
|
|
|
}
|
|
|
|
}
|
2021-02-25 15:24:30 +03:00
|
|
|
html_str.write_string(if tag.closed && tag.close_type == .in_name { '/>' } else { '>' })
|
2021-02-22 14:18:11 +03:00
|
|
|
html_str.write_string(tag.content)
|
2020-08-09 05:13:34 +03:00
|
|
|
if tag.children.len > 0 {
|
2020-12-09 22:08:15 +03:00
|
|
|
for child in tag.children {
|
2021-02-22 14:18:11 +03:00
|
|
|
html_str.write_string(child.str())
|
2020-08-09 05:13:34 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if !tag.closed || tag.close_type == .new_tag {
|
2022-11-15 16:53:13 +03:00
|
|
|
html_str.write_string('</${tag.name}>')
|
2020-08-09 05:13:34 +03:00
|
|
|
}
|
2020-12-09 22:08:15 +03:00
|
|
|
return html_str.str()
|
2020-08-09 05:13:34 +03:00
|
|
|
}
|
2022-01-09 17:07:12 +03:00
|
|
|
|
2023-05-09 00:22:52 +03:00
|
|
|
// get_tag retrieves the first found child tag in the tag that has the given tag name.
|
|
|
|
pub fn (tag &Tag) get_tag(name string) ?&Tag {
|
|
|
|
for child in tag.children {
|
|
|
|
if child.name == name {
|
|
|
|
return child
|
|
|
|
}
|
|
|
|
if c := child.get_tag(name) {
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return none
|
|
|
|
}
|
|
|
|
|
2023-06-27 20:10:31 +03:00
|
|
|
// get_tags retrieves all child tags recursively in the tag that have the given tag name.
|
2022-01-09 17:07:12 +03:00
|
|
|
pub fn (tag &Tag) get_tags(name string) []&Tag {
|
|
|
|
mut res := []&Tag{}
|
|
|
|
for child in tag.children {
|
|
|
|
if child.name == name {
|
|
|
|
res << child
|
|
|
|
}
|
|
|
|
res << child.get_tags(name)
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2023-05-09 00:22:52 +03:00
|
|
|
// get_tag_by_attribute retrieves the first found child tag in the tag that has the given attribute name.
|
|
|
|
pub fn (tag &Tag) get_tag_by_attribute(name string) ?&Tag {
|
|
|
|
for child in tag.children {
|
|
|
|
if child.attributes[name] != '' {
|
|
|
|
return child
|
|
|
|
}
|
|
|
|
if c := child.get_tag_by_attribute(name) {
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return none
|
|
|
|
}
|
|
|
|
|
2023-06-27 20:10:31 +03:00
|
|
|
// get_tags_by_attribute retrieves all child tags recursively in the tag that have the given attribute name.
|
2022-01-09 17:07:12 +03:00
|
|
|
pub fn (tag &Tag) get_tags_by_attribute(name string) []&Tag {
|
|
|
|
mut res := []&Tag{}
|
|
|
|
for child in tag.children {
|
|
|
|
if child.attributes[name] != '' {
|
|
|
|
res << child
|
|
|
|
}
|
|
|
|
res << child.get_tags_by_attribute(name)
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2023-05-09 00:22:52 +03:00
|
|
|
// get_tag_by_attribute_value retrieves the first found child tag in the tag that has the given attribute name and value.
|
|
|
|
pub fn (tag &Tag) get_tag_by_attribute_value(name string, value string) ?&Tag {
|
|
|
|
for child in tag.children {
|
|
|
|
if child.attributes[name] == value {
|
|
|
|
return child
|
|
|
|
}
|
|
|
|
if c := child.get_tag_by_attribute_value(name, value) {
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return none
|
|
|
|
}
|
|
|
|
|
2023-06-27 20:10:31 +03:00
|
|
|
// get_tags_by_attribute_value retrieves all child tags recursively in the tag that have the given attribute name and value.
|
2022-01-09 17:07:12 +03:00
|
|
|
pub fn (tag &Tag) get_tags_by_attribute_value(name string, value string) []&Tag {
|
|
|
|
mut res := []&Tag{}
|
|
|
|
for child in tag.children {
|
|
|
|
if child.attributes[name] == value {
|
|
|
|
res << child
|
|
|
|
}
|
|
|
|
res << child.get_tags_by_attribute_value(name, value)
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
2023-01-18 20:00:46 +03:00
|
|
|
|
2023-05-09 00:22:52 +03:00
|
|
|
// get_tag_by_class_name retrieves the first found child tag in the tag that has the given class name(s).
|
|
|
|
pub fn (tag &Tag) get_tag_by_class_name(names ...string) ?&Tag {
|
|
|
|
for child in tag.children {
|
|
|
|
mut matched := true
|
|
|
|
for name in names {
|
|
|
|
matched = child.class_set.exists(name)
|
|
|
|
if !matched {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if matched {
|
|
|
|
return child
|
|
|
|
}
|
|
|
|
if c := child.get_tag_by_class_name(...names) {
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return none
|
|
|
|
}
|
|
|
|
|
2023-06-27 20:10:31 +03:00
|
|
|
// get_tags_by_class_name retrieves all child tags recursively in the tag that have the given class name(s).
|
2023-01-18 20:00:46 +03:00
|
|
|
pub fn (tag &Tag) get_tags_by_class_name(names ...string) []&Tag {
|
|
|
|
mut res := []&Tag{}
|
|
|
|
for child in tag.children {
|
|
|
|
mut matched := true
|
|
|
|
for name in names {
|
|
|
|
matched = child.class_set.exists(name)
|
|
|
|
if !matched {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if matched {
|
|
|
|
res << child
|
|
|
|
}
|
|
|
|
res << child.get_tags_by_class_name(...names)
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|