/** * * 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; }
/** * * @param array $token */ public function checkHtmlTokens() { $tokens = $this->getTokens('html'); foreach ($tokens as $item) { if ($item['type'] === FL_TOKEN_HTML_TAG_START) { $attrTokens = $this->getInstance("Fl_Html_TagToken", $item['value'])->run(); $tagName = strtolower($attrTokens['tag']); $tag = '<' . $attrTokens['tag'] . FL_SPACE; $attrTokens = $attrTokens['attrs']; foreach ($attrTokens as $attrItem) { $count = count($attrItem); $attr = strtolower($attrItem[0]); if ($count == 1) { $tag .= $this->checkIt(array_merge($item, array('value' => $attrItem[0])), 'html') . FL_SPACE; } elseif ($count === 3) { if ($attr && strpos($attr, 'on') === 0) { $type = 'event'; } elseif ($attr === 'src' || $attr === 'href' || $tagName === 'form' && $attr === 'action') { $type = 'url'; } else { $type = 'html'; } $value = $this->checkIt(array_merge($item, array('value' => $attrItem[2])), $type); $tag .= $attrItem[0] . '=' . $value . FL_SPACE; } } $tag = trim($tag) . ">"; $item['value'] = $tag; } else { if ($item['type'] === FL_TOKEN_HTML_SCRIPT_TAG) { //这里要判断是否是前端模版 $detail = Fl_Html_Static::splitSpecialValue($item['value'], 'script', $this); $tagInfo = Fl_Html_Static::getScriptTagInfo($detail['tag_start'], $this); //前端模版用HTML转义 if ($tagInfo['tpl']) { $item['value'] = $this->checkIt($item, 'html'); } else { $item['value'] = $this->checkIt($item, 'js'); } } else { $item['value'] = $this->checkIt($item, 'html'); } } $this->addOutput($item); } }
/** * * compress script * @param array $token */ public function compressScript($token) { if (!$this->options['compress_tag']) { return $token['value']; } $info = Fl_Html_Static::splitSpecialValue($token['value'], 'script', $this); $content = $info['content']; $tagInfo = Fl_Html_Static::getScriptTagInfo($info['tag_start'], $this); $isExternal = $tagInfo['external']; $isScript = $tagInfo['script']; //移除空的script标签 if ($this->options['remove_empty_script']) { if (!$isExternal && empty($content)) { return ''; } } //压缩内联的JS if ($this->options['compress_inline_js']) { if ($content && !$isExternal && $isScript) { $containTpl = $this->containTpl($content); //自定义内联JS压缩方法 if (!$containTpl && $this->jsCompressMethod) { $compressContent = call_user_func($this->jsCompressMethod, $content, $this); } else { $compressContent = $this->getInstance("Fl_Js_Compress", $content)->run(); } if (!empty($compressContent) && !is_array($compressContent)) { $content = $compressContent; } } } //移除可选的属性 if ($this->options['remove_optional_attrs']) { $tagInfo['lowerTag'] = strtolower($tagInfo['tag']); $info['tag_start'] = $this->compressStartTag($tagInfo); } //合并相邻的script标签 if ($this->options['merge_adjacent_js']) { if ($isScript && !$isExternal && $this->preIsScript && $this->preIsScript['script'] && !$this->preIsScript['external']) { $endStyle = '</script>'; $outputLen = strlen($this->output); $last = substr($this->output, $outputLen - 9); if (strtolower($last) === $endStyle) { $this->output = rtrim(substr($this->output, 0, $outputLen - 9), ";"); return ';' . rtrim($content, ";") . $info['tag_end']; } } } //不移除CDATA if (!$this->options['remove_inline_js_cdata'] || $this->isXML) { $content = $info['cprefix'] . $content . $info['csuffix']; } //压缩前端模版 if ($this->options['compress_tpl_script']) { if ($tagInfo['tpl'] && !$tagInfo['external'] && $this->jsTplCompressMethod) { $c = call_user_func($this->jsTplCompressMethod, $content, $this); if (!empty($c)) { $content = $c; } } } $this->preIsScript = $tagInfo; return $info['tag_start'] . $content . $info['tag_end']; }