typecho-highlightjs/Plugin.php
2023-09-16 10:32:15 +08:00

189 lines
6.0 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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;
}
}
}