Class: Sass::Selector::Pseudo

### Home Classes Methods

### In Files

- lib/sass/selector/pseudo.rb

### Parent

Simple

### Methods

- ::new
- #normalized_name
- #specificity
- #superselector?
- #to_s
- #type
- #unify
- #with_selector

### Class/Module Index

Quicksearch

- Sass
- Sass::BaseEnvironment
- Sass::CSS
- Sass::CacheStores
- Sass::CacheStores::Base
- Sass::CacheStores::Chain
- Sass::CacheStores::Filesystem
- Sass::CacheStores::Memory
- Sass::CacheStores::Null
- Sass::Callbacks
- Sass::Callbacks::InstanceMethods
- Sass::Engine
- Sass::Engine::Line
- Sass::Environment
- Sass::Exec
- Sass::Exec::Base
- Sass::Exec::SassConvert
- Sass::Exec::SassScss
- Sass::Exec::SassScss::Sass::Plugin.compiler
- Sass::Features
- Sass::Importers
- Sass::Importers::Base
- Sass::Importers::Filesystem
- Sass::Logger
- Sass::Logger::Base
- Sass::Logger::LogLevel
- Sass::Logger::LogLevel::ClassMethods
- Sass::Media
- Sass::Media::Query
- Sass::Media::QueryList
- Sass::Plugin
- Sass::Plugin::Compiler
- Sass::Plugin::Configuration
- Sass::Plugin::MerbBootLoader
- Sass::Plugin::Rack
- Sass::Plugin::StalenessChecker
- Sass::ReadOnlyEnvironment
- Sass::Repl
- Sass::SCSS
- Sass::SCSS::CssParser
- Sass::SCSS::Parser
- Sass::SCSS::RX
- Sass::SCSS::ScriptLexer
- Sass::SCSS::ScriptParser
- Sass::SCSS::StaticParser
- Sass::Script
- Sass::Script::CssLexer
- Sass::Script::CssParser
- Sass::Script::Functions
- Sass::Script::Functions::EvaluationContext
- Sass::Script::Lexer
- Sass::Script::Parser
- Sass::Script::Tree
- Sass::Script::Tree::Funcall
- Sass::Script::Tree::Interpolation
- Sass::Script::Tree::ListLiteral
- Sass::Script::Tree::Literal
- Sass::Script::Tree::MapLiteral
- Sass::Script::Tree::Node
- Sass::Script::Tree::Operation
- Sass::Script::Tree::Selector
- Sass::Script::Tree::StringInterpolation
- Sass::Script::Tree::UnaryOperation
- Sass::Script::Tree::Variable
- Sass::Script::Value
- Sass::Script::Value::ArgList
- Sass::Script::Value::Base
- Sass::Script::Value::Bool
- Sass::Script::Value::Color
- Sass::Script::Value::Helpers
- Sass::Script::Value::List
- Sass::Script::Value::Map
- Sass::Script::Value::Null
- Sass::Script::Value::Number
- Sass::Selector
- Sass::Selector::AbstractSequence
- Sass::Selector::Attribute
- Sass::Selector::Class
- Sass::Selector::CommaSequence
- Sass::Selector::Element
- Sass::Selector::Id
- Sass::Selector::Parent
- Sass::Selector::Placeholder
- Sass::Selector::Pseudo
- Sass::Selector::Sequence
- Sass::Selector::Simple
- Sass::Selector::SimpleSequence
- Sass::Selector::Universal
- Sass::SemiGlobalEnvironment
- Sass::Shared
- Sass::Source
- Sass::Source::Map
- Sass::Source::Map::Mapping
- Sass::Source::Position
- Sass::Source::Range
- Sass::Stack
- Sass::Stack::Frame
- Sass::Supports
- Sass::Supports::Condition
- Sass::Supports::Declaration
- Sass::Supports::Interpolation
- Sass::Supports::Negation
- Sass::Supports::Operator
- Sass::SyntaxError
- Sass::Tree
- Sass::Tree::AtRootNode
- Sass::Tree::CharsetNode
- Sass::Tree::CommentNode
- Sass::Tree::ContentNode
- Sass::Tree::CssImportNode
- Sass::Tree::DebugNode
- Sass::Tree::DirectiveNode
- Sass::Tree::EachNode
- Sass::Tree::ErrorNode
- Sass::Tree::ExtendNode
- Sass::Tree::ForNode
- Sass::Tree::FunctionNode
- Sass::Tree::IfNode
- Sass::Tree::ImportNode
- Sass::Tree::KeyframeRuleNode
- Sass::Tree::MediaNode
- Sass::Tree::MixinDefNode
- Sass::Tree::MixinNode
- Sass::Tree::Node
- Sass::Tree::PropNode
- Sass::Tree::ReturnNode
- Sass::Tree::RootNode
- Sass::Tree::RuleNode
- Sass::Tree::SupportsNode
- Sass::Tree::TraceNode
- Sass::Tree::VariableNode
- Sass::Tree::Visitors
- Sass::Tree::Visitors::Base
- Sass::Tree::Visitors::CheckNesting
- Sass::Tree::Visitors::Convert
- Sass::Tree::Visitors::Cssize
- Sass::Tree::Visitors::Cssize::Bubble
- Sass::Tree::Visitors::DeepCopy
- Sass::Tree::Visitors::Extend
- Sass::Tree::Visitors::Perform
- Sass::Tree::Visitors::SetOptions
- Sass::Tree::Visitors::ToCss
- Sass::Tree::WarnNode
- Sass::Tree::WhileNode
- Sass::UnitConversionError
- Sass::Util
- Sass::Util::CrossPlatformRandom
- Sass::Util::MultibyteStringScanner
- Sass::Util::NormalizedMap
- Sass::Util::SubsetMap
- Sass::Util::Test
- Sass::Version
- ActionController
- ActionController::Base
- Object
- OrderedHash

No matching classes.

# Sass::Selector::Pseudo

A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`) selector. It can have arguments (e.g. `:nth-child(2n+1)`) which can contain selectors (e.g. `:nth-child(2n+1 of .foo)`).

### Constants

ACTUALLY_ELEMENTS

  Some pseudo-class-syntax selectors are actually considered pseudo-elements and must be treated differently. This is a list of such selectors.

  @return [Set<String>]

### Attributes

arg[R]

The argument to the selector, or `nil` if no argument was given.

@return [String, nil]

name[R]

The name of the selector.

@return [String]

selector[R]

The selector argument, or `nil` if no selector exists.

If this and {#arg} are both set, {#arg} is considered a non-selector prefix.

@return [CommaSequence]

syntactic_type[R]

Like {#type}, but returns the type of selector this looks like, rather than the type it is semantically. This only differs from type for selectors in {ACTUALLY_ELEMENTS}.

@return [Symbol]

### Public Class Methods

new(syntactic_type, name, arg, selector) click to toggle source

@param syntactic_type [Symbol] See {#syntactic_type} @param name [String] See {#name} @param arg [nil, String] See {#arg} @param selector [nil, CommaSequence] See {#selector}

    # File lib/sass/selector/pseudo.rb, line 44
    def initialize(syntactic_type, name, arg, selector)
      @syntactic_type = syntactic_type
      @name = name
      @arg = arg
      @selector = selector
    end

### Public Instance Methods

normalized_name() click to toggle source

Like {#name}, but without any vendor prefix.

@return [String]

    # File lib/sass/selector/pseudo.rb, line 111
    def normalized_name
      @normalized_name ||= name.gsub(/^-[a-zA-Z0-9]+-/, '')
    end

specificity() click to toggle source

@see AbstractSequence#specificity

    # File lib/sass/selector/pseudo.rb, line 230
    def specificity
      return 1 if type == :element
      return SPECIFICITY_BASE unless selector
      @specificity ||=
        if normalized_name == 'not'
          min = 0
          max = 0
          selector.members.each do |seq|
            spec = seq.specificity
            if spec.is_a?(Range)
              min = Sass::Util.max(spec.begin, min)
              max = Sass::Util.max(spec.end, max)
            else
              min = Sass::Util.max(spec, min)
              max = Sass::Util.max(spec, max)
            end
          end
          min == max ? max : (min..max)
        else
          min = 0
          max = 0
          selector.members.each do |seq|
            spec = seq.specificity
            if spec.is_a?(Range)
              min = Sass::Util.min(spec.begin, min)
              max = Sass::Util.max(spec.end, max)
            else
              min = Sass::Util.min(spec, min)
              max = Sass::Util.max(spec, max)
            end
          end
          min == max ? max : (min..max)
        end
    end

superselector?(their_sseq, parents = []) click to toggle source

Returns whether or not this selector matches all elements that the given selector matches (as well as possibly more).

@example

    (.foo).superselector?(.foo.bar) #=> true
    (.foo).superselector?(.bar) #=> false

@param their_sseq [SimpleSequence] @param parents [Array<SimpleSequence, String>] The parent selectors of `their_sseq`, if any. @return [Boolean]

    # File lib/sass/selector/pseudo.rb, line 149
    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'
        # 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

to_s() click to toggle source

@see Selector#to_s

    # File lib/sass/selector/pseudo.rb, line 116
    def to_s
      res = (syntactic_type == :class ? ":" : "::") + @name
      if @arg || @selector
        res << "("
        res << @arg.strip if @arg
        res << " " if @arg && @selector
        res << @selector.to_s if @selector
        res << ")"
      end
      res
    end

type() click to toggle source

The type of the selector. `:class` if this is a pseudoclass selector, `:element` if it's a pseudoelement.

@return [Symbol]

    # File lib/sass/selector/pseudo.rb, line 104
    def type
      ACTUALLY_ELEMENTS.include?(normalized_name) ? :element : syntactic_type
    end

unify(sels) click to toggle source

Returns `nil` if this is a pseudoelement selector and `sels` contains a pseudoelement selector different than this one.

@see SimpleSequence#unify

    # File lib/sass/selector/pseudo.rb, line 132
    def unify(sels)
      return if type == :element && sels.any? do |sel|
        sel.is_a?(Pseudo) && sel.type == :element &&
          (sel.name != name || sel.arg != arg || sel.selector != selector)
      end
      super
    end

with_selector(new_selector) click to toggle source

Returns a copy of this with {#selector} set to {#new_selector}.

@param new_selector [CommaSequence] @return [Array<Simple>]

    # File lib/sass/selector/pseudo.rb, line 55
    def with_selector(new_selector)
      result = Pseudo.new(syntactic_type, name, arg,
        CommaSequence.new(new_selector.members.map do |seq|
          next seq unless seq.members.length == 1
          sseq = seq.members.first
          next seq unless sseq.is_a?(SimpleSequence) && sseq.members.length == 1
          sel = sseq.members.first
          next seq unless sel.is_a?(Pseudo) && sel.selector

          case normalized_name
          when 'not'
            # In theory, if there's a nested :not its contents should be
            # unified with the return value. For example, if :not(.foo)
            # extends .bar, :not(.bar) should become .foo:not(.bar). However,
            # this is a narrow edge case and supporting it properly would make
            # this code and the code calling it a lot more complicated, so
            # it's not supported for now.
            next [] unless sel.normalized_name == 'matches'
            sel.selector.members
          when 'matches', 'any', 'current', 'nth-child', 'nth-last-child'
            # As above, we could theoretically support :not within :matches, but
            # doing so would require this method and its callers to handle much
            # more complex cases that likely aren't worth the pain.
            next [] unless sel.name == name && sel.arg == arg
            sel.selector.members
          when 'has', 'host', 'host-context'
            # We can't expand nested selectors here, because each layer adds an
            # additional layer of semantics. For example, `:has(:has(img))`
            # doesn't match `<div><img></div>` but `:has(img)` does.
            sel
          else
            []
          end
        end.flatten))

      # Older browsers support :not but only with a single complex selector.
      # In order to support those browsers, we break up the contents of a :not
      # unless it originally contained a selector list.
      return [result] unless normalized_name == 'not'
      return [result] if selector.members.length > 1
      result.selector.members.map do |seq|
        Pseudo.new(syntactic_type, name, arg, CommaSequence.new([seq]))
      end
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.