Initial commit
Some checks failed
定时更新GitHub源插件 / 自动更新GitHub插件 (push) Has been cancelled

This commit is contained in:
chorblack
2026-03-07 11:19:25 +08:00
commit e75f275ef4
4484 changed files with 645480 additions and 0 deletions

292
MenuTree/Plugin.php Normal file
View File

@@ -0,0 +1,292 @@
<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
* 根据内容标题关系自动生成目录树 【<a href="https://github.com/typecho-fans/plugins" target="_blank">TF</a>社区维护版】
*
* @package Menu Tree
* @author BeaconFire,Melon
* @version 0.1.2
* @link https://github.com/typecho-fans/plugins/tree/master/MenuTree
*/
// 使用方法:
// 在文章某处地方加上<!-- index-menu -->,程序会把这个注释替换成目录树
// 样式:
// .index-menu 整个目录
// .index-menu-list 列表 ul
// .index-menu-item 每个目录项 li
// .index-menu-link 目录项连接 a
// 独立模式下需要在主题模板中调用:$this->treeMenu();
class MenuTree_Plugin implements Typecho_Plugin_Interface
{
/**
* 索引ID
*/
public static $id = 1;
public static $pattern = '/(&lt;|<)!--\s*index-menu\s*--(&gt;|>)/i';
/**
* 标题匹配模式
*/
public static $patternTitle = '/<h([1-6])[^>]*>.*?<\/h\1>/s';
/**
* 目录树
*/
public static $tree = array();
/**
* 激活插件方法,如果激活失败,直接抛出异常
*
* @access public
* @return void
*/
public static function activate()
{
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('MenuTree_Plugin', 'render');
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('MenuTree_Plugin', 'render');
Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array('MenuTree_Plugin', 'contentEx');
Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx = array('MenuTree_Plugin', 'excerptEx');
Typecho_Plugin::factory('Widget_Archive')->___treeMenu = array('MenuTree_Plugin', 'treeMenu');
}
/**
* 禁用插件方法,如果禁用失败,直接抛出异常
*
* @static
* @access public
* @return void
*/
public static function deactivate()
{
//do nothing
}
/**
* 获取插件配置面板
*
* @access public
* @param Typecho_Widget_Helper_Form $form 配置面板
* @return void
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
$type = new Typecho_Widget_Helper_Form_Element_Checkbox('switch',
array('normal' => _t('嵌入模式'), 'single' => _t('独立模式')),
array('normal'),
_t('显示模式'));
$form->addInput($type);
}
/**
* 个人用户的配置面板
*
* @access public
* @param Typecho_Widget_Helper_Form $form
* @return void
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form)
{
//do nothing
}
/**
* 列表页忽略目录生成标记
*
* @access public
* @return string
*/
public static function excerptEx($html, $widget, $lastResult)
{
return self::rmMenuTag($html);
}
/**
* 内容页构造索引目录
*
* @access public
* @return string
* @throws Typecho_Plugin_Exception
*/
public static function contentEx($html, $widget, $lastResult)
{
$html = empty($lastResult) ? $html : $lastResult;
$options = Helper::options()->plugin('MenuTree');
/**开关判断*/
if (!is_null($options->switch)
&& (in_array('single', $options->switch) or in_array('normal', $options->switch))) {
$html = preg_replace_callback(self::$patternTitle, array('MenuTree_Plugin', 'parseCallback'), $html);
if (in_array('normal', $options->switch)) {
$html = preg_replace(self::$pattern, '<div class="index-menu">' . self::buildMenuHtml(self::$tree) . '</div>', $html);
} else {
$html = self::rmMenuTag($html);
}
self::$id = 1;
self::$tree = array();
return $html;
}
$html = self::rmMenuTag($html);
return $html;
}
/**
* 构造独立的索引目录
*
* @param $archive
* @return string
* @throws Typecho_Plugin_Exception
*/
public static function treeMenu($archive)
{
$options = Helper::options()->plugin('MenuTree');
if (is_null($options->switch) || !in_array('single', $options->switch)) {
return '';
}
preg_replace_callback(self::$patternTitle, array('MenuTree_Plugin', 'parseCallback'), $archive->content);
$result = '<div class="index-menu">' . self::buildMenuHtml(self::$tree) . '</div>';
self::$id = 1;
self::$tree = array();
return $result;
}
/**
* 解析
*
* @access public
* @param array $match 解析值
* @return string
*/
public static function parseCallback($match)
{
$parent = &self::$tree;
$html = $match[0];
$n = $match[1];
$menu = array(
'num' => $n,
'title' => trim(strip_tags($html)),
'id' => 'menu_index_' . self::$id,
'sub' => array()
);
$current = array();
if ($parent) {
$current = &$parent[count($parent) - 1];
}
// 根
if (!$parent || (isset($current['num']) && $n <= $current['num'])) {
$parent[] = $menu;
} else {
while (is_array($current['sub'])) {
// 父子关系
if ($current['num'] == $n - 1) {
$current['sub'][] = $menu;
break;
} // 后代关系,并存在子菜单
elseif ($current['num'] < $n && $current['sub']) {
$current = &$current['sub'][count($current['sub']) - 1];
} // 后代关系,不存在子菜单
else {
for ($i = 0; $i < $n - $current['num']; $i++) {
$current['sub'][] = array(
'num' => $current['num'] + 1,
'sub' => array()
);
$current = &$current['sub'][0];
}
$current['sub'][] = $menu;
break;
}
}
}
self::$id++;
return "<span class=\"menu-target-fix\" id=\"{$menu['id']}\" name=\"{$menu['id']}\"></span>" . $html;
}
/**
* 构建目录树,生成索引
*
* @access public
* @param $tree
* @param bool $include
* @return string
*/
public static function buildMenuHtml($tree, $include = true)
{
$menuHtml = '';
foreach ($tree as $menu) {
/**默认给第一个链接添加class: .current */
$current = ($menu['id'] == 'menu_index_1') ? 'current' : '';
if (!isset($menu['id']) && $menu['sub']) {
$menuHtml .= self::buildMenuHtml($menu['sub'], false);
} elseif ($menu['sub']) {
$menuHtml .= "<li class=\"index-menu-item\"><a data-scroll class=\"index-menu-link {$current}\" href=\"#{$menu['id']}\" title=\"{$menu['title']}\">{$menu['title']}</a>" . self::buildMenuHtml($menu['sub']) . "</li>";
} else {
$menuHtml .= "<li class=\"index-menu-item\"><a data-scroll class=\"index-menu-link {$current}\" href=\"#{$menu['id']}\" title=\"{$menu['title']}\">{$menu['title']}</a></li>";
}
}
if ($include) {
$menuHtml = '<ul class="index-menu-list">' . $menuHtml . '</ul>';
}
return $menuHtml;
}
/**
* 删除文章中的菜单标记注释
*
* @param $html
* @return string|string[]|null
*/
public static function rmMenuTag($html)
{
$html = preg_replace(self::$pattern, '', $html);
return $html;
}
/**
* 编辑器插入短代码功能。
* @access public
* @return void
*/
public static function render(){
?>
<script>
$(function(){
var wmd = $('#wmd-image-button');
if (wmd.length>0) {
wmd.after(
'<li class="wmd-button" id="wmd-mn-button" style="padding-top:5px;" title="<?php _e("插入目录树"); ?>"><img src="data:image/svg+xml,%3csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'16\' height=\'16\' viewBox=\'0 0 24 24\'%3e%3cpath fill=\'%23999\' d=\'M22 18v-7h-9v-5h3v-6h-8v6h3v5h-9v7h-2v6h6v-6h-2v-5h7v5h-2v6h6v-6h-2v-5h7v5h-2v6h6v-6z\'/%3e%3c/svg%3e"/></li>');
} else {
$('.url-slug').after('<button type="button" id="wmd-mn-button" class="btn btn-xs" style="margin-right:5px;"><?php _e("插入目录树"); ?></button>');
}
$('#wmd-mn-button').click(function(){
var textarea = $('#text'),
mninput = '<!-- index-menu -->',
sel = textarea.getSelection(),
offset = (sel ? sel.start : 0)+mninput.length;
textarea.replaceSelection(mninput);
textarea.setSelection(offset,offset);
});
});
</script>
<?php
}
}

79
MenuTree/README.md Normal file
View File

@@ -0,0 +1,79 @@
<a href="https://typecho-fans.github.io">
<img src="https://typecho-fans.github.io/text-logo.svg" alt="TF Logo" title="Typecho Fans开源作品社区" align="right" height="100" />
</a>
MenuTree v0.1.2 - 社区维护版
======================
<h4 align="center">—— 嵌入式文章内容目录树插件,可使用短代码标签或模板函数自定显示位置。</h4>
<p align="center">
<a href="#使用说明">使用说明</a> •
<a href="#版本历史">版本历史</a> •
<a href="#贡献作者">贡献作者</a> •
<a href="#附注链接">附注/链接</a> •
<a href="#授权协议">授权协议</a>
</p>
---
## 使用说明
<table>
<tr>
<td>
###### 可根据文章内容中的子标题结构生成锚点目录树,点击链接即可快速跳转至相应位置。支持在文内或模板中控制输出位置,新版添加了编辑器快捷插入按钮。
**使用方法**
##### 1. 下载本插件,放在 `usr/plugins/` 目录中,确保文件夹名为 MenuTree
##### 2. 激活插件,设置内可开关“嵌入模式”即文章标签输出,“独立模式”即模板函数输出;
##### 3. “嵌入模式”勾选时,编辑文章用按钮插入或手写`<!-- index-menu -->`标签发布即可显示目录树;
##### 4. “独立模式”勾选时修改模板文件如post.php中写入`<?php $this->treeMenu(); ?>`也可显示。
**注意事项**
* ##### 插件仅输出html不带css请根据以下class命名自行处理样式
```
.index-menu 容器 div
.index-menu-list 列表 ul
.index-menu-item 列表项 li
.index-menu-link 列表项链接 a
.menu-target-fix {display:block; position:relative; top:-60px; //偏移量} 锚点跳转定位
```
</td>
</tr>
</table>
## 版本历史
* v0.1.2 (20-07-15 [@jzwalk](https://github.com/jzwalk))
* 添加自适应编辑器按钮合并1个衍生版本功能
* 增加模板函数输出及复选框设置([@xxyangyoulin](https://github.com/xxyangyoulin))。
* v0.1.1 (18-05-24 [@wuruowuxin74](https://github.com/wuruowuxin74))
* 增加摘要隐藏处理;
* 增加锚点定位class。
* v0.1.0 (15-06-20 @Melon)
* 原作发布。
## 贡献作者
[![jzwalk](https://avatars1.githubusercontent.com/u/252331?v=3&s=100)](https://github.com/jzwalk) | [![xxyangyoulin](https://avatars1.githubusercontent.com/u/25523208?v=3&s=100)](https://github.com/xxyangyoulin) | [![wuruowuxin74](https://avatars1.githubusercontent.com/u/16893894?v=3&s=100)](https://github.com/wuruowuxin74) | [![Melon](https://secure.gravatar.com/avatar/?d=mp&s=100)](#)
:---:|:---:|:---:|:---:
[jzwalk](https://github.com/jzwalk) (2020) | [xxyangyoulin](https://github.com/xxyangyoulin) (2019) | [wuruowuxin74](https://github.com/wuruowuxin74) (2018) | Melon (2015)
## 附注/链接
本社区维护版已包含以下各版本功能并做优化调整:
* [Fork版(xxyangyoulin)](https://github.com/xxyangyoulin) - 添加模板输出与面板设置。
* [修正版(wuruowuxin74)](https://github.com/wuruowuxin74/MenuTree) - 添加摘要/锚点处理。
* [原版](http://forum.typecho.org/viewtopic.php?f=6&t=8201&p=33354) - 实现插入代码替换目录树功能。
欢迎社区成员继续贡献代码参与更新。<br/>
另有带样式目录树插件[ContentIndex](https://github.com/typecho-fans/plugins/blob/master/ContentIndex)和Js悬浮目录树插件[MenuTree](https://github.com/typecho-fans/plugins/blob/master/MenuTree_hongweipeng)可供参考。
## 授权协议
TF目录下的社区维护版作品如果没有明确声明默认采用与Typecho相同的[GPLv2](https://github.com/typecho/typecho/blob/master/LICENSE.txt)开源协议。(要求提及出处,保持开源并注明修改。)
> MenuTree原作未附协议声明原作者保留所有权利。 © Melon