@@ -250,6 +250,30 @@ def specificity(self):
250250 return a1 + a2 , b1 + b2 , c1 + c2
251251
252252
253+ class Relation (object ):
254+ """
255+ Represents selector:has(subselector)
256+ """
257+ def __init__ (self , selector , subselector ):
258+ self .selector = selector
259+ self .subselector = subselector
260+
261+ def __repr__ (self ):
262+ return '%s[%r:has(%r)]' % (
263+ self .__class__ .__name__ , self .selector , self .subselector )
264+
265+ def canonical (self ):
266+ subsel = self .subselector .canonical ()
267+ if len (subsel ) > 1 :
268+ subsel = subsel .lstrip ('*' )
269+ return '%s:has(%s)' % (self .selector .canonical (), subsel )
270+
271+ def specificity (self ):
272+ a1 , b1 , c1 = self .selector .specificity ()
273+ a2 , b2 , c2 = self .subselector .specificity ()
274+ return a1 + a2 , b1 + b2 , c1 + c2
275+
276+
253277class Attrib (object ):
254278 """
255279 Represents selector[namespace|attrib operator value]
@@ -538,6 +562,9 @@ def parse_simple_selector(stream, inside_negation=False):
538562 if next != ('DELIM' , ')' ):
539563 raise SelectorSyntaxError ("Expected ')', got %s" % (next ,))
540564 result = Negation (result , argument )
565+ elif ident .lower () == 'has' :
566+ arguments = parse_relative_selector (stream )
567+ result = Relation (result , arguments )
541568 else :
542569 result = Function (result , ident , parse_arguments (stream ))
543570 else :
@@ -564,6 +591,24 @@ def parse_arguments(stream):
564591 "Expected an argument, got %s" % (next ,))
565592
566593
594+ def parse_relative_selector (stream ):
595+ arguments = []
596+ stream .skip_whitespace ()
597+ next = stream .next ()
598+ if next in [('DELIM' , '+' ), ('DELIM' , '-' ), ('DELIM' , '>' ), ('DELIM' , '~' )]:
599+ arguments .append (next )
600+ while 1 :
601+ stream .skip_whitespace ()
602+ next = stream .next ()
603+ if next .type in ('IDENT' , 'STRING' , 'NUMBER' ):
604+ arguments .append (Element (element = next .value ))
605+ elif next == ('DELIM' , ')' ):
606+ return arguments
607+ else :
608+ raise SelectorSyntaxError (
609+ "Expected an argument, got %s" % (next ,))
610+
611+
567612def parse_attrib (selector , stream ):
568613 stream .skip_whitespace ()
569614 attrib = stream .next_ident_or_star ()
0 commit comments