<?php namespace TypechoPlugin\HighlightJs; use Typecho\Plugin\PluginInterface; use Typecho\Widget\Helper\Form; use Utils\Helper; use Widget\Archive; use Widget\Base\Comments; use Widget\Base\Contents; if (!defined('__TYPECHO_ROOT_DIR__')) { exit; } /** * Highlight.JS插件,智能实现代码高亮 * * @package Highlight Js * @author joyqi * @version 1.1.0 * @since 1.2.0 * @link https://github.com/joyqi/typecho-plugins */ class Plugin implements PluginInterface { /** * 激活插件方法,如果激活失败,直接抛出异常 */ public static function activate() { Contents::pluginHandle()->contentEx = __CLASS__ . '::parse'; Contents::pluginHandle()->excerptEx = __CLASS__ . '::parse'; Comments::pluginHandle()->contentEx = __CLASS__ . '::parse'; Archive::pluginHandle()->header = __CLASS__ . '::header'; Archive::pluginHandle()->footer = __CLASS__ . '::footer'; } /** * 禁用插件方法,如果禁用失败,直接抛出异常 */ public static function deactivate() { } /** * 获取插件配置面板 * * @param Form $form 配置面板 */ public static function config(Form $form) { $compatibilityMode = new Form\Element\Radio('compatibilityMode', [ 0 => _t('不启用'), 1 => _t('启用') ], 0, _t('兼容模式'), _t('兼容模式一般用于对以前没有使用Markdown语法解析的文章')); $form->addInput($compatibilityMode->addRule('enum', _t('必须选择一个模式'), [0, 1])); $styles = array_map('basename', glob(dirname(__FILE__) . '/res/styles/*.css')); $styles = array_combine($styles, $styles); $style = new Form\Element\Select('style', $styles, 'default.css', _t('代码配色样式')); $form->addInput($style->addRule('enum', _t('必须选择配色样式'), $styles)); } /** * 个人用户的配置面板 * * @param Form $form */ public static function personalConfig(Form $form) { } /** * 输出头部css */ public static function header($header, Archive $archive) { if ($archive->is('single')) { $cssUrl = Helper::options()->pluginUrl . '/HighlightJs/res/styles/' . Helper::options()->plugin('HighlightJs')->style; echo '<link rel="stylesheet" type="text/css" href="' . $cssUrl . '" />'; } } /** * 输出尾部js */ public static function footer(Archive $archive) { if ($archive->is('single')) { $jsUrl = Helper::options()->pluginUrl . '/HighlightJs/res/highlight.min.js'; echo '<script type="text/javascript" src="' . $jsUrl . '"></script>'; echo '<script type="text/javascript">window.onload = function () { var codes = document.getElementsByTagName("pre"), hlNames = { actionscript : /^as[1-3]$/i, cmake : /^(make|makefile)$/i, cs : /^csharp$/i, css : /^css[1-3]$/i, delphi : /^pascal$/i, javascript : /^js$/i, markdown : /^md$/i, objectivec : /^objective\-c$/i, php : /^php[1-6]$/i, sql : /^mysql$/i, xml : /^(html|html5|xhtml)$/i }, hlLangs = hljs.LANGUAGES; for (var i = 0; i < codes.length; i ++) { var children = codes[i].getElementsByTagName("code"), highlighted = false; if (children.length > 0) { var code = children[0], className = code.className; if (!!className) { if (0 == className.indexOf("language-")) { var lang = className.substring(5).toLowerCase(), finalLang; if (hlLangs[lang]) { finalLang = lang; } else { for (var l in hlNames) { if (lang.match(hlNames[l])) { finalLang = l; } } } if (!!finalLang) { var result = hljs.highlight(finalLang, code.textContent, true); code.innerHTML = result.value; highlighted = true; } } } if (!highlighted) { var html = code.innerHTML; code.innerHTML = html.replace(/<\/?[a-z]+[^>]*>/ig, ""); hljs.highlightElement(code); } } } }</script>'; } } /** * 插件实现方法 * * @access public * @return string */ public static function parse($text, $widget, $lastResult): string { $text = empty($lastResult) ? $text : $lastResult; if (!Helper::options()->plugin('HighlightJs')->compatibilityMode) { return $text; } if ($widget instanceof Archive || $widget instanceof Comments) { $isMarkdown = $widget instanceof Comments ? Helper::options()->commentsMarkdown : $widget->isMarkdown; return preg_replace_callback("/<(code|pre)(\s*[^>]*)>(.*?)<\/\\1>/is", function ($matches) use ($isMarkdown) { if ('code' == $matches[1] && !$isMarkdown) { $language = $matches[2]; if (!empty($language)) { if (preg_match("/^\s*(class|lang|language)=\"(?:lang-|language-)?([_a-z0-9-]+)\"$/i", $language, $out)) { $language = ' class="' . trim($out[2]) . '"'; } elseif (preg_match("/\s*([_a-z0-9]+)/i", $language, $out)) { $language = ' class="language-' . trim($out[1]) . '"'; } } return "<pre><code{$language}>" . htmlspecialchars(trim($matches[3])) . "</code></pre>"; } return $matches[0]; }, $text); } else { return $text; } } }