@@ -250,6 +250,30 @@ def specificity(self):
250
250
return a1 + a2 , b1 + b2 , c1 + c2
251
251
252
252
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
+
253
277
class Attrib (object ):
254
278
"""
255
279
Represents selector[namespace|attrib operator value]
@@ -538,6 +562,9 @@ def parse_simple_selector(stream, inside_negation=False):
538
562
if next != ('DELIM' , ')' ):
539
563
raise SelectorSyntaxError ("Expected ')', got %s" % (next ,))
540
564
result = Negation (result , argument )
565
+ elif ident .lower () == 'has' :
566
+ arguments = parse_relative_selector (stream )
567
+ result = Relation (result , arguments )
541
568
else :
542
569
result = Function (result , ident , parse_arguments (stream ))
543
570
else :
@@ -564,6 +591,24 @@ def parse_arguments(stream):
564
591
"Expected an argument, got %s" % (next ,))
565
592
566
593
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
+
567
612
def parse_attrib (selector , stream ):
568
613
stream .skip_whitespace ()
569
614
attrib = stream .next_ident_or_star ()
0 commit comments