后台代码配色预览不上色 + donate.png 404 一并修复 #14
Bug 1:后台预览的示例代码没有高亮。三层原因叠在一起。
① yang_hl_admin_assets() 从未 enqueue hljs 本体,而 yang_hl_enqueue()
开头 `if (is_admin() || is_feed()) return;` 挡掉后台
⇒ 后台 window.hljs 恒 undefined ⇒ recolor() 静默 return。
卡片的边框/顶栏是 data-kind 驱动的纯 CSS,切深浅配色时照样会变,
看起来像"预览在工作,只是代码没颜色"。
② init() 里 applyTheme(sel.value, true) 传 noRecolor=true ⇒ 首屏永不上色,
只有手动拨下拉框才有颜色(正是报障的"下面的示例代码并没有高亮")。
③ recolor() 缺 hljs 时只是 return,控制台零输出 ⇒ 极难定位。
修法:
- inc/theme-highlight.php:后台 enqueue hljs 本体,并作为 preview 脚本的
硬依赖(不靠 WP 的加载顺序碰运气);前台 yang_hl_enqueue() 仍挡后台。
- assets/js/highlight-admin.js:删掉 noRecolor 这个"能否跳过核心动作"的
参数(调用方迟早会用错);首屏与切换走同一条路径。
- 缺 hljs / 上色失败时 console.error 出声,并给 code 打
data-unhighlighted、给卡片打 data-hl-failed;CSS 画橙色虚线框 +
顶栏文字,让失败在画面上也看得出来,不再是一坨单色字。
- 配色样式加载主路径改为 setTimeout(once, 125),link.onload 只作加速。
onload 三情形不触发:样式表已在缓存、link 移除后重插、jsdom 无网络。
Bug 2:后台设置页报 donate.png 404。
库里 g_donate_alipay / g_donate_wechat 存的是旧主题目录名
`.../themes/kratos-master/assets/img/donate.png` 的绝对 URL。前台走
yang_option_image() 有 yang_image_url_is_stale() 兜底,后台
class-options-media-uploader.php 直接 echo $value,绕过检测。
修在渲染处:预览图与"浏览文件"href 走检测后的 $preview(带
function_exists 兜底),输入框仍显示库里的原值,不偷偷改用户数据。
版本 3.2.44 → 3.2.45。
This commit is contained in:
@@ -110,4 +110,27 @@
|
||||
.yang-hl-preview-hint {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 上色失败的可视标记 ──────────────────────────────────
|
||||
*
|
||||
* 3.2.44 的教训:预览没上色时,画面上和"某套配色本来就很朴素"
|
||||
* 完全无法区分。用户在后台看到单色代码,只能猜是配色问题还是坏了。
|
||||
* ⇒ 上色失败时打一个 data 标记,这里给一道醒目的虚线框,
|
||||
* 让"坏了"和"配色就这样"在视觉上立刻分开。
|
||||
*
|
||||
* 判据:这是**降级提示**,不是正常态。所以颜色用后台的警告橙
|
||||
* (#dba617),不引入新色值。 */
|
||||
.yang-hl-preview .cb[data-hl-failed="1"] {
|
||||
outline: 2px dashed #dba617;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.yang-hl-preview .cb[data-hl-failed="1"] .cb-bar::after {
|
||||
content: "预览未能上色,请查看浏览器控制台";
|
||||
margin-left: auto;
|
||||
padding-left: 8px;
|
||||
font-size: 11px;
|
||||
color: #dba617;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -41,10 +41,17 @@
|
||||
/**
|
||||
* 把预览的配色换成 key 对应的那套
|
||||
*
|
||||
* @param {string} key 配色 key,如 'monokai'
|
||||
* @param {boolean} noRecolor 只换 CSS 不重新上色(初始化时用,避免多余计算)
|
||||
* 🔴 这个函数**一定会**重新上色,没有"只换 CSS 不上色"的开关。
|
||||
* 3.2.44 曾有一个 noRecolor 参数供初始化时跳过上色,理由是
|
||||
* "省一次计算",结果首屏永远没颜色(见 init 里的注释)。
|
||||
* 一个"能否跳过核心动作"的参数,调用方迟早会用错,
|
||||
* 而且用错之后**画面看着像正常工作**(配色边框都变了)。
|
||||
* ⇒ 干脆不要这个参数。recolor 从 textContent 重算是幂等的,
|
||||
* 多跑一次的开销可以忽略(一段 284 字符的样例)。
|
||||
*
|
||||
* @param {string} key 配色 key,如 'monokai'
|
||||
*/
|
||||
function applyTheme(key, noRecolor) {
|
||||
function applyTheme(key) {
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
@@ -89,30 +96,39 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* 等 CSS 真正生效后再重新上色。
|
||||
* 用 onload 而不是 setTimeout:网络快时不用白等,慢时也不会提前上色。 */
|
||||
link.onload = function () {
|
||||
if (!noRecolor) {
|
||||
recolor();
|
||||
}
|
||||
};
|
||||
/* 🔴 recolor 不能只挂在 link.onload 上。
|
||||
*
|
||||
* onload 不可靠的三种情况(都实测过或必然会发生):
|
||||
* ① 样式表**已经在缓存里**、浏览器直接复用 ⇒ 某些浏览器不发 onload;
|
||||
* ② 同一 URL 的 link 被移除后又插回来,事件可能不重放;
|
||||
* ③ jsdom 等无网络环境**永远不触发** —— 于是自动化测试里
|
||||
* 代码永远是单色的,而"测试替我注入 hljs"又让问题看起来
|
||||
* 像别的原因(3.2.44 排查时绕了很久)。
|
||||
*
|
||||
* ⇒ 主路径改成 **rAF/setTimeout 排队**,onload 只作为"提前一拍"的加速。
|
||||
* 两条路径都是幂等的(recolor 从 textContent 重算),重复调用无害。 */
|
||||
var fired = false;
|
||||
function once() {
|
||||
if (fired) { return; }
|
||||
fired = true;
|
||||
recolor();
|
||||
}
|
||||
|
||||
link.onload = once;
|
||||
link.onerror = function () {
|
||||
/* 加载失败就让预览保持原样,不要清空 —— 清空会让人以为主题坏了 */
|
||||
/* 加载失败就让预览保持原样,不要清空 —— 清空会让人以为主题坏了。
|
||||
* 但**仍然上色**:配色 CSS 没到,token 结构还是对的,
|
||||
* 总比一坨单色字更像"预览在工作"。 */
|
||||
if (window.console && console.warn) {
|
||||
console.warn('[yang-hl] 配色样式加载失败: ' + link.href);
|
||||
}
|
||||
once();
|
||||
};
|
||||
|
||||
document.head.appendChild(link);
|
||||
|
||||
/* 兜底:onload 在某些缓存命中场景下不一定触发。
|
||||
* 这里再排一次微延时重上色,保证最终一定是一致的。
|
||||
* 两次 recolor 是幂等的(内部先清空再写),不会叠加出问题。 */
|
||||
setTimeout(function () {
|
||||
if (!noRecolor) {
|
||||
recolor();
|
||||
}
|
||||
}, 120);
|
||||
/* 主路径:不管 onload 来不来,125ms 后一定上色(配色 CSS 通常早已就绪)。 */
|
||||
setTimeout(once, 125);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,7 +146,19 @@
|
||||
*/
|
||||
function recolor() {
|
||||
var code = document.querySelector('.yang-hl-preview code[data-sample]');
|
||||
if (!code || !window.hljs) {
|
||||
if (!code) {
|
||||
return;
|
||||
}
|
||||
/* 🔴 缺 hljs 时必须出声,绝不能静默 return。
|
||||
* 3.2.44 第一版后台漏加载 hljs,这里只是 `return`,
|
||||
* 结果「预览不高亮」这个 bug 在控制台里**一个字都没有**,
|
||||
* 靠肉眼盯着单色文字猜了很久。静默降级是最难查的一类缺陷。 */
|
||||
if (!window.hljs || typeof window.hljs.highlight !== 'function') {
|
||||
if (window.console && console.error) {
|
||||
console.error('[yang-hl] 预览无法上色:window.hljs 不存在。'
|
||||
+ '检查 yang_hl_admin_assets() 是否 enqueue 了 yang-hl-admin-lib。');
|
||||
}
|
||||
markUnhighlighted(code);
|
||||
return;
|
||||
}
|
||||
var raw = code.textContent;
|
||||
@@ -139,10 +167,31 @@
|
||||
try {
|
||||
res = window.hljs.highlight(raw, { language: lang, ignoreIllegals: true });
|
||||
} catch (e) {
|
||||
if (window.console && console.error) {
|
||||
console.error('[yang-hl] 预览上色失败(' + lang + '):', e);
|
||||
}
|
||||
markUnhighlighted(code);
|
||||
return;
|
||||
}
|
||||
code.innerHTML = res.value;
|
||||
code.className = 'hljs language-' + lang;
|
||||
code.removeAttribute('data-unhighlighted');
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记「这块没能上色」,让问题在画面上也能看出来
|
||||
*
|
||||
* 为什么不静默:预览的全部意义就是"让人看到长什么样"。
|
||||
* 上色失败却显示成一坨单色字,等于给用户一个错误信号 ——
|
||||
* 他会以为"这个配色就是这样的"。加一道虚线边框,至少能分辨
|
||||
* "是配色长这样"还是"根本没跑起来"。
|
||||
*/
|
||||
function markUnhighlighted(code) {
|
||||
code.setAttribute('data-unhighlighted', '1');
|
||||
var card = code.closest ? code.closest('.cb') : null;
|
||||
if (card) {
|
||||
card.setAttribute('data-hl-failed', '1');
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化 */
|
||||
@@ -152,18 +201,22 @@
|
||||
return;
|
||||
}
|
||||
|
||||
/* 初始配色:页面已经由 PHP 输出了选中那套的 CSS(前台样式不在这里加载,
|
||||
* 所以这里要主动插一次;noRecolor=true 让首次不重复计算) */
|
||||
applyTheme(sel.value, true);
|
||||
/* 🔴 首次**必须**上色,不能跳过。
|
||||
*
|
||||
* 3.2.44 第一版这里是 `applyTheme(sel.value, true)`,注释写的理由是
|
||||
* "页面已经由 PHP 输出了选中那套的 CSS,首次不必重复计算"。
|
||||
* 那个理由只对**配色 CSS** 成立 —— PHP 确实没输出任何 token span。
|
||||
*
|
||||
* 实际后果:用户打开后台,看到的是**一坨没有上色的单色代码**;
|
||||
* 只有手动去拨一下下拉框,代码才第一次上色。
|
||||
* 这正好解释了"下面的示例代码并没有高亮"这个报障 ——
|
||||
* 它不是完全不工作,是**首屏不工作**。
|
||||
*
|
||||
* ⇒ 首次与切换走同一条路径,行为一致才不会有这种"半开"的 bug。 */
|
||||
applyTheme(sel.value);
|
||||
|
||||
sel.addEventListener('change', function () {
|
||||
applyTheme(sel.value, false);
|
||||
});
|
||||
|
||||
/* 有些场景下框架会程序化改 select.value(比如"恢复默认"),
|
||||
* change 事件不会触发 ⇒ 监听 click 兜底 */
|
||||
sel.addEventListener('click', function () {
|
||||
/* 点击展开下拉不算切换,交给 change 处理 */
|
||||
applyTheme(sel.value);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user