All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.css.compiler.ast.CssSelectorNode Maven / Gradle / Ivy

Go to download

Closure Stylesheets is an extension to CSS that adds variables, functions, conditionals, and mixins to standard CSS. The tool also supports minification, linting, RTL flipping, and CSS class renaming.

The newest version!
/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.css.compiler.ast;

import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain;
import com.google.common.css.SourceCodeLocation;

import javax.annotation.Nullable;

/**
 * A node representing a selector in the AST.
 *
 * @author [email protected] (Oana Florescu)
 */
public class CssSelectorNode extends CssNode implements ChunkAware {
  /** Reference to a list of refiners. */
  private CssRefinerListNode refiners;
  /** Reference to a combinator of selectors. */
  private CssCombinatorNode combinator = null;
  /** Name of the selector held by this node. */
  private String selectorName;
  /** The chunk this selector belongs to. */
  private Object chunk;

  /**
   * Constructor of a selector node.
   *
   * @param selectorName
   * @param sourceCodeLocation
   */
  public CssSelectorNode(@Nullable String selectorName,
      @Nullable SourceCodeLocation sourceCodeLocation) {
    super(sourceCodeLocation);
    this.selectorName = selectorName;
    this.refiners = new CssRefinerListNode();
    becomeParentForNode(this.refiners);
  }

  /**
   * Constructor of a selector node.
   *
   * @param selectorName
   */
  public CssSelectorNode(String selectorName) {
    this(selectorName, null);
  }

  /**
   * Copy-constructor of a selector node.
   *
   * @param node
   */
  public CssSelectorNode(CssSelectorNode node) {
    this(node.getSelectorName(), node.getSourceCodeLocation());
    this.chunk = node.getChunk();
    this.refiners = node.getRefiners().deepCopy();
    becomeParentForNode(this.refiners);
    if (node.getCombinator() != null) {
      this.combinator = node.getCombinator().deepCopy();
      becomeParentForNode(this.combinator);
    }
  }

  @Override
  public CssSelectorNode deepCopy() {
    return new CssSelectorNode(this);
  }

  public CssRefinerListNode getRefiners() {
    return refiners;
  }

  public void setRefiners(CssRefinerListNode refiners) {
    removeAsParentOfNode(this.refiners);
    this.refiners = refiners;
    becomeParentForNode(this.refiners);
  }

  public CssCombinatorNode getCombinator() {
    return combinator;
  }

  public void setCombinator(CssCombinatorNode combinator) {
    if (this.combinator != null) {
      removeAsParentOfNode(this.combinator);
    }
    this.combinator = combinator;
    becomeParentForNode(this.combinator);
  }

  public void setSelectorName(String selectorName) {
    this.selectorName = selectorName;
  }

  public String getSelectorName() {
    return selectorName;
  }

  public Specificity getSpecificity() {
    return Specificity.of(this);
  }

  @Override
  public void setChunk(Object chunk) {
    this.chunk = chunk;
  }

  @Override
  public Object getChunk() {
    return chunk;
  }

  /**
   * For debugging only.
   */
  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    if (selectorName != null) {
      sb.append(selectorName);
    }
    if (!refiners.isEmpty()) {
      for (CssRefinerNode node : refiners.childIterable()) {
        sb.append(node.toString());
      }
    }
    if (combinator != null) {
      sb.append(combinator.toString());
    }
    return sb.toString();
  }

  /**
   * The specifity of a selector is used to select among rules with the same
   * importance and origin. It is calculated as specified at
   * http://www.w3.org/TR/CSS2/cascade.html#specificity.
   */
  public static class Specificity implements Comparable {
    /**
     * Counts 1 if the declaration is from is a 'style' attribute rather than
     * a rule with a selector, 0 otherwise
     */
     // a omitted as always 0

    /**
     * Counts the number of ID attributes in the selector.
     */
    private final int b;

    /**
     * Counts the number of other attributes and pseudo-classes in the selector.
     */
    private final int c;

    /**
     * Counts the number of element names and pseudo-elements in the selector.
     */
    private final int d;

    Specificity(int b, int c, int d) {
      this.b = b;
      this.c = c;
      this.d = d;
    }

    private static Specificity of(CssSelectorNode s) {
      int b = 0;
      int c = 0;
      int d = 0;
      if (s.selectorName != null
          && !s.selectorName.isEmpty()
          && !s.selectorName.equals("*")) {
        d++;
      }

      for (CssRefinerNode refiner : s.refiners.childIterable()) {
        Specificity refinerSecificity = refiner.getSpecificity();
        b += refinerSecificity.b;
        c += refinerSecificity.c;
        d += refinerSecificity.d;
      }

      if (s.combinator != null) {
        Specificity o = s.combinator.getSelector().getSpecificity();
        b += o.b;
        c += o.c;
        d += o.d;
      }

      return new Specificity(b, c, d);
    }

    @Override
    public int compareTo(Specificity other) {
      return ComparisonChain.start()
          .compare(b, other.b)
          .compare(c, other.c)
          .compare(d, other.d)
          .result();
    }

    @Override
    public boolean equals(@Nullable Object object) {
      if (object instanceof Specificity) {
        Specificity that = (Specificity) object;
        return this.b == that.b && this.c == that.c && this.d == that.d;
      }
      return false;
    }

    @Override
    public int hashCode() {
      return Objects.hashCode(b, c, d);
    }

    @Override
    public String toString() {
      return "0," + b + "," + c + "," + d;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy