class Sass::Selector::Pseudo
def superselector?(their_sseq, parents = [])
-
(Boolean)
-
Parameters:
-
parents
(Array
) -- The parent selectors of `their_sseq`, if any. -
their_sseq
(SimpleSequence
) --
def superselector?(their_sseq, parents = []) case normalized_name when 'matches', 'any' # :matches can be a superselector of another selector in one of two # ways. Either its constituent selectors can be a superset of those of # another :matches in the other selector, or any of its constituent # selectors can individually be a superselector of the other selector. (their_sseq.selector_pseudo_classes[normalized_name] || []).any? do |their_sel| next false unless their_sel.is_a?(Pseudo) next false unless their_sel.name == name selector.superselector?(their_sel.selector) end || selector.members.any? do |our_seq| their_seq = Sequence.new(parents + [their_sseq]) our_seq.superselector?(their_seq) end when 'has', 'host', 'host-context', 'slotted' # Like :matches, :has (et al) can be a superselector of another # selector if its constituent selectors are a superset of those of # another :has in the other selector. However, the :matches other case # doesn't work, because :has refers to nested elements. (their_sseq.selector_pseudo_classes[normalized_name] || []).any? do |their_sel| next false unless their_sel.is_a?(Pseudo) next false unless their_sel.name == name selector.superselector?(their_sel.selector) end when 'not' selector.members.all? do |our_seq| their_sseq.members.any? do |their_sel| if their_sel.is_a?(Element) || their_sel.is_a?(Id) # `:not(a)` is a superselector of `h1` and `:not(#foo)` is a # superselector of `#bar`. our_sseq = our_seq.members.last next false unless our_sseq.is_a?(SimpleSequence) our_sseq.members.any? do |our_sel| our_sel.class == their_sel.class && our_sel != their_sel end else next false unless their_sel.is_a?(Pseudo) next false unless their_sel.name == name # :not(X) is a superselector of :not(Y) exactly when Y is a # superselector of X. their_sel.selector.superselector?(CommaSequence.new([our_seq])) end end end when 'current' (their_sseq.selector_pseudo_classes['current'] || []).any? do |their_current| next false if their_current.name != name # Explicitly don't check for nested superselector relationships # here. :current(.foo) isn't always a superselector of # :current(.foo.bar), since it matches the *innermost* ancestor of # the current element that matches the selector. For example: # # <div class="foo bar"> # <p class="foo"> # <span>current element</span> # </p> # </div> # # Here :current(.foo) would match the p element and *not* the div # element, whereas :current(.foo.bar) would match the div and not # the p. selector == their_current.selector end when 'nth-child', 'nth-last-child' their_sseq.members.any? do |their_sel| # This misses a few edge cases. For example, `:nth-child(n of X)` # is a superselector of `X`, and `:nth-child(2n of X)` is a # superselector of `:nth-child(4n of X)`. These seem rare enough # not to be worth worrying about, though. next false unless their_sel.is_a?(Pseudo) next false unless their_sel.name == name next false unless their_sel.arg == arg selector.superselector?(their_sel.selector) end else throw "[BUG] Unknown selector pseudo class #{name}" end end