Skip to content

Commit 437148e

Browse files
committed
:is pseudo selector support added
1 parent aae514f commit 437148e

File tree

5 files changed

+168
-1
lines changed

5 files changed

+168
-1
lines changed

src/main/java/org/htmlunit/cssparser/parser/condition/Condition.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,37 @@ public interface Condition extends Locatable {
2929
enum ConditionType {
3030
/** ATTRIBUTE_CONDITION. */
3131
ATTRIBUTE_CONDITION,
32+
3233
/** ID_CONDITION. */
3334
ID_CONDITION,
35+
3436
/** LANG_CONDITION. */
3537
LANG_CONDITION,
38+
3639
/** ONE_OF_ATTRIBUTE_CONDITION. */
3740
ONE_OF_ATTRIBUTE_CONDITION,
41+
3842
/** BEGIN_HYPHEN_ATTRIBUTE_CONDITION. */
3943
BEGIN_HYPHEN_ATTRIBUTE_CONDITION,
44+
4045
/** CLASS_CONDITION. */
4146
CLASS_CONDITION,
47+
4248
/** PREFIX_ATTRIBUTE_CONDITION. */
4349
PREFIX_ATTRIBUTE_CONDITION,
50+
4451
/** PSEUDO_CLASS_CONDITION. */
4552
PSEUDO_CLASS_CONDITION,
53+
54+
/** IS_PSEUDO_CLASS_CONDITION. */
55+
IS_PSEUDO_CLASS_CONDITION,
56+
4657
/** NOT_PSEUDO_CLASS_CONDITION. */
4758
NOT_PSEUDO_CLASS_CONDITION,
59+
4860
/** SUBSTRING_ATTRIBUTE_CONDITION. */
4961
SUBSTRING_ATTRIBUTE_CONDITION,
62+
5063
/** SUFFIX_ATTRIBUTE_CONDITION. */
5164
SUFFIX_ATTRIBUTE_CONDITION
5265
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2019-2024 Ronald Brill.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* https://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
package org.htmlunit.cssparser.parser.condition;
16+
17+
import java.io.Serializable;
18+
19+
import org.htmlunit.cssparser.parser.AbstractLocatable;
20+
import org.htmlunit.cssparser.parser.Locator;
21+
import org.htmlunit.cssparser.parser.selector.SelectorList;
22+
23+
/**
24+
* Not condition.
25+
*
26+
* @author Ronald Brill
27+
*/
28+
public class IsPseudoClassCondition extends AbstractLocatable implements Condition, Serializable {
29+
30+
private final SelectorList selectors_;
31+
private final boolean doubleColon_;
32+
33+
/**
34+
* Ctor.
35+
* @param selectors the selector list
36+
* @param locator the locator
37+
* @param doubleColon true if was prefixed by double colon
38+
*/
39+
public IsPseudoClassCondition(final SelectorList selectors, final Locator locator, final boolean doubleColon) {
40+
selectors_ = selectors;
41+
setLocator(locator);
42+
doubleColon_ = doubleColon;
43+
}
44+
45+
@Override
46+
public ConditionType getConditionType() {
47+
return ConditionType.IS_PSEUDO_CLASS_CONDITION;
48+
}
49+
50+
/**
51+
* {@inheritDoc}
52+
*/
53+
@Override
54+
public String getLocalName() {
55+
return null;
56+
}
57+
58+
/**
59+
* {@inheritDoc}
60+
*/
61+
@Override
62+
public String getValue() {
63+
return selectors_.toString();
64+
}
65+
66+
/**
67+
* @return the list of selectors
68+
*/
69+
public SelectorList getSelectors() {
70+
return selectors_;
71+
}
72+
73+
@Override
74+
public String toString() {
75+
return (doubleColon_ ? "::" : ":") + "is(" + getValue() + ")";
76+
}
77+
}

src/main/javacc/CSS3Parser.jj

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import org.htmlunit.cssparser.parser.condition.ClassCondition;
4848
import org.htmlunit.cssparser.parser.condition.Condition;
4949
import org.htmlunit.cssparser.parser.condition.IdCondition;
5050
import org.htmlunit.cssparser.parser.condition.LangCondition;
51+
import org.htmlunit.cssparser.parser.condition.IsPseudoClassCondition;
5152
import org.htmlunit.cssparser.parser.condition.NotPseudoClassCondition;
5253
import org.htmlunit.cssparser.parser.condition.OneOfAttributeCondition;
5354
import org.htmlunit.cssparser.parser.condition.PrefixAttributeCondition;
@@ -425,6 +426,8 @@ TOKEN_MGR_DECLS :
425426
| < FUNCTION_LAB: ("ok")? "lab" <LROUND> >
426427
| < FUNCTION_LCH: ("ok")? "lch" <LROUND> >
427428

429+
| < FUNCTION_IS: "is" <LROUND> >
430+
428431
| < CUSTOM_PROPERTY_NAME: < MINUS > <MINUS > <NMSTART> ( <NMCHAR> )* >
429432

430433
// {ident} "(" {return FUNCTION;}
@@ -1398,6 +1401,17 @@ Object pseudo(boolean pseudoElementFound) :
13981401
}
13991402
)
14001403
|
1404+
(
1405+
t = <FUNCTION_IS> { function = unescape(t.image, false); }
1406+
( <S> )*
1407+
selectorList = selectorList()
1408+
<RROUND>
1409+
{
1410+
if (pseudoElementFound) { throw toCSSParseException("duplicatePseudo", new String[] { function + selectorList + ")" }, locator); }
1411+
return new IsPseudoClassCondition(selectorList, locator, doubleColon);
1412+
}
1413+
)
1414+
|
14011415
(
14021416
t = <FUNCTION_LANG> { function = unescape(t.image, false); }
14031417
( <S> )*
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (c) 2019-2024 Ronald Brill.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* https://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
package org.htmlunit.cssparser.parser;
16+
17+
import static org.junit.jupiter.api.Assertions.assertEquals;
18+
19+
import org.htmlunit.cssparser.parser.condition.Condition;
20+
import org.htmlunit.cssparser.parser.condition.Condition.ConditionType;
21+
import org.htmlunit.cssparser.parser.condition.IsPseudoClassCondition;
22+
import org.htmlunit.cssparser.parser.selector.ElementSelector;
23+
import org.htmlunit.cssparser.parser.selector.Selector;
24+
import org.htmlunit.cssparser.parser.selector.Selector.SelectorType;
25+
import org.htmlunit.cssparser.parser.selector.SelectorList;
26+
import org.junit.jupiter.api.Test;
27+
28+
/**
29+
* @author Ronald Brill
30+
*/
31+
public class CSS3ParserIsSelectorTest extends AbstractCSSParserTest {
32+
33+
/**
34+
* @throws Exception if any error occurs
35+
*/
36+
@Test
37+
public void isElementType() throws Exception {
38+
// element name
39+
final SelectorList selectors = createSelectors(":is(ol, ul)");
40+
assertEquals("*:is(ol, ul)", selectors.get(0).toString());
41+
42+
assertEquals(1, selectors.size());
43+
final Selector selector = selectors.get(0);
44+
45+
assertEquals(SelectorType.ELEMENT_NODE_SELECTOR, selector.getSelectorType());
46+
47+
final ElementSelector elemSel = (ElementSelector) selector;
48+
assertEquals(1, elemSel.getConditions().size());
49+
50+
final Condition condition = elemSel.getConditions().get(0);
51+
assertEquals(ConditionType.IS_PSEUDO_CLASS_CONDITION, condition.getConditionType());
52+
53+
final IsPseudoClassCondition pseudo = (IsPseudoClassCondition) condition;
54+
assertEquals("ol, ul", pseudo.getValue());
55+
assertEquals(":is(ol, ul)", pseudo.toString());
56+
57+
final SelectorList conditionSelectors = pseudo.getSelectors();
58+
assertEquals(2, conditionSelectors.size());
59+
final Selector conditionSelector = conditionSelectors.get(0);
60+
final ElementSelector conditionElemSelector = (ElementSelector) conditionSelector;
61+
assertEquals("ol", conditionElemSelector.getElementName());
62+
}
63+
}

src/test/java/org/htmlunit/cssparser/parser/CSS3ParserTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3289,7 +3289,7 @@ public void pseudoElementsErrors() throws Exception {
32893289
checkErrorSelector("input:before:",
32903290
"Error in pseudo class or element. (Invalid token \"<EOF>\". "
32913291
+ "Was expecting one of: \"and\", \"only\", \"inherit\", \"none\", \"from\", <IDENT>, "
3292-
+ "\":\", <FUNCTION_NOT>, <FUNCTION_LANG>, <FUNCTION>.)");
3292+
+ "\":\", <FUNCTION_NOT>, <FUNCTION_LANG>, <FUNCTION_IS>, <FUNCTION>.)");
32933293

32943294
// pseudo element not at end
32953295
checkErrorSelector("input:before:not(#test)",

0 commit comments

Comments
 (0)