Location: PHPKode > scripts > CSS Crush > peteboere-css-crush-145f165/lib/Mixin.php
<?php
/**
 *
 *  Mixin objects
 *
 */

class csscrush_mixin {

	public $declarationsTemplate = array();

	public $arguments;

	public function __construct ( $block ) {

		// Strip comment markers
		$block = csscrush_util::stripComments( $block );

		// Prepare the arguments object
		$this->arguments = new csscrush_arglist( $block );

		// Re-assign with the parsed arguments string
		$block = $this->arguments->string;

		// Need to split safely as there are semi-colons in data-uris
		$declarations_match = csscrush_util::splitDelimList( $block, ';', true );

		foreach ( $declarations_match->list as $raw_declaration ) {

			$colon = strpos( $raw_declaration, ':' );
			if ( $colon === -1 ) {
				continue;
			}

			// Store template declarations as arrays as they are copied by value not reference
			$declaration = array();

			$declaration['property'] = trim( substr( $raw_declaration, 0, $colon ) );
			$declaration['value'] = trim( substr( $raw_declaration, $colon + 1 ) );

			if ( $declaration['property'] === 'mixin' ) {

				// Mixin can contain other mixins if they are available
				if ( $mixin_declarations = csscrush_mixin::parseValue( $declaration['value'] ) ) {

					// Add mixin result to the stack
					$this->declarationsTemplate = array_merge( $this->declarationsTemplate, $mixin_declarations );
				}
			}
			elseif ( ! empty( $declaration['value'] ) ) {
				$this->declarationsTemplate[] = $declaration;
			}
		}
		return '';
	}


	public function call ( array $args ) {

		// Copy the template
		$declarations = $this->declarationsTemplate;

		if ( count( $this->arguments ) ) {

			list( $find, $replace ) = $this->arguments->getSubstitutions( $args );

			// Place the arguments
			foreach ( $declarations as &$declaration ) {
				$declaration['value'] = str_replace( $find, $replace, $declaration['value'] );
			}
		}

		// Return mixin declarations
		return $declarations;
	}


	public static function parseSingleValue ( $message ) {

		$message = ltrim( $message );

		// e.g. mymixin( 50px, rgba(0,0,0,0), left 100% )

		if ( preg_match( '!^[a-zA-Z0-9_-]+!', $message, $name_match ) ) {

			$mixin_name = $name_match[0];

			if ( isset( csscrush::$process->mixins[ $mixin_name ] ) ) {
				$mixin = csscrush::$process->mixins[ $mixin_name ];
			}
			else {
				// No mixin found with that name
				return false;
			}

			// Discard the name part and any wrapping parens and whitespace
			$message = substr( $message, strlen( $mixin_name ) );
			$message = preg_replace( '!^\s*\(?\s*|\s*\)?\s*$!', '', $message );

			// e.g. "value, rgba(0,0,0,0), left 100%"

			// Determine what raw arguments there are to pass to the mixin
			$args = array();
			if ( $message !== '' ) {
				$args = csscrush_util::splitDelimList( $message, ',', true, true );
				// $args = array_map( 'trim', $args->list );
				$args = $args->list;
			}

			return $mixin->call( $args );
		}
		return false;
	}


	public static function parseValue ( $message ) {

		// Call the mixin and return the list of declarations
		$values = csscrush_util::splitDelimList( $message, ',', true );

		$declarations = array();

		foreach ( $values->list as $item ) {

			if ( $result = self::parseSingleValue( $item ) ) {

				$declarations = array_merge( $declarations, $result );
			}
		}
		return $declarations;
	}
}


/**
 *
 *  Fragment objects
 *
 */

class csscrush_fragment {

	public $template = array();

	public $arguments;

	public function __construct ( $block ) {

		// Prepare the arguments object
		$this->arguments = new csscrush_arglist( $block );

		// Re-assign with the parsed arguments string
		$this->template = $this->arguments->string;
	}

	public function call ( array $args ) {

		// Copy the template
		$template = $this->template;

		if ( count( $this->arguments ) ) {

			list( $find, $replace ) = $this->arguments->getSubstitutions( $args );
			$template = str_replace( $find, $replace, $template );
		}

		// Return fragment css
		return $template;
	}
}




/**
 *
 *  Argument list management for mixins and fragments
 *
 */

class csscrush_arglist implements Countable {

	// Positional argument default values
	public $defaults = array();

	// The number of expected arguments
	public $argCount = 0;

	// The string passed in with arg calls replaced by tokens
	public $string;

	// The arg matching regex
	protected static $argRegex;

	public static function init () {

		// Create regex pattern for matching 'arg' functions
		self::$argRegex = csscrush_function::createFunctionMatchPatt( array( 'arg' ), false );
	}

	function __construct ( $str ) {

		// Parse all arg function calls in the passed string, callback creates default values
		$this->string = csscrush_function::parseCustomFunctions(
												$str, self::$argRegex, array( $this, 'store' ) );
	}

	public function store ( $raw_argument ) {

		// Match the argument index integer
		if ( ! preg_match( '!^[0-9]+!', $raw_argument, $position_match ) ) {
			// On failure to match an integer, return an empty string
			return '';
		}

		// Get the match from the array
		$position_match = $position_match[0];

		// Store the default value
		$default_value = substr( $raw_argument, strlen( $position_match ) );
		$default_value = $default_value ? ltrim( $default_value, " ,\t\n\r" ) : null;

		if ( ! is_null( $default_value ) ) {
			$this->defaults[ $position_match ] = trim( $default_value );
		}

		// Update the mixin argument count
		$argNumber = ( (int) $position_match ) + 1;
		$this->argCount = max( $this->argCount, $argNumber );

		// Return the argument token
		return "___arg{$position_match}___";
	}

	public function getDefaultValue ( $index ) {

		return isset( $this->defaults[ $index ] ) ? $this->defaults[ $index ] : '';
	}

	public function getSubstitutions ( $args ) {

		$argIndexes = range( 0, $this->argCount-1 );

		// Create table of substitutions
		$find = array();
		$replace = array();

		foreach ( $argIndexes as $index ) {

			$find[] = "___arg{$index}___";

			if ( isset( $args[ $index ] ) && $args[ $index ] !== 'default' ) {
				$replace[] = $args[ $index ];
			}
			else {
				$replace[] = $this->getDefaultValue( $index );
			}
		}

		return array( $find, $replace );
	}

	public function count () {
		return $this->argCount;
	}
}


Return current item: CSS Crush