/** * * validate css selector * @param array $token */ public function validateSelector($token) { $tokens = $this->getInstance("Fl_Css_SelectorToken", $token['value'])->run(); $maxSelectorLevel = intval($this->options['selector_max_level']); foreach ($tokens as $selectorItem) { if ($maxSelectorLevel && count($selectorItem) > $maxSelectorLevel) { $selector = Fl_Css_Static::selectorTokenToText($selectorItem); $this->addMessage('selector `' . $selector['text'] . '` level can not max ' . $maxSelectorLevel, 'selector_max_level', array('line' => $token['line'] + $selector['line'], 'col' => $selector['col'])); } foreach ($selectorItem as $item) { if ($item['type'] === FL_TOKEN_CSS_SELECTOR_CLASS) { if (!preg_match($this->options['class_pattern'], $item['value'])) { $this->addMessage('`' . $item['value'] . '` is not valid', 'class_pattern', array('line' => $token['line'] + $item['line'], 'col' => $item['col'])); } } else { if ($item['type'] === FL_TOKEN_CSS_SELECTOR_ID) { if (!preg_match($this->options['id_pattern'], $item['value'])) { $this->addMessage('`' . $item['value'] . '` is not valid', 'id_pattern', array('line' => $token['line'] + $item['line'], 'col' => $item['col'])); } } } } } }
/** * * get key frames * @param array $t */ public function getKeyFrames($token = array()) { $result = array(); while (true) { $t = $this->tokenInstance->getNextToken(); if (empty($t) || $t['type'] === FL_TOKEN_CSS_BRACES_TWO_END) { break; } if ($t['type'] !== FL_TOKEN_CSS_BRACES_TWO_START) { $result[] = $t; } } $text = Fl_Css_Static::selectorTokenToText($result, false); preg_match($this->keyFramesPattern, $token['value'], $matches); $type = $matches[1]; if (empty($type)) { $type = 'w3c'; } $name = strtolower($matches[2]); if (isset($this->keyframesList[$name])) { return $token['value'] . '{' . $text . '}'; } $output = ''; if (in_array($type, $this->completeAttrs['keyframes'])) { $output = $token['value'] . '{' . $text . '}'; } $this->keyframesList[$name] = true; $extTypes = array(); $searchText = substr($this->text, $token['pos']); foreach ($this->completeAttrs['keyframes'] as $item) { if (!$this->options[$item] || $item == $type) { continue; } if ($item == 'w3c') { $pattern = '/@keyframes\\s+' . $name . '/ies'; } else { $pattern = '/@\\-' . $item . '\\-keyframes\\s+' . $name . '/ies'; } //这里为了方便直接通过正则向后匹配 if (preg_match($pattern, $searchText)) { continue; } $instance = $this->getInstance("Fl_Css_AutoComplete", $text); $options = array('w3c' => false, 'webkit' => false, 'moz' => false, 'ms' => false, 'o' => false, 'opacity' => false, 'keyframes' => true); $options[$item] = true; if ($item == 'ms') { $options['opacity'] = true; } $return = $instance->run($options); if ($item == 'w3c') { $output .= '@keyframes ' . $name; } else { $output .= '@-' . $item . '-keyframes ' . $name; } $output .= '{' . $return . '}'; } return $output; }
/** * * collection selector * @param array $token * @param int $selectorPos */ public function collectionSelector($token, $selectorPos = 0) { $attrs = $this->getSelectorProperties(); if ($this->options['remove_empty_selector'] && empty($attrs)) { return true; } $detail = array('attrs' => $attrs, 'score' => 0, 'equal' => array(), 'pos' => $selectorPos++); $result = $this->getInstance('Fl_Css_SelectorToken', $token['value'])->run(); if ($this->removeUnusedClass) { $removeResult = array(); foreach ($result as $item) { $last = $item[count($item) - 1]; if ($last['type'] === FL_TOKEN_CSS_SELECTOR_CLASS) { $classValue = substr($last['value'], 1); if (in_array($classValue, $this->useClassList)) { $removeResult[] = $item; } } else { $removeResult[] = $item; } } if (empty($removeResult)) { return true; } $result = $removeResult; } if (count($result) === 1) { //only a tag if (!$this->inKeyframes && count($result[0]) === 1 && $result[0][0]['type'] === FL_TOKEN_CSS_SELECTOR_TYPE) { $value = strtolower($result[0][0]['value']); $se = array_merge($detail, array("selector" => $value, "score" => 1)); if (!isset($this->tagMultis[$value])) { if (isset($this->selectors[$value])) { $attrs = Fl_Css_Static::mergeProperties($this->selectors[$value]['attrs'], $attrs); $this->selectors[$value]['attrs'] = $attrs; } else { /*$this->selectors = array_merge ( array ( $value => $se ), $this->selectors );*/ $this->selectors[$value] = $se; } } else { $this->selectors[$value . "%" . $selectorPos++] = $se; } } else { $selector = Fl_Css_Static::selectorTokenToText($result[0], false); $detail['selector'] = $selector; $detail['score'] = Fl_Css_Static::getSelectorSpecificity($result[0], true); $this->selectors[$selector . "%" . $selectorPos++] = $detail; } } else { $every = true; $sts = array(); foreach ($result as $item) { if (count($item) === 1 && $item[0]['type'] === FL_TOKEN_CSS_SELECTOR_TYPE) { $sts[strtolower($item[0]['value'])] = 1; } else { $every = false; } } $selectors = array(); $score = -1; $same = true; foreach ($result as $item) { $selectors[] = Fl_Css_Static::selectorTokenToText($item, false); $s = Fl_Css_Static::getSelectorSpecificity($item, true); if ($score != -1 && $score !== $s) { $same = false; } if ($score === -1) { $score = $s; } } $selector = join(",", $selectors); if ($every) { if (isset($this->selectors[$selector])) { $attrs = Fl_Css_Static::mergeProperties($this->selectors[$selector]['attrs'], $attrs); $this->selectors[$selector]['attrs'] = $attrs; } else { $detail['selector'] = array_shift($selectors); $detail['score'] = 1; $detail['same_score'] = true; $detail['equal'] = $selectors; /*$this->selectors = array_merge ( array ( $selector => $detail ), $this->selectors );*/ $this->selectors[$selector] = $detail; } } else { $this->tagMultis = array_merge($this->tagMultis, $sts); $detail['selector'] = array_shift($selectors); $detail['equal'] = $selectors; $detail['same_score'] = $same; $detail['score'] = $score; $this->selectors[$selector . "%" . $selectorPos++] = $detail; } } }
/** * * moz hack里的css直接返回 * @param array $token */ public function getMozHack($token = array()) { $tokens = array(); $result = $token['value']; while (true) { $token = $this->tokenInstance->getNextToken(); if (empty($token)) { break; } $tokens[] = $token; if ($token['type'] === FL_TOKEN_CSS_BRACES_TWO_END) { break; } } $result .= Fl_Css_Static::selectorTokenToText($tokens, false); return array('ie6' => '', 'css3' => $result); }