3.2.31 目录「正文内显示」与「浮动显示」拆成两个独立开关(#1)
原来「目录位置」是一个三选一下拉:正文中间 / 页面左侧 / 页面右侧,
等于把「放进正文」和「浮在页边」当成互斥的一件事 —— 想同时在正文
开头放一份、又在边上浮一份,做不到。
改成两个独立勾选,各自带子选项:
· 在正文中显示 → 正文中的对齐(靠左 / 靠右)+ 自动插入位置
· 浮动显示 → 浮动方向(页面左侧 / 页面右侧)
两个都勾就同时出现两份,只勾一个就只出现一种。四种组合都在后台
联动里逐个验证过(探针 70/0)。
新增能力「正文内靠左 / 靠右」是本单的主要新需求。实现上两个要点:
1. 必须给正文目录一个宽度上限(max-width: min(100%, 28em))。
块级盒子默认撑满正文栏,此时 margin:auto 没有剩余空间可分配,
「靠左/靠右」会是一个属性正确、画面纹丝不动的空操作。
2. 用 data-align 属性把方向带下去,CSS 只需两条规则,
不随方向数量膨胀。属性在 yang_toc_slot_html() 里输出。
语义收窄:手写 [TOC] 以前会让整份自动处理全停(连带 rail=false),
现在只手管「正文那一份」—— 手写位置优先,浮动仍由 float 开关独立
决定。这样「精确定位正文位置」和「全站边上都有目录」可以并存。
顺手修掉一处默认值错配:checkbox 用 !empty() 判断会把「键不存在」
和「键明确为空」混成一件事,导致新装站点后台框显示勾上、页面却
不出目录。改用 array_key_exists() 区分的三态判断。
老配置不迁移:3.2.30 的 toc_place 直接作废,不做兼容。
默认 inline=1 / float=0,升级后页面与升级前一致。
重构:把内容过滤器拆成 yang_toc_apply()(纯执行层)+ 运行时壳,
使设置组合能在单进程单测里逐个喂进去(PHP 无法重置函数 static)。
验证
逻辑 101/0 · 逻辑反向 15/15
旧回归 53/0
静态契约 58/0 · 反向 11/11
后台几何+交互 70/0 · 反向 11/11
侧栏几何 73/0 · 反向 8/8
正文对齐几何 23/0 · 反向 5/5(含阴性对照)
包内容契约 59/0 · 反向 9/9
正文对齐的几何探针量到真实的 Δleft = 348px(靠右比靠左),
而不是只断言 data-align 字符串存在。
This commit is contained in:
@@ -262,6 +262,34 @@ body.admin-bar .k-main .details .content h6[id] {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── 正文内目录的左右对齐 ─────────────────────────────────────
|
||||||
|
* 需求里「靠左 / 靠右」指的是:目录块在**正文容器内部**贴左还是贴右,
|
||||||
|
* 不是浮到页面边上(那是 .yang-toc-rail 的职责)。
|
||||||
|
*
|
||||||
|
* 为什么必须收窄宽度:块级盒子默认撑满正文栏,此时靠左靠右在视觉上
|
||||||
|
* 完全一样 —— 只写 margin 的「对齐」是个**看起来实现了、实际是空操作**
|
||||||
|
* 的功能,量几何都量不出差别。所以这里给一个上限宽度,让对齐有意义。
|
||||||
|
*
|
||||||
|
* 用 min() 而不是固定 px:窄屏时自动退化成 100%,不会出现「手机上目录
|
||||||
|
* 只占一半、右边空一大块」。em 单位跟着字号走,用户改了基础字号也不会怪。
|
||||||
|
*
|
||||||
|
* 用 margin-left/right:auto 而不是 float:float 会让正文文字绕排,那是
|
||||||
|
* 另一回事(也会把 <details> 的折叠交互搞乱)。这里只做「在容器里摆哪边」。
|
||||||
|
*/
|
||||||
|
.yang-toc-slot[data-align] > .yang-toc {
|
||||||
|
max-width: min(100%, 28em);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yang-toc-slot[data-align="left"] > .yang-toc {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yang-toc-slot[data-align="right"] > .yang-toc {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── 侧边浮动目录 ─────────────────────────────────────────────
|
/* ── 侧边浮动目录 ─────────────────────────────────────────────
|
||||||
* 结构:贴边的一条细标签 + 一块可滑出的面板。
|
* 结构:贴边的一条细标签 + 一块可滑出的面板。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -100,21 +100,33 @@ jQuery(document).ready(function ($) {
|
|||||||
jQuery('#section-top_describe').show()
|
jQuery('#section-top_describe').show()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自动目录:只有「目录位置 = 正文中间」时,插入位置才有意义。
|
// 自动目录:字段显隐跟着两个开关走。
|
||||||
// 侧栏模式(左/右)下它完全无效 —— 若还留着这个下拉框,用户会以为
|
//
|
||||||
// 「选了文章结尾却没插进正文」是个 bug。
|
// 「在正文中显示」勾了 → 「正文中的对齐」「自动插入位置」才有意义
|
||||||
|
// 「浮动显示」勾了 → 「浮动方向」才有意义
|
||||||
|
//
|
||||||
|
// 为什么必须藏起来:两个开关任一关闭时,它下面那几个子选项完全无效。
|
||||||
|
// 若还留着,用户会以为「选了文章结尾却没插进正文」是个 bug。
|
||||||
//
|
//
|
||||||
// 用 class 切换而不是 fadeIn/fadeOut:.section 的 display 是 flow-root
|
// 用 class 切换而不是 fadeIn/fadeOut:.section 的 display 是 flow-root
|
||||||
// (3.2.28 靠它建独立 BFC,避免被左侧浮动标签列的 clear:both 拉长)。
|
// (3.2.28 靠它建独立 BFC,避免被左侧浮动标签列的 clear:both 拉长)。
|
||||||
// jQuery 的 show()/hide() 会写行内 display,把那套布局打回 block,
|
// jQuery 的 show()/hide() 会写行内 display,把那套布局打回 block,
|
||||||
// 等于悄悄回退 3.2.28 的修复。
|
// 等于悄悄回退 3.2.28 的修复。
|
||||||
function yq_toggle_toc_anchor () {
|
//
|
||||||
var center = jQuery('#toc_place').val() === 'center'
|
// ⚠️ 绑定事件用 delegation('change' 挂 document、选择器过滤):
|
||||||
jQuery('#section-toc_anchor').toggleClass('yq-cond-hide', !center)
|
// 这两个是 checkbox,框架的 checkbox 控件可能在外面再包一层 label/inline,
|
||||||
|
// 直接绑在 input 上偶尔会因为 DOM 顺序变了而漏绑。delegation 不受影响。
|
||||||
|
function yq_toggle_toc_fields () {
|
||||||
|
var inline = jQuery('#toc_inline').is(':checked')
|
||||||
|
var float = jQuery('#toc_float').is(':checked')
|
||||||
|
|
||||||
|
jQuery('#section-toc_inline_align').toggleClass('yq-cond-hide', !inline)
|
||||||
|
jQuery('#section-toc_anchor').toggleClass('yq-cond-hide', !inline)
|
||||||
|
jQuery('#section-toc_float_side').toggleClass('yq-cond-hide', !float)
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery('#toc_place').on('change', yq_toggle_toc_anchor)
|
jQuery(document).on('change', '#toc_inline, #toc_float', yq_toggle_toc_fields)
|
||||||
yq_toggle_toc_anchor()
|
yq_toggle_toc_fields()
|
||||||
|
|
||||||
// Loads the color pickers
|
// Loads the color pickers
|
||||||
$('.of-color').wpColorPicker()
|
$('.of-color').wpColorPicker()
|
||||||
|
|||||||
+47
-20
@@ -397,15 +397,55 @@ function kratos_options()
|
|||||||
);
|
);
|
||||||
|
|
||||||
$options[] = array(
|
$options[] = array(
|
||||||
'name' => __('目录位置', 'kratos'),
|
'name' => __('在正文中显示', 'kratos'),
|
||||||
'desc' => __('<b>正文中间</b>:目录是正文的一部分,按下面的「自动插入位置」插进去。<br><b>页面左侧 / 右侧</b>:目录变成贴在页面边缘的浮动面板,点边上的小标签滑出,正文里不放任何东西(「自动插入位置」对它无效)。窄屏(手机)上也是从边缘滑出的抽屉,不会挤占正文。', 'kratos'),
|
'desc' => __('勾选后,在文章正文里插一份目录。<br>它和下面的「浮动显示」<b>互不影响</b>:两个都勾就同时出现两份(正文一份、边上浮一份),只勾一个就只出现一种。', 'kratos'),
|
||||||
'id' => 'toc_place',
|
'id' => 'toc_inline',
|
||||||
'std' => 'center',
|
'std' => '1',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
);
|
||||||
|
|
||||||
|
$options[] = array(
|
||||||
|
'name' => __('正文中的对齐', 'kratos'),
|
||||||
|
'desc' => __('正文里那份目录在<b>文章内容区域内</b>靠左还是靠右。这里不是「浮到页面边上」—— 目录仍然在正文流里,上下文的文字会绕开它,只是整体贴向一侧。<br>只在勾选「在正文中显示」时才有意义。', 'kratos'),
|
||||||
|
'id' => 'toc_inline_align',
|
||||||
|
'std' => 'left',
|
||||||
'type' => 'select',
|
'type' => 'select',
|
||||||
'options' => array(
|
'options' => array(
|
||||||
'center' => __('正文中间', 'kratos'),
|
'left' => __('靠左', 'kratos'),
|
||||||
'left' => __('页面左侧(浮动)', 'kratos'),
|
'right' => __('靠右', 'kratos'),
|
||||||
'right' => __('页面右侧(浮动)', 'kratos'),
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$options[] = array(
|
||||||
|
'name' => __('自动插入位置', 'kratos'),
|
||||||
|
'desc' => __('只在「添加方式 = 自动」且勾选了「在正文中显示」时起作用。<br><b>第一个标题之前</b>取正文里最先出现的 h1 或 h2 —— 文章大标题在正文之外,不会被算进去;一个 h1/h2 都没有时退回插在文章开头。', 'kratos'),
|
||||||
|
'id' => 'toc_anchor',
|
||||||
|
'std' => 'first',
|
||||||
|
'type' => 'select',
|
||||||
|
'options' => array(
|
||||||
|
'start' => __('文章开头', 'kratos'),
|
||||||
|
'first' => __('第一个标题之前(H1 / H2)', 'kratos'),
|
||||||
|
'end' => __('文章结尾', 'kratos'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$options[] = array(
|
||||||
|
'name' => __('浮动显示', 'kratos'),
|
||||||
|
'desc' => __('勾选后,目录变成贴在页面边缘的浮动面板,点边上的小标签滑出,<b>不占正文位置</b>。窄屏(手机)上是从边缘滑出的抽屉,不会挤占正文。<br>与「在正文中显示」互相独立,可以同时勾选。', 'kratos'),
|
||||||
|
'id' => 'toc_float',
|
||||||
|
'std' => '',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
);
|
||||||
|
|
||||||
|
$options[] = array(
|
||||||
|
'name' => __('浮动方向', 'kratos'),
|
||||||
|
'desc' => __('浮动面板贴页面左边还是右边。只在勾选「浮动显示」时才有意义。', 'kratos'),
|
||||||
|
'id' => 'toc_float_side',
|
||||||
|
'std' => 'left',
|
||||||
|
'type' => 'select',
|
||||||
|
'options' => array(
|
||||||
|
'left' => __('页面左侧', 'kratos'),
|
||||||
|
'right' => __('页面右侧', 'kratos'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -421,19 +461,6 @@ function kratos_options()
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
$options[] = array(
|
|
||||||
'name' => __('自动插入位置', 'kratos'),
|
|
||||||
'desc' => __('只在「添加方式 = 自动」且「目录位置 = 正文中间」时起作用。<br><b>第一个标题之前</b>取正文里最先出现的 h1 或 h2 —— 文章大标题在正文之外,不会被算进去;一个 h1/h2 都没有时退回插在文章开头。', 'kratos'),
|
|
||||||
'id' => 'toc_anchor',
|
|
||||||
'std' => 'first',
|
|
||||||
'type' => 'select',
|
|
||||||
'options' => array(
|
|
||||||
'start' => __('文章开头', 'kratos'),
|
|
||||||
'first' => __('第一个标题之前(H1 / H2)', 'kratos'),
|
|
||||||
'end' => __('文章结尾', 'kratos'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
$options[] = array(
|
$options[] = array(
|
||||||
'name' => __('默认状态', 'kratos'),
|
'name' => __('默认状态', 'kratos'),
|
||||||
'desc' => __('<b>默认显示</b>:进来就能看到全部条目。<b>默认隐藏</b>:先只露出标题栏(或侧边的标签),读者自己点开。<b>较长或标题很多的文章建议默认隐藏</b>,否则目录会占掉一屏。<br>注:这里只管「默认长什么样」,读者点开后仍然可以正常使用;正文里手写的 <b>[TOC]</b> 也可以用 <b>open="0"</b> 单独指定。', 'kratos'),
|
'desc' => __('<b>默认显示</b>:进来就能看到全部条目。<b>默认隐藏</b>:先只露出标题栏(或侧边的标签),读者自己点开。<b>较长或标题很多的文章建议默认隐藏</b>,否则目录会占掉一屏。<br>注:这里只管「默认长什么样」,读者点开后仍然可以正常使用;正文里手写的 <b>[TOC]</b> 也可以用 <b>open="0"</b> 单独指定。', 'kratos'),
|
||||||
|
|||||||
+129
-33
@@ -21,17 +21,26 @@
|
|||||||
* 手写标记里写了的参数优先于后台设置,没写的才用后台设置。
|
* 手写标记里写了的参数优先于后台设置,没写的才用后台设置。
|
||||||
*
|
*
|
||||||
* ② 自动:后台「主题设置 → 自动目录」里选好,正文不用写任何东西。
|
* ② 自动:后台「主题设置 → 自动目录」里选好,正文不用写任何东西。
|
||||||
* · 目录位置:正文中间 / 页面左侧(浮动)/ 页面右侧(浮动)
|
* 显示方式是**两个独立开关**,可同时开启:
|
||||||
* · 添加方式:手动 / 自动
|
* · 在正文中显示 → 子选项:正文中的对齐(靠左 / 靠右)、插入位置
|
||||||
* · 自动插入位置(只对「正文中间」有效):文章开头 / 第一个 H1、H2 之前 / 文章结尾
|
* (文章开头 / 第一个 H1、H2 之前 / 文章结尾)
|
||||||
* · 默认状态:默认显示 / 默认隐藏
|
* · 浮动显示 → 子选项:浮动方向(左侧 / 右侧)
|
||||||
* · 另外可配目录标题、收录层级、是否显示序号
|
* 全开时同一篇文章里正文一份 + 浮动一份,两份指向同一批锚点。
|
||||||
|
* 另外还有:添加方式(手动 / 自动)、默认状态(显示 / 隐藏)、
|
||||||
|
* 目录标题、收录层级、是否显示序号。
|
||||||
*
|
*
|
||||||
* ── 手写永远优先 ──────────────────────────────────────────────
|
* ⚠️ 「靠左 / 靠右」是**正文容器内部**的对齐,不是浮到页面边上;
|
||||||
* 只要正文里有 [TOC],就**只**按作者写的位置渲染,不再自动插第二份、
|
* 「浮动方向」才是贴页面哪一边。这两件事曾经被合并成一个三选一的
|
||||||
* 也不出侧栏。理由:作者明确表过态的地方,机器不该再替他做一次决定;
|
* place 字段(center/left/right),导致两者永远互斥、无法同时开启。
|
||||||
|
*
|
||||||
|
* ── 手写永远优先(仅限正文那一份)────────────────────────────
|
||||||
|
* 只要正文里有 [TOC],就**只**按作者写的位置渲染正文那一份,不再自动
|
||||||
|
* 插第二份。理由:作者明确表过态的地方,机器不该再替他做一次决定;
|
||||||
* 否则老文章升级后会突然多出一个目录,位置还未必是他要的。
|
* 否则老文章升级后会突然多出一个目录,位置还未必是他要的。
|
||||||
*
|
*
|
||||||
|
* 但浮动面板是**独立开关**:它不属于正文流,作者写了 [TOC] 也没说过
|
||||||
|
* 「不要浮动目录」。所以 float=1 时照样出浮动面板。
|
||||||
|
*
|
||||||
* ── 为什么默认收 h1(曾经错设成 "2,3")──────────────────────
|
* ── 为什么默认收 h1(曾经错设成 "2,3")──────────────────────
|
||||||
* 原先的理由是「h1 是文章标题本身,不该进目录」。这个理由是**假的**:
|
* 原先的理由是「h1 是文章标题本身,不该进目录」。这个理由是**假的**:
|
||||||
* 文章标题输出在 single.php 的 <h1 class="title">,在 the_content
|
* 文章标题输出在 single.php 的 <h1 class="title">,在 the_content
|
||||||
@@ -89,9 +98,23 @@ if (!defined('ABSPATH')) {
|
|||||||
function yang_toc_defaults()
|
function yang_toc_defaults()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'place' => 'center', // center | left | right
|
/* 两个**互相独立**的显示开关,可同时为 1。
|
||||||
|
*
|
||||||
|
* 为什么不是「三选一」:曾经用单个 place=center/left/right 表达,
|
||||||
|
* 把「放在正文里」和「浮在页面边上」混成了同一个维度的三个值,
|
||||||
|
* 于是两者永远互斥 —— 用户想「正文里放一份、边上再浮一份」时无法表达。
|
||||||
|
* 现在拆成 inline / float 两个开关 + 各自的子选项:
|
||||||
|
* inline 在正文流里插一份
|
||||||
|
* inline_align inline 生效时的对齐:left | right
|
||||||
|
* float 在页面边缘浮一份
|
||||||
|
* float_side float 生效时浮哪边:left | right
|
||||||
|
*/
|
||||||
|
'inline' => 1, // 0 | 1
|
||||||
|
'inline_align' => 'left', // left | right(正文容器内部对齐)
|
||||||
|
'float' => 0, // 0 | 1
|
||||||
|
'float_side' => 'left', // left | right(贴页面哪一边)
|
||||||
'mode' => 'manual', // manual | auto
|
'mode' => 'manual', // manual | auto
|
||||||
'anchor' => 'first', // start | first | end(只对 center 有效)
|
'anchor' => 'first', // start | first | end(只对 inline 有效)
|
||||||
'default' => 'show', // show | hide
|
'default' => 'show', // show | hide
|
||||||
'title' => __('目录', 'kratos'),
|
'title' => __('目录', 'kratos'),
|
||||||
'levels' => array('1' => 1, '2' => 1, '3' => 1, '4' => 0),
|
'levels' => array('1' => 1, '2' => 1, '3' => 1, '4' => 0),
|
||||||
@@ -175,7 +198,25 @@ function yang_toc_normalize_settings($raw)
|
|||||||
};
|
};
|
||||||
|
|
||||||
$s = array();
|
$s = array();
|
||||||
$s['place'] = $pick('place', array('center', 'left', 'right'));
|
|
||||||
|
/* checkbox 的存值有两种:框架写回时是 '1' 或 ''(也可能 true/false)。
|
||||||
|
* 关键区别在「键不存在」和「键存在但为空」:
|
||||||
|
* · 键不存在 = 从没配过(新站 / 老库升级)= 用默认值
|
||||||
|
* · 键存在且为空 = 用户明确取消勾选 = 0
|
||||||
|
* 用 !empty() 一把梭会把这两种情况混成一件事,结果**新装站点默认不显示
|
||||||
|
* 正文目录** —— 后台勾选框看起来是勾上的(那是 std 预填),页面却不出。
|
||||||
|
* 这种错配极难发现,因为两边单独看都"正常"。 */
|
||||||
|
$flag = function ($key) use ($raw, $d) {
|
||||||
|
if (!array_key_exists($key, $raw)) {
|
||||||
|
return $d[$key]; // 从没配过
|
||||||
|
}
|
||||||
|
return empty($raw[$key]) ? 0 : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
$s['inline'] = $flag('inline');
|
||||||
|
$s['float'] = $flag('float');
|
||||||
|
$s['inline_align'] = $pick('inline_align', array('left', 'right'));
|
||||||
|
$s['float_side'] = $pick('float_side', array('left', 'right'));
|
||||||
$s['mode'] = $pick('mode', array('manual', 'auto'));
|
$s['mode'] = $pick('mode', array('manual', 'auto'));
|
||||||
$s['anchor'] = $pick('anchor', array('start', 'first', 'end'));
|
$s['anchor'] = $pick('anchor', array('start', 'first', 'end'));
|
||||||
$s['default'] = $pick('default', array('show', 'hide'));
|
$s['default'] = $pick('default', array('show', 'hide'));
|
||||||
@@ -207,7 +248,8 @@ function yang_toc_settings()
|
|||||||
}
|
}
|
||||||
|
|
||||||
$raw = array();
|
$raw = array();
|
||||||
foreach (array('place', 'mode', 'anchor', 'default', 'title', 'levels', 'numbering') as $k) {
|
foreach (array('inline', 'inline_align', 'float', 'float_side',
|
||||||
|
'mode', 'anchor', 'default', 'title', 'levels', 'numbering') as $k) {
|
||||||
$raw[$k] = kratos_option('toc_' . $k, null);
|
$raw[$k] = kratos_option('toc_' . $k, null);
|
||||||
}
|
}
|
||||||
// 库里没有的键用 null 占位,normalize 时按「未配置」回落默认值
|
// 库里没有的键用 null 占位,normalize 时按「未配置」回落默认值
|
||||||
@@ -275,15 +317,20 @@ function yang_toc_has_marker($content)
|
|||||||
* 'start' 文章开头
|
* 'start' 文章开头
|
||||||
* 'first' 第一个 H1/H2 之前
|
* 'first' 第一个 H1/H2 之前
|
||||||
* 'end' 文章结尾
|
* 'end' 文章结尾
|
||||||
|
* inline_align 'left'/'right' 正文章节的对齐方向
|
||||||
* rail bool 是否输出侧边浮动目录
|
* rail bool 是否输出侧边浮动目录
|
||||||
* side 'left'/'right' 侧栏挂哪边
|
* side 'left'/'right' 侧栏挂哪边
|
||||||
* settings array 归一化设置
|
* settings array 归一化设置
|
||||||
*
|
*
|
||||||
* 规则(顺序即优先级):
|
* 规则(顺序即优先级):
|
||||||
* ① 正文有 [TOC] ⇒ 只在标记处渲染,不出侧栏、不自动插;
|
* ① 正文有 [TOC] ⇒ 只在标记处渲染正文那一份;浮动仍按 float 开关独立决定。
|
||||||
* ② 添加方式 = 手动 ⇒ 什么都不自动做;
|
* 手写标记只管「正文那一份在哪」,没道理连带把浮动面板也关掉 ——
|
||||||
* ③ 目录位置 = 中间 ⇒ 按「自动插入位置」插进正文;
|
* 那是两件事。但正文绝不会出现第二份。
|
||||||
* ④ 目录位置 = 左/右 ⇒ 出侧栏,正文不动(插入位置对侧栏无效)。
|
* ② 添加方式 = 手动 ⇒ 不自动插正文那份;浮动同样独立决定。
|
||||||
|
* ③ inline=1 ⇒ 按 anchor 插进正文;inline=0 ⇒ 正文不动。
|
||||||
|
* ④ float=1 ⇒ 出浮动面板,方向按 float_side。
|
||||||
|
*
|
||||||
|
* ③ 和 ④ 完全独立,可以同时成立:正文一份 + 浮动一份,共用同一批锚点。
|
||||||
*
|
*
|
||||||
* @param bool $has_marker
|
* @param bool $has_marker
|
||||||
* @param array $s 设置(不传则取当前设置)
|
* @param array $s 设置(不传则取当前设置)
|
||||||
@@ -296,12 +343,20 @@ function yang_toc_plan($has_marker = false, $s = null)
|
|||||||
}
|
}
|
||||||
|
|
||||||
$plan = array(
|
$plan = array(
|
||||||
'inline_at' => null,
|
'inline_at' => null,
|
||||||
'rail' => false,
|
'inline_align' => $s['inline_align'],
|
||||||
'side' => 'left',
|
'rail' => false,
|
||||||
'settings' => $s,
|
'side' => $s['float_side'],
|
||||||
|
'settings' => $s,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* 浮动独立于手写标记与添加方式:它不属于正文流,
|
||||||
|
作者写了 [TOC] 也没说过「不要浮动目录」。 */
|
||||||
|
if (!empty($s['float'])) {
|
||||||
|
$plan['rail'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 正文那一份:手写标记 > 自动插入 */
|
||||||
if ($has_marker) {
|
if ($has_marker) {
|
||||||
$plan['inline_at'] = 'marker';
|
$plan['inline_at'] = 'marker';
|
||||||
return $plan;
|
return $plan;
|
||||||
@@ -311,11 +366,8 @@ function yang_toc_plan($has_marker = false, $s = null)
|
|||||||
return $plan;
|
return $plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($s['place'] === 'center') {
|
if (!empty($s['inline'])) {
|
||||||
$plan['inline_at'] = $s['anchor'];
|
$plan['inline_at'] = $s['anchor'];
|
||||||
} else {
|
|
||||||
$plan['rail'] = true;
|
|
||||||
$plan['side'] = ($s['place'] === 'right') ? 'right' : 'left';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $plan;
|
return $plan;
|
||||||
@@ -769,6 +821,27 @@ function yang_toc_filter_content($content)
|
|||||||
yang_toc_rail_ready(true);
|
yang_toc_rail_ready(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return yang_toc_apply($content, $out, $items, $has_marker, $plan);
|
||||||
|
}
|
||||||
|
add_filter('the_content', 'yang_toc_filter_content', 9);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 plan 把目录落到已补好 id 的正文上(纯函数)
|
||||||
|
*
|
||||||
|
* 单独拆出来是为了让测试能「喂一份设置 → 直接看输出」:上面那个壳依赖
|
||||||
|
* WordPress 运行时(is_singular / in_the_loop / get_the_ID 全要对上),
|
||||||
|
* 而设置是从库里读的、一次请求只能有一份。拆开之后,几十种组合可以在
|
||||||
|
* 同一个进程里逐个跑,不必为了测试给读设置那层开后门。
|
||||||
|
*
|
||||||
|
* @param string $content 原始正文(替换失败时原样返回它)
|
||||||
|
* @param string $out 已补好标题 id 的正文
|
||||||
|
* @param array $items yang_toc_scan() 得到的条目
|
||||||
|
* @param bool $has_marker 原文里有没有手写 [TOC]
|
||||||
|
* @param array $plan yang_toc_plan() 的结果
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function yang_toc_apply($content, $out, $items, $has_marker, $plan)
|
||||||
|
{
|
||||||
/* ── ① 手写标记:按作者写的位置渲染,且不再自动插第二份 ── */
|
/* ── ① 手写标记:按作者写的位置渲染,且不再自动插第二份 ── */
|
||||||
if ($has_marker) {
|
if ($has_marker) {
|
||||||
/* 后台设置当默认值,标记里写了的属性覆盖它。
|
/* 后台设置当默认值,标记里写了的属性覆盖它。
|
||||||
@@ -786,12 +859,12 @@ function yang_toc_filter_content($content)
|
|||||||
return is_string($replaced) ? $replaced : $content;
|
return is_string($replaced) ? $replaced : $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── ② 侧栏模式:正文只补 id,目录由 wp_footer 输出 ── */
|
/* ── ② 只出浮动:正文只补 id,目录由 wp_footer 输出 ── */
|
||||||
if ($plan['inline_at'] === null) {
|
if ($plan['inline_at'] === null) {
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── ③ 自动插入 ── */
|
/* ── ③ 正文里插一份 ── */
|
||||||
$html = yang_toc_render($items, yang_toc_atts_from_settings($plan['settings']));
|
$html = yang_toc_render($items, yang_toc_atts_from_settings($plan['settings']));
|
||||||
if ($html === '') {
|
if ($html === '') {
|
||||||
// 一个符合层级的标题都没有 —— 不输出空壳
|
// 一个符合层级的标题都没有 —— 不输出空壳
|
||||||
@@ -799,11 +872,36 @@ function yang_toc_filter_content($content)
|
|||||||
}
|
}
|
||||||
|
|
||||||
$pos = $plan['inline_at'];
|
$pos = $plan['inline_at'];
|
||||||
$slot = '<div class="yang-toc-slot yang-toc-slot-' . esc_attr($pos) . '">' . $html . '</div>';
|
$slot = yang_toc_slot_html($html, $pos, $plan['inline_align']);
|
||||||
|
|
||||||
return yang_toc_inject($out, $slot, $pos);
|
return yang_toc_inject($out, $slot, $pos);
|
||||||
}
|
}
|
||||||
add_filter('the_content', 'yang_toc_filter_content', 9);
|
|
||||||
|
/**
|
||||||
|
* 正文目录的外层盒子(带插入位置与对齐方向)
|
||||||
|
*
|
||||||
|
* 对齐为什么放在这一层、而不是 .yang-toc 上:
|
||||||
|
* · .yang-toc 自己已经有 24px 上下的外边距,再叠一层 margin 会叠加;
|
||||||
|
* · 靠左/靠右本质是「盒子在正文容器里怎么摆」,属于外层容器的职责;
|
||||||
|
* · 用 data 属性把方向带下去,CSS 只需一条 [data-align="right"] 规则,
|
||||||
|
* 不必再生成 -right 这种 class 变体(class 会越想越多)。
|
||||||
|
*
|
||||||
|
* 注意靠左/靠右**不改变盒子的宽度**:目录块是否撑满正文栏由 .yang-toc
|
||||||
|
* 的样式决定(默认 auto,即撑满)。对齐只在它不撑满时才有可见效果,
|
||||||
|
* 所以这里同时给了 inline-size 相关的钩子,样式里再按需收窄。
|
||||||
|
*
|
||||||
|
* @param string $html 目录 HTML
|
||||||
|
* @param string $pos start | first | end
|
||||||
|
* @param string $align left | right
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function yang_toc_slot_html($html, $pos, $align = 'left')
|
||||||
|
{
|
||||||
|
$align = ($align === 'right') ? 'right' : 'left';
|
||||||
|
|
||||||
|
return '<div class="yang-toc-slot yang-toc-slot-' . esc_attr($pos) . '"'
|
||||||
|
. ' data-align="' . esc_attr($align) . '">' . $html . '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 把目录插进正文(纯函数)
|
* 把目录插进正文(纯函数)
|
||||||
@@ -923,12 +1021,10 @@ function yang_toc_render_rail()
|
|||||||
if (!$post || !isset($post->post_content)) {
|
if (!$post || !isset($post->post_content)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 作者写了 [TOC]:手写优先,不出侧栏
|
|
||||||
if (yang_toc_has_marker($post->post_content)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$plan = yang_toc_plan(false);
|
/* 手写 [TOC] 只管「正文那一份在哪」,不再连带关掉浮动面板。
|
||||||
|
两者现在是独立开关,作者写了标记也不等于说过「不要浮动目录」。 */
|
||||||
|
$plan = yang_toc_plan(yang_toc_has_marker($post->post_content));
|
||||||
if (!$plan['rail']) {
|
if (!$plan['rail']) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Theme Name: Kratos_Yang
|
Theme Name: Kratos_Yang
|
||||||
Text Domain: kratos_Yang
|
Text Domain: kratos_Yang
|
||||||
Version: 3.2.30
|
Version: 3.2.31
|
||||||
Requires PHP: 7.0
|
Requires PHP: 7.0
|
||||||
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
|
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
|
||||||
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好
|
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好
|
||||||
|
|||||||
Reference in New Issue
Block a user