public function test3()
 {
     $this->getFlInstance();
     $tokens = $this->getTokens('3.text');
     $tokens = $tokens[0];
     $score = Fl_Css_Static::getSelectorSpecificity($tokens);
     //print_r($score);
 }
Example #2
0
 /**
  * 
  * 获取选择器的属性
  */
 public function getSelectorProperties()
 {
     $attr = $value = '';
     $attrs = array();
     $hasColon = false;
     $hasTpl = false;
     while (true) {
         $token = $this->tokenInstance->getNextToken();
         if (empty($token)) {
             break;
         }
         if ($token['type'] === FL_TOKEN_CSS_PROPERTY) {
             $attr = $token['value'];
         } elseif ($token['type'] === FL_TOKEN_CSS_COLON) {
             $hasColon = true;
         } elseif ($token['type'] === FL_TOKEN_CSS_VALUE) {
             $value = $token['value'];
         } elseif ($token['type'] === FL_TOKEN_TPL) {
             if ($hasColon) {
                 $value .= $token['value'];
             } else {
                 $attr .= $token['value'];
             }
             $hasTpl = true;
         } elseif ($token['type'] === FL_TOKEN_CSS_HACK) {
             $attrs[] = array('property' => '', 'value' => $token['value'], 'type' => FL_TOKEN_CSS_HACK);
         } elseif ($token['type'] === FL_TOKEN_CSS_SEMICOLON || $token['type'] === FL_TOKEN_CSS_BRACES_ONE_END) {
             if ($hasTpl || $this->containTpl($attr)) {
                 $attrs[] = array('property' => $attr, 'value' => $value, 'type' => FL_TOKEN_TPL);
             } else {
                 if (!empty($attr) || !empty($value)) {
                     $propertyDetail = Fl_Css_Static::getPropertyDetail($attr);
                     $valueDetail = Fl_Css_Static::getValueDetail($value);
                     $detail = $propertyDetail + $valueDetail;
                     $attrs[] = $detail;
                 }
             }
             $hasTpl = $hasColon = false;
             $attr = $value = '';
         }
         if ($token['type'] === FL_TOKEN_CSS_BRACES_ONE_END) {
             break;
         }
     }
     return $attrs;
 }
Example #3
0
 /**
  * 
  * beautify
  * @param array $ast
  */
 public function beautifyAst($ast, $parentType = '')
 {
     $result = '';
     $first = true;
     foreach ($ast as $item) {
         if (!$first) {
             $result = rtrim($result, FL_NEWLINE) . FL_NEWLINE;
         }
         $hasComment = false;
         if (count($item['value']['commentBefore'])) {
             $hasComment = true;
         }
         $comment = $this->beautifyComment($item['value']);
         if ($comment['remove']) {
             $result = rtrim($result, FL_NEWLINE);
         }
         $result .= $comment['value'];
         //
         if ($item['type'] === FL_TOKEN_HTML_TAG_END) {
             continue;
         }
         if ($first) {
             $first = false;
         }
         $indent = $newline = false;
         if ($item['type'] === FL_TOKEN_HTML_TAG) {
             $count = count($item['children']);
             if ($count > 1) {
                 $indent = true;
                 $newline = true;
             } elseif ($count === 1) {
                 $c = $item['children'][$count - 1];
                 if ($c['type'] !== FL_TOKEN_HTML_TEXT) {
                     $indent = true;
                     $newline = true;
                 }
             }
         } else {
             if (count($ast) > 1) {
                 $newline = true;
             }
             if ($item['type'] === FL_TOKEN_HTML_DOCTYPE || $item['type'] === FL_TOKEN_HTML_SINGLE_TAG) {
                 $newline = true;
             }
             if ($item['type'] === FL_TOKEN_HTML_STYLE_TAG || $item['type'] === FL_TOKEN_HTML_SCRIPT_TAG) {
                 $newline = true;
                 $indent = true;
             }
         }
         if ($item['type'] !== FL_TOKEN_HTML_TEXT) {
             $result .= $this->getIndentString();
         } else {
             if (count($ast) > 1) {
                 $result .= $this->getIndentString();
             }
         }
         if ($parentType === FL_TOKEN_HTML_STYLE_TAG) {
             Fl::loadClass("Fl_Css_Static");
             $value = Fl_Css_Static::getStyleDetail($item['value']['value']);
             if ($value['prefix']) {
                 $result .= $value['prefix'] . FL_NEWLINE;
             }
             $result .= $this->beautify_special($value['value'], 'css');
             if ($value['suffix']) {
                 $result .= FL_NEWLINE . $value['suffix'] . FL_NEWLINE;
             }
         } elseif ($parentType === FL_TOKEN_HTML_SCRIPT_TAG) {
             $result .= $this->beautify_special($item['value']['value'], 'js');
         } else {
             $result .= $item['value']['value'];
         }
         if ($newline) {
             $result .= FL_NEWLINE;
         }
         if ($indent) {
             $this->indent++;
         }
         if (count($item['children'])) {
             $type = $item['type'];
             if ($type === FL_TOKEN_HTML_SCRIPT_TAG) {
                 $tagInfo = Fl_Html_Static::getScriptTagInfo($item['value']['value'], $this);
                 //虽然是script标签,但不一定是Js
                 if (!$tagInfo['script'] || $tagInfo['external']) {
                     $type = '';
                 }
             }
             $children = $this->beautifyAst($item['children'], $type);
             if ($tagInfo['external'] && !strlen(trim($children))) {
                 $result = rtrim($result, FL_NEWLINE);
                 $newline = false;
                 $indent = 2;
             } else {
                 $result .= $children;
             }
         }
         $types = array(FL_TOKEN_HTML_TAG => 1, FL_TOKEN_HTML_SCRIPT_TAG => 1, FL_TOKEN_HTML_PRE_TAG => 1, FL_TOKEN_HTML_STYLE_TAG => 1, FL_TOKEN_HTML_TEXTAREA_TAG => 1);
         $this->preToken = $item['value'];
         if (isset($types[$item['type']])) {
             if ($newline) {
                 $result = rtrim($result, FL_NEWLINE);
                 $result .= FL_NEWLINE;
             }
             if ($indent) {
                 $this->indent--;
                 if ($indent === true) {
                     $result .= $this->getIndentString();
                 }
             }
             if (!empty($item['end'])) {
                 $this->preToken = $item['end'];
                 $comment = $this->beautifyComment($item['end']);
                 $result .= rtrim($comment['value'], FL_NEWLINE);
             }
             $result .= '</' . $item['tag'] . '>';
         }
     }
     return $result;
 }
Example #4
0
 /**
  * 
  * 获取@的详细类型
  */
 public function getAtDetailType($result = '')
 {
     return $this->preTokenType = Fl_Css_Static::getAtDetailType($result, $this);
 }
Example #5
0
 /**
  * 
  * get such as :hover token
  * @param string $char
  */
 public function getPseudoClassToken($char)
 {
     $result = $char;
     $this->getNextChar();
     $parenthesesNum = 0;
     while (!$this->isEof()) {
         $char = $this->getCurrentChar();
         if ($parenthesesNum === 0 && Fl_Css_Static::isSelectorCharUtil($char)) {
             break;
         } else {
             if ($char === '(') {
                 $parenthesesNum++;
             } else {
                 if ($char === ')') {
                     $parenthesesNum--;
                 } else {
                     if ($char === '"' || $char === "'") {
                         $char = $this->getQuoteText($char, true, true);
                     }
                 }
             }
         }
         $result .= $char;
         if (!$this->pendingNextChar) {
             $this->getNextChar();
         } else {
             $this->pendingNextChar = false;
         }
     }
     if ($parenthesesNum !== 0) {
         $this->throwException('get Pseudo Class error');
     }
     return $result;
 }
Example #6
0
 /**
  * 
  * short padding,margin properties 
  * @param array $attrs
  */
 public function shortProperties($attrs = array())
 {
     $attrs = Fl_Css_Static::combineProperty($attrs, 'padding', Fl_Css_Static::$paddingChildren);
     $attrs = Fl_Css_Static::combineProperty($attrs, 'margin', Fl_Css_Static::$marginChildren);
     return $attrs;
 }
Example #7
0
 /**
  * 
  * Calculating a selector's specificity
  * see more: http://www.w3.org/TR/selectors/#specificity
  * @param array $selectorTokens
  */
 public static function getSelectorSpecificity($selectorTokens = array())
 {
     if (!is_array($selectorTokens)) {
         $selectorTokens = self::getSelectorTokens($selectorTokens);
     }
     $score = array(0, 0, 0);
     $notPattern = '/^\\:not\\(/ies';
     foreach ($selectorTokens as $item) {
         $type = $item['type'];
         switch ($type) {
             case FL_TOKEN_CSS_SELECTOR_ID:
                 $score[0]++;
                 break;
             case FL_TOKEN_CSS_SELECTOR_TYPE:
             case FL_TOKEN_CSS_SELECTOR_PSEUDO_ELEMENT:
                 $score[2]++;
                 break;
             case FL_TOKEN_CSS_SELECTOR_CLASS:
             case FL_TOKEN_CSS_SELECTOR_ATTRIBUTES:
                 $score[1]++;
                 break;
             case FL_TOKEN_CSS_SELECTOR_PSEUDO_CLASS:
                 $value = $item['value'];
                 //:not(xxx)
                 if (preg_match($notPattern, $value)) {
                     $value = trim(preg_replace($notPattern, "", $value));
                     $value = substr($value, 0, strlen($value) - 1);
                     Fl::loadClass('Fl_Css_SelectorToken');
                     $instance = new Fl_Css_SelectorToken($value);
                     $tokens = $instance->run();
                     $notScore = Fl_Css_Static::getSelectorSpecificity($tokens[0]);
                     $score[0] += $notScore[0];
                     $score[1] += $notScore[1];
                     $score[2] += $notScore[2];
                 } else {
                     $score[1]++;
                 }
                 break;
         }
     }
     return $score;
 }
Example #8
0
 /**
  * 
  * 背景图
  * @param array $tokens
  */
 public function updateBackgroundImageTokenType($tokens)
 {
     foreach ($tokens as &$token) {
         $value = $token['value'];
         $urlValue = Fl_Css_Static::isUrlValue($value);
         if ($urlValue) {
             //背景图
             $token['type'] = 'background-image';
             $token['clean_value'] = $urlValue;
         }
     }
     return $tokens;
 }
Example #9
0
 /**
  * 
  * token值里可能含有color
  * @param array $token
  */
 public static function mayHasColor($token)
 {
     if ($token['type'] != FL_TOKEN_CSS_PROPERTY) {
         return false;
     }
     $value = $token['value'];
     $detail = Fl_Css_Static::getPropertyDetail($value);
     $name = strtolower($detail['property']);
     if (isset(Fl_Css_Static::$mayHasColorProperties[$name])) {
         return true;
     }
     return false;
 }
Example #10
0
 /**
  * 
  * compress style
  * @param array $token
  */
 public function compressStyle($token)
 {
     if (!$this->options['compress_tag']) {
         return $token['value'];
     }
     $info = Fl_Html_Static::splitSpecialValue($token['value'], 'style', $this);
     $content = trim($info['content']);
     if ($this->options['remove_empty_style'] && !$content) {
         return '';
     }
     if ($this->options['compress_inline_css'] && $content) {
         Fl::loadClass("Fl_Css_Static");
         $value = Fl_Css_Static::getStyleDetail($content);
         $containTpl = $this->containTpl($value['value']);
         //自定义内联CSS压缩方法
         if (!$containTpl && $this->cssCompressMethod) {
             $content = call_user_func($this->cssCompressMethod, $value['value'], $this);
         } else {
             $content = $this->getInstance("Fl_Css_Compress", $value['value'])->run();
         }
     }
     if ($this->options['remove_optional_attrs']) {
         $tagInfo = $this->getInstance("Fl_Html_TagToken", $info['tag_start'])->run();
         $tagInfo['lowerTag'] = strtolower($tagInfo['tag']);
         $info['tag_start'] = $this->compressStartTag($tagInfo);
     }
     if ($this->options['merge_adjacent_css']) {
         $endStyle = '</style>';
         $outputLen = strlen($this->output);
         $last = substr($this->output, $outputLen - 8);
         if (strtolower($last) === $endStyle) {
             $this->output = substr($this->output, 0, $outputLen - 8);
             return $content . $info['tag_end'];
         }
     }
     return $info['tag_start'] . $content . $info['tag_end'];
 }
Example #11
0
 /**
  * 
  * validate css property
  * @param array $token
  */
 public function validateProperty($token)
 {
     if (!$this->options['property_hack']) {
         return true;
     }
     if (!Fl_Css_Static::checkPropertyPattern($token['value'])) {
         return $this->addMessage("property `" . $token['value'] . "` is not valid", 'property_hack', $token);
     }
     if (strpos($token['value'], 'filter') !== false) {
         return $this->addMessage("property `" . $token['value'] . "` is not valid", 'filter', $token);
     }
 }
Example #12
0
 /**
  * 
  * beautify default token
  * @param array $token
  */
 public function beautifyDefault($token)
 {
     //for ;;;
     if ($token['type'] === FL_TOKEN_CSS_SEMICOLON && $this->preToken['type'] === FL_TOKEN_CSS_SEMICOLON) {
         return '';
     }
     if (isset($this->preToken['type'])) {
         //for @ type
         if ($token['type'] === FL_TOKEN_CSS_AT_KEYFRAMES || $token['type'] === FL_TOKEN_CSS_AT_MOZILLA) {
             return FL_NEWLINE . $this->getIndentString() . $token['value'];
         } else {
             if (Fl_Css_Static::isAtType($token['type'])) {
                 return FL_NEWLINE . $token['value'];
             }
         }
     }
     if ($token['type'] === FL_TOKEN_CSS_HACK) {
         return FL_NEWLINE . $this->getIndentString() . $token['value'];
     }
     return $token['value'];
 }