7070import org .htmlunit .cssparser .parser .condition .AttributeCondition ;
7171import org .htmlunit .cssparser .parser .condition .Condition ;
7272import org .htmlunit .cssparser .parser .condition .Condition .ConditionType ;
73+ import org .htmlunit .cssparser .parser .condition .HasPseudoClassCondition ;
7374import org .htmlunit .cssparser .parser .condition .IsPseudoClassCondition ;
7475import org .htmlunit .cssparser .parser .condition .NotPseudoClassCondition ;
7576import org .htmlunit .cssparser .parser .condition .WherePseudoClassCondition ;
8081import org .htmlunit .cssparser .parser .selector .ElementSelector ;
8182import org .htmlunit .cssparser .parser .selector .GeneralAdjacentSelector ;
8283import org .htmlunit .cssparser .parser .selector .PseudoElementSelector ;
84+ import org .htmlunit .cssparser .parser .selector .RelativeSelector ;
8385import org .htmlunit .cssparser .parser .selector .Selector ;
8486import org .htmlunit .cssparser .parser .selector .Selector .SelectorType ;
8587import org .htmlunit .cssparser .parser .selector .SelectorList ;
100102import org .htmlunit .html .HtmlTextArea ;
101103import org .htmlunit .html .ValidatableElement ;
102104import org .htmlunit .javascript .host .css .MediaList ;
103- import org .htmlunit .javascript .host .dom .Document ;
104105import org .htmlunit .util .MimeType ;
105106import org .htmlunit .util .StringUtils ;
106107import org .htmlunit .util .UrlUtils ;
@@ -509,6 +510,53 @@ && selects(browserVersion, gas.getSelector(), (DomElement) prev1,
509510 }
510511 return false ;
511512
513+ case RELATIVE_SELECTOR :
514+ final RelativeSelector rs = (RelativeSelector ) selector ;
515+
516+ switch (rs .getCombinator ()) {
517+ case DESCENDANT_COMBINATOR :
518+ for (final DomElement descendant : element .getDomElementDescendants ()) {
519+ if (selects (browserVersion , rs .getSelector (), descendant , pseudoElement ,
520+ fromQuerySelectorAll , throwOnSyntax )) {
521+ return true ;
522+ }
523+ }
524+ return false ;
525+
526+ case CHILD_COMBINATOR :
527+ for (final DomElement child : element .getChildElements ()) {
528+ if (selects (browserVersion , rs .getSelector (), child , pseudoElement ,
529+ fromQuerySelectorAll , throwOnSyntax )) {
530+ return true ;
531+ }
532+ }
533+ return false ;
534+
535+ case NEXT_SIBLING_COMBINATOR :
536+ final DomElement nextSibling = element .getNextElementSibling ();
537+ if (selects (browserVersion , rs .getSelector (), nextSibling , pseudoElement ,
538+ fromQuerySelectorAll , throwOnSyntax )) {
539+ return true ;
540+ }
541+ return false ;
542+
543+ case SUBSEQUENT_SIBLING_COMBINATOR :
544+ for (DomNode n = element .getNextSibling (); n != null ; n = n .getNextSibling ()) {
545+ if (n instanceof DomElement
546+ && selects (browserVersion , rs .getSelector (), (DomElement ) n , pseudoElement ,
547+ fromQuerySelectorAll , throwOnSyntax )) {
548+ return true ;
549+ }
550+ }
551+ return false ;
552+
553+ default :
554+ if (LOG .isErrorEnabled ()) {
555+ LOG .error ("Unknown CSS combinator '" + rs .getCombinator () + "'." );
556+ }
557+ return false ;
558+ }
559+
512560 default :
513561 if (LOG .isErrorEnabled ()) {
514562 LOG .error ("Unknown CSS selector type '" + selector .getSelectorType () + "'." );
@@ -659,6 +707,16 @@ static boolean selects(final BrowserVersion browserVersion,
659707 }
660708 return false ;
661709
710+ case HAS_PSEUDO_CLASS_CONDITION :
711+ final HasPseudoClassCondition hasPseudoCondition = (HasPseudoClassCondition ) condition ;
712+ final SelectorList hasSelectorList = hasPseudoCondition .getSelectors ();
713+ for (final Selector selector : hasSelectorList ) {
714+ if (selects (browserVersion , selector , element , null , fromQuerySelectorAll , throwOnSyntax )) {
715+ return true ;
716+ }
717+ }
718+ return false ;
719+
662720 case PSEUDO_CLASS_CONDITION :
663721 return selectsPseudoClass (browserVersion , condition , element );
664722
@@ -1074,6 +1132,7 @@ private static String toString(final InputSource source) {
10741132 * Validates the list of selectors.
10751133 * @param selectorList the selectors
10761134 * @param domNode the dom node the query should work on
1135+ *
10771136 * @throws CSSException if a selector is invalid
10781137 */
10791138 public static void validateSelectors (final SelectorList selectorList , final DomNode domNode ) throws CSSException {
@@ -1084,9 +1143,6 @@ public static void validateSelectors(final SelectorList selectorList, final DomN
10841143 }
10851144 }
10861145
1087- /**
1088- * @param documentMode see {@link Document#getDocumentMode()}
1089- */
10901146 private static boolean isValidSelector (final Selector selector , final DomNode domNode ) {
10911147 switch (selector .getSelectorType ()) {
10921148 case ELEMENT_NODE_SELECTOR :
@@ -1124,9 +1180,6 @@ private static boolean isValidSelector(final Selector selector, final DomNode do
11241180 }
11251181 }
11261182
1127- /**
1128- * @param documentMode see {@link Document#getDocumentMode()}
1129- */
11301183 private static boolean isValidCondition (final Condition condition , final DomNode domNode ) {
11311184 switch (condition .getConditionType ()) {
11321185 case ATTRIBUTE_CONDITION :
@@ -1141,8 +1194,35 @@ private static boolean isValidCondition(final Condition condition, final DomNode
11411194 return true ;
11421195 case NOT_PSEUDO_CLASS_CONDITION :
11431196 final NotPseudoClassCondition notPseudoCondition = (NotPseudoClassCondition ) condition ;
1144- final SelectorList selectorList = notPseudoCondition .getSelectors ();
1145- for (final Selector selector : selectorList ) {
1197+ final SelectorList notSelectorList = notPseudoCondition .getSelectors ();
1198+ for (final Selector selector : notSelectorList ) {
1199+ if (!isValidSelector (selector , domNode )) {
1200+ return false ;
1201+ }
1202+ }
1203+ return true ;
1204+ case IS_PSEUDO_CLASS_CONDITION :
1205+ final IsPseudoClassCondition isPseudoCondition = (IsPseudoClassCondition ) condition ;
1206+ final SelectorList isSelectorList = isPseudoCondition .getSelectors ();
1207+ for (final Selector selector : isSelectorList ) {
1208+ if (!isValidSelector (selector , domNode )) {
1209+ return false ;
1210+ }
1211+ }
1212+ return true ;
1213+ case WHERE_PSEUDO_CLASS_CONDITION :
1214+ final WherePseudoClassCondition wherePseudoCondition = (WherePseudoClassCondition ) condition ;
1215+ final SelectorList whereSelectorList = wherePseudoCondition .getSelectors ();
1216+ for (final Selector selector : whereSelectorList ) {
1217+ if (!isValidSelector (selector , domNode )) {
1218+ return false ;
1219+ }
1220+ }
1221+ return true ;
1222+ case HAS_PSEUDO_CLASS_CONDITION :
1223+ final HasPseudoClassCondition hasPseudoCondition = (HasPseudoClassCondition ) condition ;
1224+ final SelectorList hasSelectorList = hasPseudoCondition .getSelectors ();
1225+ for (final Selector selector : hasSelectorList ) {
11461226 if (!isValidSelector (selector , domNode )) {
11471227 return false ;
11481228 }
0 commit comments