* @license https://raw2.github.com/soloproyectos/php.common-libs/master/LICENSE BSD 2-Clause License * @link https://github.com/soloproyectos/php.common-libs */ namespace com\soloproyectos\common\css\parser\filter; use \DOMElement; use com\soloproyectos\common\css\parser\filter\CssParserFilter; /** * Class CssParserFilterAttr. * * This class represents the attribute filter. * * @category Css * @package CssParser * @author Gonzalo Chumillas * @license https://raw2.github.com/soloproyectos/php.common-libs/master/LICENSE BSD 2-Clause License * @link https://github.com/soloproyectos/php.common-libs */ class CssParserFilterAttr extends CssParserFilter { const EQUAL_SELECTOR = '='; const NOT_EQUAL_SELECTOR = '!='; const CONTAIN_SELECTOR = '*='; const CONTAIN_WORD_SELECTOR = '~='; const CONTAIN_PREFIX_SELECTOR = '|='; const START_WITH_SELECTOR = '^='; const END_WITH_SELECTOR = '$='; /** * List of operators * @static * @var array of strings */ private static $_operators = array( CssParserFilterAttr::EQUAL_SELECTOR, CssParserFilterAttr::NOT_EQUAL_SELECTOR, CssParserFilterAttr::CONTAIN_SELECTOR, CssParserFilterAttr::CONTAIN_WORD_SELECTOR, CssParserFilterAttr::CONTAIN_PREFIX_SELECTOR, CssParserFilterAttr::START_WITH_SELECTOR, CssParserFilterAttr::END_WITH_SELECTOR ); /** * Attribute name. * @var string */ private $_attrName; /** * Operator. * @var string */ private $_op; /** * Value. * @var string */ private $_value; /** * Constructor. * * @param string $attrName Attribute name * @param string $op Operator * @param string $value A value */ public function __construct($attrName, $op, $value) { $this->_attrName = $attrName; $this->_op = $op; $this->_value = $value; } /** * Gets a list of available operators. * * @static * @return array of strings */ public static function getOperators() { return self::$_operators; } /** * Equal selector. * * Selects elements that have the specified attribute with a value exactly equal * to a certain value. * * @param DOMElement $node DOMElement object * * @link http://api.jquery.com/attribute-equals-selector/ * @return boolean */ private function _isEqualSelector($node) { return $node->hasAttribute($this->_attrName) && $node->getAttribute($this->_attrName) == $this->_value; } /** * Not equal selector. * * Select elements that either don't have the specified attribute, or do have * the specified attribute but not with a certain value. * * @param DOMElement $node DOMElement object * * @link http://api.jquery.com/attribute-not-equal-selector/ * @return boolean */ private function _isNotEqualSelector($node) { return !$node->hasAttribute($this->_attrName) || $node->getAttribute($this->_attrName) != $this->_value; } /** * Contain selector. * * Selects elements that have the specified attribute with a value containing * the a given substring. * * @param DOMElement $node DOMElement object * * @link http://api.jquery.com/attribute-contains-selector/ * @return boolean */ private function _isContainSelector($node) { if ($node->hasAttribute($this->_attrName)) { $attr = $node->getAttribute($this->_attrName); $len = strlen($this->_value); if ($len > 0) { $pos = strpos($attr, $this->_value); return $pos !== false; } } return false; } /** * Contain word selector. * * Selects elements that have the specified attribute with a value containing a * given word, delimited by spaces. * * @param DOMElement $node DOMElement object * * @link http://api.jquery.com/attribute-contains-word-selector/ * @return boolean */ private function _isContainWordSelector($node) { if ($node->hasAttribute($this->_attrName)) { $items = explode(" ", trim($node->getAttribute($this->_attrName))); foreach ($items as $item) { if (preg_match("/^\w+$/", $item) && $this->_value == $item) { return true; } } } return false; } /** * Contain prefix selector. * * Selects elements that have the specified attribute with a value either equal * to a given string or starting with that string followed by a hyphen (-). * * @param DOMElement $node DOMElement object * * @link http://api.jquery.com/attribute-contains-prefix-selector/ * @return boolean */ private function _isContainPrefixSelector($node) { if ($node->hasAttribute($this->_attrName)) { $attr = $node->getAttribute($this->_attrName); $len = strlen($this->_value); if ($len > 0) { $pos = stripos($attr, $this->_value); return $pos === 0 && (strlen($attr) <= $len || $attr[$len] == "-"); } } return false; } /** * Start with selector. * * Selects elements that have the specified attribute with a value beginning * exactly with a given string. * * @param DOMElement $node DOMElement object * * @link http://api.jquery.com/attribute-starts-with-selector/ * @return boolean */ private function _isStartWithSelector($node) { if ($node->hasAttribute($this->_attrName) && strlen($this->_value) > 0) { $attrValue = $node->getAttribute($this->_attrName); return strpos($attrValue, $this->_value) === 0; } return false; } /** * End with selector. * * Selects elements that have the specified attribute with a value ending * exactly with a given string. The comparison is case sensitive. * * @param DOMElement $node DOMElement object * * @link http://api.jquery.com/attribute-ends-with-selector/ * @return boolean */ private function _isEndWithSelector($node) { if ($node->hasAttribute($this->_attrName)) { $len = strlen($this->_value); if ($len > 0) { $attr = $node->getAttribute($this->_attrName); $attrLen = strlen($attr); return $len <= $attrLen && strpos($attr, $this->_value, $attrLen - $len) !== false; } } return false; } /** * Does the node has the attribute? * * @param DOMElement $node DOMElement object * * @return boolean */ private function _hasAttribute($node) { return $node->hasAttribute($this->_attrName); } /** * Is an attribute selector? * * @param DOMElement $node DOMElement object * * @return boolean */ private function _isAttrSelector($node) { $ret = false; if ($this->_op == CssParserFilterAttr::EQUAL_SELECTOR) { $ret = $this->_isEqualSelector($node); } elseif ($this->_op == CssParserFilterAttr::NOT_EQUAL_SELECTOR) { $ret = $this->_isNotEqualSelector($node); } elseif ($this->_op == CssParserFilterAttr::CONTAIN_SELECTOR) { $ret = $this->_isContainSelector($node); } elseif ($this->_op == CssParserFilterAttr::CONTAIN_WORD_SELECTOR) { $ret = $this->_isContainWordSelector($node); } elseif ($this->_op == CssParserFilterAttr::CONTAIN_PREFIX_SELECTOR) { $ret = $this->_isContainPrefixSelector($node); } elseif ($this->_op == CssParserFilterAttr::START_WITH_SELECTOR) { $ret = $this->_isStartWithSelector($node); } elseif ($this->_op == CssParserFilterAttr::END_WITH_SELECTOR) { $ret = $this->_isEndWithSelector($node); } else { $ret = $this->_hasAttribute($node); } return $ret; } /** * Does the node match? * * @param DOMElement $node DOMElement object * @param integer $position Node position * @param array $items List of nodes * * @return boolean */ public function match($node, $position, $items) { return $this->_isAttrSelector($node); } }