2 #include "css_selector.h"
5 void litehtml::css_element_selector::parse_nth_child_params(const string
& param
, int& num
, int& off
)
12 else if (param
== "even")
20 split_string(param
, tokens
, " n", "n");
26 for (const auto& token
: tokens
)
40 num
= atoi(s_num
.c_str());
41 off
= atoi(s_off
.c_str());
45 void litehtml::css_element_selector::parse( const string
& txt
)
47 string::size_type el_end
= txt
.find_first_of(".#[:");
48 string tag
= txt
.substr(0, el_end
);
50 if (tag
== "") tag
= "*";
54 while(el_end
!= string::npos
)
56 if(txt
[el_end
] == '.')
58 css_attribute_selector attribute
;
60 attribute
.type
= select_class
;
61 string::size_type pos
= txt
.find_first_of(".#[:", el_end
+ 1);
62 string name
= txt
.substr(el_end
+ 1, pos
- el_end
- 1);
63 litehtml::lcase(name
);
64 attribute
.name
= _id(name
);
65 m_attrs
.push_back(attribute
);
67 } else if(txt
[el_end
] == '#')
69 css_attribute_selector attribute
;
71 attribute
.type
= select_id
;
72 string::size_type pos
= txt
.find_first_of(".#[:", el_end
+ 1);
73 string name
= txt
.substr(el_end
+ 1, pos
- el_end
- 1);
74 litehtml::lcase(name
);
75 attribute
.name
= _id(name
);
76 m_attrs
.push_back(attribute
);
78 } else if(txt
[el_end
] == ':')
80 css_attribute_selector attribute
;
82 if(txt
[el_end
+ 1] == ':')
84 attribute
.type
= select_pseudo_element
;
85 string::size_type pos
= txt
.find_first_of(".#[:", el_end
+ 2);
86 string name
= txt
.substr(el_end
+ 2, pos
- el_end
- 2);
87 litehtml::lcase(name
);
88 attribute
.name
= _id(name
);
89 m_attrs
.push_back(attribute
);
93 string::size_type pos
= txt
.find_first_of(".#[:(", el_end
+ 1);
94 string name
= txt
.substr(el_end
+ 1, pos
- el_end
- 1);
96 attribute
.name
= _id(name
);
97 if(attribute
.name
== _after_
|| attribute
.name
== _before_
)
99 attribute
.type
= select_pseudo_element
;
102 attribute
.type
= select_pseudo_class
;
106 if(pos
!= string::npos
&& txt
.at(pos
) == '(')
108 auto end
= find_close_bracket(txt
, pos
);
109 val
= txt
.substr(pos
+ 1, end
- pos
- 1);
110 if (end
!= string::npos
) pos
= end
+ 1;
113 switch (attribute
.name
)
117 case _nth_last_child_
:
118 case _nth_last_of_type_
:
120 parse_nth_child_params(val
, attribute
.a
, attribute
.b
);
123 attribute
.sel
= std::make_shared
<css_element_selector
>();
124 attribute
.sel
->parse(val
);
133 m_attrs
.push_back(attribute
);
136 } else if(txt
[el_end
] == '[')
138 css_attribute_selector attribute
;
140 string::size_type pos
= txt
.find_first_of("]~=|$*^", el_end
+ 1);
141 string attr
= txt
.substr(el_end
+ 1, pos
- el_end
- 1);
143 litehtml::lcase(attr
);
144 if(pos
!= string::npos
)
148 attribute
.type
= select_exists
;
149 } else if(txt
[pos
] == '=')
151 attribute
.type
= select_equal
;
153 } else if(txt
.substr(pos
, 2) == "~=")
155 attribute
.type
= select_contain_str
;
157 } else if(txt
.substr(pos
, 2) == "|=")
159 attribute
.type
= select_start_str
;
161 } else if(txt
.substr(pos
, 2) == "^=")
163 attribute
.type
= select_start_str
;
165 } else if(txt
.substr(pos
, 2) == "$=")
167 attribute
.type
= select_end_str
;
169 } else if(txt
.substr(pos
, 2) == "*=")
171 attribute
.type
= select_contain_str
;
175 attribute
.type
= select_exists
;
178 pos
= txt
.find_first_not_of(" \t", pos
);
179 if(pos
!= string::npos
)
183 string::size_type pos2
= txt
.find_first_of('\"', pos
+ 1);
184 attribute
.val
= txt
.substr(pos
+ 1, pos2
== string::npos
? pos2
: (pos2
- pos
- 1));
185 pos
= pos2
== string::npos
? pos2
: (pos2
+ 1);
186 } else if(txt
[pos
] == '\'')
188 string::size_type pos2
= txt
.find_first_of('\'', pos
+ 1);
189 attribute
.val
= txt
.substr(pos
+ 1, pos2
== string::npos
? pos2
: (pos2
- pos
- 1));
190 pos
= pos2
== string::npos
? pos2
: (pos2
+ 1);
191 } else if(txt
[pos
] == ']')
196 string::size_type pos2
= txt
.find_first_of(']', pos
+ 1);
197 attribute
.val
= txt
.substr(pos
, pos2
== string::npos
? pos2
: (pos2
- pos
));
199 pos
= pos2
== string::npos
? pos2
: (pos2
+ 1);
204 attribute
.type
= select_exists
;
206 attribute
.name
= _id(attr
);
207 m_attrs
.push_back(attribute
);
213 el_end
= txt
.find_first_of(".#[:", el_end
);
218 bool litehtml::css_selector::parse( const string
& text
)
224 string_vector tokens
;
225 split_string(text
, tokens
, "", " \t>+~", "([");
233 string right
= tokens
.back();
237 while(!tokens
.empty() && (tokens
.back() == " " || tokens
.back() == "\t" || tokens
.back() == "+" || tokens
.back() == "~" || tokens
.back() == ">"))
239 if(combinator
== ' ' || combinator
== 0)
241 combinator
= tokens
.back()[0];
246 for(const auto & token
: tokens
)
259 m_right
.parse(right
);
264 m_combinator
= combinator_child
;
267 m_combinator
= combinator_adjacent_sibling
;
270 m_combinator
= combinator_general_sibling
;
273 m_combinator
= combinator_descendant
;
281 m_left
= std::make_shared
<css_selector
>();
282 if(!m_left
->parse(left
))
291 void litehtml::css_selector::calc_specificity()
293 if(m_right
.m_tag
!= star_id
)
297 for(const auto& attr
: m_right
.m_attrs
)
299 if(attr
.type
== select_id
)
309 m_left
->calc_specificity();
310 m_specificity
+= m_left
->m_specificity
;
314 void litehtml::css_selector::add_media_to_doc( document
* doc
) const
316 if(m_media_query
&& doc
)
318 doc
->add_media_list(m_media_query
);