├── Plugin.php ├── README.md ├── ShortCode.php └── TOC.php /Plugin.php: -------------------------------------------------------------------------------- 1 | begin = [__Class__, 'init']; 22 | Typecho_Plugin::factory('Widget_Archive')->handleInit = [__Class__, 'init']; 23 | } 24 | 25 | /** 26 | * 禁用插件方法,如果禁用失败,直接抛出异常 27 | * 28 | * @static 29 | * @access public 30 | * @return void 31 | * @throws Typecho_Plugin_Exception 32 | */ 33 | public static function deactivate(){} 34 | 35 | /** 36 | * 获取插件配置面板 37 | * 38 | * @access public 39 | * @param Typecho_Widget_Helper_Form $form 配置面板 40 | * @return void 41 | */ 42 | public static function config(Typecho_Widget_Helper_Form $form){} 43 | 44 | /** 45 | * 个人用户的配置面板 46 | * 47 | * @access public 48 | * @param Typecho_Widget_Helper_Form $form 49 | * @return void 50 | */ 51 | public static function personalConfig(Typecho_Widget_Helper_Form $form){} 52 | 53 | /** 54 | * 插件初始化 55 | * 56 | * @access public 57 | * @return void 58 | */ 59 | public static function init(){ 60 | require_once 'ShortCode.php'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Typecho ShortCode 短代码插件 2 | Typecho ShortCode 是一款用于自定义短代码的Typecho插件 3 | 4 | [GitHub 地址](https://github.com/moeshin/Typecho-Plugins-ShortCode) | [GitHub 下载](https://codeload.github.com/moeshin/Typecho-Plugins-ShortCode/zip/master) 5 | 6 | 由于Typecho目前自带的MarkDown解析不支持许多HTML标签,可能影响你使用ShortCode短代码 7 | 可以使用其他的MarkDown解析,例如:[Parsedown](https://github.com/erusev/parsedown)([插件](https://github.com/kokororin/typecho-plugin-Parsedown))等等 8 | ## 函数说明 9 | 使用以下函数来自定义短代码,均为公开静态 10 | ### ShortCode::set 11 | 注册短代码,返回一个`ShortCode`实例 12 | 13 | 参数名|类型|说明 14 | :-|:-|:- 15 | names|mixed|短代码名称,可以一个字符串或字符串数组 16 | callbacks|mixed|短代码对应回调函数,可以一个回调函数或回调函数数组 17 | overried|bool|覆盖已存在的短代码设置
可选,默认`false` 18 | ### ShortCode::get 19 | 获取已注册短代码列表,返回数组,格式例如: 20 | ```php 21 | array{ 22 | [短代码名称] => 回调函数或回调函数名 23 | ... 24 | } 25 | ``` 26 | ### ShortCode::remove 27 | 移除已注册的短代码,返回一个`ShortCode`实例 28 | 29 | 参数名|类型|说明 30 | :-|:-|:- 31 | names|string|短代码名称 32 | callbacks|callback|只有回调函数相同,短代码才会被移除
可选,默认`null` 33 | ### ShortCode::removeAll 34 | 移除所有已注册短的代码,返回一个`ShortCode`实例 35 | ### ShortCode::isForce 36 | 是否强制处理内容,返回布尔值,当前设置 37 | 使用此插件后Markdown或AutoP失效,使用此函数,并传入`true`值 38 | 39 | 参数名|类型|说明 40 | :-|:-|:- 41 | bool|bool|可选,默认`null` 42 | ### ShortCode::handle 43 | 字符串处理,返回字符串 44 | 45 | 参数名|类型|说明 46 | :-|:-|:- 47 | content|string|要处理的字符串 48 | ## 短代码回调函数参数说明 49 | 参数名|类型|说明 50 | :-|:-|:- 51 | name|string|短代码名称 52 | attr|string|短代码属性 53 | text|string|短代码内容 54 | code|string|整条短代码内容 55 | ## 注册短代码栗子 56 | ### \#1 一个对一个 57 | ```php 58 | ShortCode::set('video',function ShorCode($name,$attr,$text,$code){ 59 | return ''; 60 | }); 61 | ``` 62 | ### \#2 多个对一个 63 | ```php 64 | ShortCode::set(['video','audio'],'ShorCode'); 65 | function ShorCode($name,$attr,$text,$code){ 66 | switch($name){ 67 | case 'video': 68 | return ''; 69 | case 'audio': 70 | return ''; 71 | } 72 | return $code; 73 | } 74 | ``` 75 | ## [TOC]自动生成目录说明 76 | 上下不要有文本,自己占一行,与``写法一样 77 | 在文章列表里不显示也不生成目录 78 | 79 | ### 举个栗子 80 | MarkDown: 81 | ```markdown 82 | [TOC] 83 | # 文章大标题 84 | ## 文章中标题 85 | ### 文章小标题 86 | ... 87 | ``` 88 | HTML: 89 | ```html 90 |
91 | 目录 92 |
    93 |
  1. 94 | 文章大标题 95 |
      96 |
    1. 97 | 文章中标题 98 |
        99 |
      1. 100 | 文章小标题 101 |
      2. 102 |
      103 |
    2. 104 |
    105 |
  2. 106 |
107 |
108 |

文章大标题

109 |

文章中标题

110 |

文章小标题

111 |

...

112 | ``` 113 | 114 | ## 更新 115 | **2018.03.24** 116 | - 添加[TOC]自动生成目录功能 117 | - 支持短代码转义(在短代码前加上反斜杠) -------------------------------------------------------------------------------- /ShortCode.php: -------------------------------------------------------------------------------- 1 | content = ['ShortCode', 'content']; 4 | Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = ['ShortCode', 'contentEx']; 5 | require_once 'TOC.php'; 6 | 7 | /** 8 | * Short Code 9 | * 10 | * @package ShortCode 11 | * @author 小さな手は 12 | * @version 1.0.1 13 | * @link https://www.littlehands.site/ 14 | */ 15 | class ShortCode{ 16 | 17 | /** 18 | * 已注册的短代码列表 19 | * 20 | * @access private 21 | * @var array 22 | */ 23 | private static $ShortCodes = []; 24 | 25 | /** 26 | * 实例 27 | * 28 | * @access private 29 | * @var array 30 | */ 31 | private static $instance = null; 32 | 33 | /** 34 | * 是否强制处理文本 35 | * 36 | * @access public 37 | * @var bool 38 | */ 39 | public static $isForce = false; 40 | 41 | /** 42 | * 注册短代码 43 | * 44 | * @access public 45 | * @param mixed $names 短代码名称,可以一个字符串或字符串数组 46 | * @param mixed $callbacks 短代码对应回调函数,可以一个回调函数或回调函数数组 47 | * @param bool $overried 覆盖已注册的短代码
可选,默认false 48 | * @return ShortCode 49 | */ 50 | public static function set($names,$callbacks,$overried = false){ 51 | if(!is_array($names)) $names = [$names]; 52 | if(!is_array($callbacks)) $callbacks = [$callbacks]; 53 | $i = count($callbacks)-1; 54 | foreach($names as $j => $name){ 55 | $k = $j; 56 | if($i<$j) $k = $i; 57 | $callback = $callbacks[$k]; 58 | if(!array_key_exists($name,self::$ShortCodes)||$overried) 59 | self::$ShortCodes[$name] = $callback; 60 | } 61 | return self::instance(); 62 | } 63 | 64 | /** 65 | * 移除短代码 66 | * 67 | * @access public 68 | * @param string $name 短代码名称 69 | * @param callback $callback 只有回调函数相同,短代码才会被移除
可选,默认Null 70 | * @return ShortCode 71 | */ 72 | public static function remove($name,$callback = null){ 73 | if(isset(self::$ShortCodes[$name])) 74 | if(self::$ShortCodes[$name] === $callback||empty($callback)) 75 | unset(self::$ShortCodes[$name]); 76 | return self::instance(); 77 | } 78 | 79 | /** 80 | * 移除所有短代码 81 | * 82 | * @access public 83 | * @return ShortCode 84 | */ 85 | public static function removeAll(){ 86 | self::$ShortCodes[] = []; 87 | return self::instance(); 88 | } 89 | 90 | /** 91 | * 获取短代码列表 92 | * 93 | * @access public 94 | * @return array 95 | */ 96 | public static function get(){ 97 | return self::$ShortCodes; 98 | } 99 | 100 | /** 101 | * 强制处理文本 102 | * 使用此插件后Markdown或AutoP失效,使用此函数,并传入true值 103 | * @access public 104 | * @param bool 105 | * @return bool 106 | */ 107 | public static function isForce($bool = null){ 108 | if(is_bool($bool)) self::$isForce = $bool; 109 | return self::$isForce; 110 | } 111 | 112 | /** 113 | * 文本处理 114 | * 115 | * @access public 116 | * @param string 117 | * @retur string 118 | */ 119 | public static function handle($content){ 120 | $pattern = []; 121 | $RegExp = '((?:"[^"]*"|'."'[^']*'|[^'".'"\]])*)'; 122 | foreach(array_keys(self::$ShortCodes) as $name) 123 | array_push($pattern, 124 | "#\\\\\[|\[($name)$RegExp\]([\s\S]*?)\[/$name\]#i", 125 | "#\\\\\[|\[($name)$RegExp\]()#i" 126 | ); 127 | return preg_replace_callback($pattern,function($a){ 128 | if(count($a) == 1) 129 | return $a[0]; 130 | $name = strtolower($a[1]); 131 | $ShortCodes = self::$ShortCodes; 132 | $callback = $ShortCodes[$name]; 133 | if(array_key_exists($name,$ShortCodes)&&is_callable($callback)) 134 | return call_user_func($callback, $name, $a[2], trim($a[3]), $a[0]); 135 | else 136 | return $a[0]; 137 | },$content); 138 | } 139 | 140 | /** 141 | * 插件处理 content 142 | * 143 | * @access public 144 | * @param string 145 | * @param Widget_Abstract_Contents 146 | * @param string 147 | * @return string 148 | */ 149 | public static function content($content,$archive,$last){ 150 | if($last) $content = $last; 151 | $content = self::handle($content); 152 | if(Typecho_Plugin::export()['handles']['Widget_Abstract_Contents:content'] === [[__Class__,__Function__]]||self::$isForce) 153 | return $archive->isMarkdown?$archive->markdown($content):$archive->autoP($content); 154 | return $content; 155 | } 156 | 157 | /** 158 | * 插件处理 contentEx 159 | * 160 | * @access public 161 | * @param string 162 | * @param Widget_Abstract_Contents 163 | * @param string 164 | * @return string 165 | */ 166 | public static function contentEx($content,$archive,$last){ 167 | if($last) $content = $last; 168 | return TOC::build($content,$archive->is('single')); 169 | } 170 | 171 | /** 172 | * 获取实例 173 | * 174 | * @access private 175 | * @return ShortCode 176 | */ 177 | private static function instance(){ 178 | return self::$instance?self::$instance:new ShortCode(); 179 | } 180 | 181 | /** 182 | * 构造函数 183 | * 184 | * @access public 185 | */ 186 | public function __construct(){ 187 | self::$instance = $this; 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /TOC.php: -------------------------------------------------------------------------------- 1 | loadHTML(''.$content.''); 41 | libxml_use_internal_errors(false); 42 | 43 | if(self::$xpath){ 44 | self::$xpath->__construct($dom); 45 | $xpath = self::$xpath; 46 | }else 47 | self::$xpath = $xpath = new DOMXPath($dom); 48 | $objs = $xpath->query('//h1|//h2|//h3|//h4|//h5|//h6'); 49 | if (!$objs->length) 50 | return $content; 51 | $arr = []; 52 | $html = '
目录'; 53 | foreach($objs as $n => $obj){ 54 | $obj->setAttribute('id','TOC'.$n); 55 | self::handle($obj,$n,$arr,$html); 56 | } 57 | foreach($arr as $n) 58 | $html .= ''; 59 | $html .= '
'; 60 | $content = self::html($xpath->document->getElementsByTagName('body')->item(0)); 61 | } 62 | return preg_replace('#

\[toc\]

#i',$html,$content); 63 | } 64 | 65 | /** 66 | * 处理目录 67 | * 68 | * @param DOMElement $obj 69 | * @param int $n 70 | * @param array &$arr 71 | * @param string &$html 72 | * @return void 73 | */ 74 | public static function handle($obj,$n,&$arr,&$html){ 75 | $i = str_replace('h','',$obj->tagName); 76 | $j = end($arr); 77 | if($i > $j){ 78 | $arr[] = $i; 79 | $html .= '
    '; 80 | }else if($i == $j) 81 | $html .= ''; 82 | else if(in_array($i,$arr)){ 83 | $html .= '
'; 84 | array_pop($arr); 85 | self::handle($obj,$n,$arr,$html); 86 | return; 87 | }else{ 88 | $arr = [$i]; 89 | $html .= ''; 90 | } 91 | $html .= '
  • '.$obj->textContent.''; 92 | } 93 | 94 | /** 95 | * 获取DOMDocument的HTML 96 | * 97 | * @param DOMElement $obj 98 | * @return string 99 | */ 100 | public static function html($obj){ 101 | $dom = self::$dom?self::$dom:(self::$dom = new DOMDocument()); 102 | $html = ''; 103 | foreach ($obj->childNodes as $child) 104 | $html .= $dom->saveHTML($child); 105 | return $html; 106 | } 107 | } 108 | ?> --------------------------------------------------------------------------------