You are here

Compress.inc in Advanced CSS/JS Aggregation 6

Same filename and directory in other branches
  1. 7 advagg_css_compress/css-compressor-3.x/src/lib/Compress.inc

File

advagg_css_compress/css-compressor-3.x/src/lib/Compress.inc
View source
<?php

/**
 * CSS Compressor [VERSION]
 * [DATE]
 * Corey Hart @ http://www.codenothing.com
 */
class CSSCompression_Compress {

  /**
   * Trim Patterns
   *
   * @param (array) options: Reference to options
   * @param (array) stats: Reference to stats
   * @param (regex) rsemicolon: Checks for semicolon without an escape '\' character before it
   * @param (regex) rcolon: Checks for colon without an escape '\' character before it
   * @param (regex) rspace: Checks for space without an escape '\' character before it
   */
  private $options = array();
  private $stats = array();
  private $rsemicolon = "/(?<!\\\\);/";
  private $rcolon = "/(?<!\\\\):/";
  private $rspace = "/(?<!\\\\)\\s/";

  /**
   * Other inner classes that get used within compression
   *
   * @class Control: Compression Controller
   * @class Trim: Trim Instance
   * @class Setup: Setup Instance
   * @class Format: Formatting Instance
   * @class Combine: Combine Instance
   * @class Cleanup: Cleanup Instance
   * @class Organize: Organize Instance
   * @class Selectors: Selectors Instance
   * @param (array) others: List of above classes for copying
   */
  private $Control;
  private $Trim;
  private $Setup;
  private $Format;
  private $Combine;
  private $Cleanup;
  private $Organize;
  private $Selectors;
  private $others = array(
    'Trim',
    'Setup',
    'Format',
    'Combine',
    'Cleanup',
    'Organize',
    'Selectors',
  );

  /**
   * Stash a reference to the controller on each instantiation
   *
   * @param (class) control: CSSCompression Controller
   */
  public function __construct(CSSCompression_Control $control) {
    $this->Control = $control;
    $this->options =& $control->Option->options;
    $this->stats =& $control->stats;
    foreach ($this->others as $class) {
      $this->{$class} = $control->{$class};
    }
  }

  /**
   * Centralized function to run css compression.
   *
   * @param (string) css: Stylesheet to compresss
   */
  public function compress($css) {
    $setup = $this
      ->setup($css);
    $setup = $this
      ->rulesets($setup);
    $css = $this
      ->readability($setup);

    // Attach plea to top of page with unknown blocks
    if ($this->options['add-unknown'] && count($setup['unknown'])) {
      $css = "/*\nThere are unknown blocks in the sheet, please please please open an issue with your sheet attached to it:\n" . "https://github.com/codenothing/css-compressor/issues\n" . "Thank You --\n\n" . implode("\n", $setup['unknown']) . "\n*/\n" . $css;
    }

    // Mark final file size
    $this->stats['after']['size'] = strlen($css = trim($css));

    // Return compressed css
    return $css;
  }

  /**
   * Runs css through initial setup handlers
   *
   * @param (string) css: Sheet to compress
   */
  private function setup($css) {

    // Initial stats
    $this->stats['before']['time'] = microtime(true);
    $this->stats['before']['size'] = strlen($css);

    // Initial trimming
    $css = $this->Trim
      ->trim($css);

    // Do a little tokenizing, compress each property individually
    $setup = $this->Setup
      ->setup($css);

    // Mark number of selectors pre-combine
    $this->stats['before']['selectors'] = count($setup['selectors']);
    return $setup;
  }

  /**
   * Focus compressions on each rule set
   *
   * @param (array) setup: Array containing selectors and rule sets
   */
  private function rulesets($setup) {

    // Do selector specific compressions
    $this->Selectors
      ->selectors($setup['selectors']);

    // Look at each group of properties as a whole, and compress/combine similiar definitions
    $this->Combine
      ->combine($setup['selectors'], $setup['details']);

    // If order isn't important, run comination functions before and after compressions to catch all instances
    // Be sure to prune before hand for higher chance of matching
    if ($this->options['organize']) {
      $this->Cleanup
        ->cleanup($setup['selectors'], $setup['details']);
      $this->Organize
        ->organize($setup['selectors'], $setup['details']);
      $this->Combine
        ->combine($setup['selectors'], $setup['details']);
    }

    // Do final maintenace work, remove injected property/values
    $this->Cleanup
      ->cleanup($setup['selectors'], $setup['details']);

    // Run final counters before full cleanup
    $this
      ->finalCount($setup['selectors'], $setup['details']);
    return $setup;
  }

  /**
   * Runs final counts on selectors and props
   *
   * @param (array) selectors: Selector rules
   * @param (array) details: Rule sets
   */
  private function finalCount($selectors, $details) {

    // Selectors and props
    $this->stats['after']['selectors'] = count($selectors);
    foreach ($details as $item) {
      $props = preg_split($this->rsemicolon, $item);

      // Make sure count is true
      foreach ($props as $k => $v) {
        if (!isset($v) || $v == '') {
          unset($props[$k]);
        }
      }
      $this->stats['after']['props'] += count($props);
    }

    // Final count for stats
    $this->stats['after']['time'] = microtime(true);
  }

  /**
   * Formats the compressed rule sets into a stylesheet
   *
   * @param (array) setup: Array containing selectors and rule sets
   */
  private function readability($setup) {

    // Format css to users preference
    $css = $this->Format
      ->readability($this->options['readability'], $setup['selectors'], $setup['details']);

    // Intros
    foreach ($setup as $value) {
      if ($value && is_string($value)) {
        $css = $value . $css;
      }
    }

    // Remove escapables
    $css = $this->Cleanup
      ->removeInjections($css);
    return $css;
  }

  /**
   * Access to private methods for testing
   *
   * @param (string) method: Method to be called
   * @param (array) args: Array of paramters to be passed in
   */
  public function access($method, $args) {
    if (method_exists($this, $method)) {
      return call_user_func_array(array(
        $this,
        $method,
      ), $args);
    }
    else {
      throw new CSSCompression_Exception("Unknown method in Compress Class - " . $method);
    }
  }

}

Classes

Namesort descending Description
CSSCompression_Compress CSS Compressor [VERSION] [DATE] Corey Hart @ http://www.codenothing.com