fix(widgets): restore single-card reference UI for search and quote widgets
The 搜索框 and 一言 sidebar widgets fell into the generic renderer branch, so they rendered a .jio-panel card wrapping a second bespoke card (.jio-widget-search / .jio-widget-quote). In-article 一言 also used divergent modifier classes and an extra hover rule. - search: render through the shared jio_get_search_box() (legacy keyword, history and category pickers) inside one reference card, mirroring the reference widget's markup and title default 「搜索」 - quote: render the reference .yiyan-box card itself as the click root; the shell now emits only the reference widget-container/title wrapper - article 一言: adopt the reference class lists for header, footer and the standalone after-article box; drop the invented yiyan--* modifiers and the duplicate hover/opacity rules - client: fill .cn/.en in the reference order (first line .cn, second .en) and drop the stale window.JioYiyan bridge plus the dead qv-yiyan.php AJAX path in runtime main.js - schema: replace the ad-hoc search_style radio with the reference switches (keywords, history, input category, more_cats) and default title - assets: enqueue assets/js/yiyan.js through the quote widget's asset list Tests: widget-system suite 820/821 (the one failure is the pre-existing frontend-lifecycle theme-init stub); new search/quote card contracts pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1549d5b25d
commit
f80ca1e27d
19 files changed
+276
-182
No files matched your search
@@ -1,45 +1,3 @@
|
||||
/* ---- Yiyan inline blocks (single post) ---- */
|
||||
.yiyan--header,
|
||||
.yiyan--footer {
|
||||
margin: 16px 0;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.yiyan--box {
|
||||
margin: 24px 0;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
background: var(--card-bg, #fff);
|
||||
box-shadow: var(--card-shadow, 0 2px 8px rgba(0, 0, 0, .06));
|
||||
}
|
||||
|
||||
.jio-yiyan[data-jio-yiyan] {
|
||||
cursor: pointer;
|
||||
transition: box-shadow .2s ease, opacity .2s ease;
|
||||
}
|
||||
|
||||
.jio-yiyan[data-jio-yiyan]:hover,
|
||||
.jio-yiyan[data-jio-yiyan]:focus-visible {
|
||||
box-shadow: inset 0 0 5px 0 var(--focus-shadow-color, rgba(253, 83, 161, .3));
|
||||
}
|
||||
|
||||
.jio-yiyan .yiyan {
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.jio-yiyan .yiyan .en {
|
||||
font-size: .9em;
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
.jio-yiyan.is-loading {
|
||||
opacity: .65;
|
||||
}
|
||||
|
||||
.jio-yiyan.is-error .cn {
|
||||
color: var(--muted-color, #777);
|
||||
}
|
||||
|
||||
/* ---- Front / After content insertion ---- */
|
||||
.article-front-content,
|
||||
.article-after-content {
|
||||
|
||||
@@ -4463,41 +4463,7 @@ jQuery(document).ready(function () {
|
||||
.delay(1e3, function () {
|
||||
jQuery(this).remove(), jQuery('#qj_dh_css').remove();
|
||||
});
|
||||
/*一言功能*/
|
||||
function yiyan_nr(n) {
|
||||
var yylink = _win.uri + '/yiyan/qv-yiyan.php',
|
||||
y_nr;
|
||||
jQuery.ajax({
|
||||
type: 'POST',
|
||||
url: yylink,
|
||||
}).done(function (i) {
|
||||
var lines = i
|
||||
.replace(/\r\n|\r/g, '/&/')
|
||||
.trim()
|
||||
.split('/&/');
|
||||
if (lines) {
|
||||
var type = n.attr('type');
|
||||
if (type) {
|
||||
y_nr = type === 'en' ? lines[0] : lines[1];
|
||||
} else {
|
||||
y_nr = '<div class="cn">' + lines[0] + '</div><div class="en">' + lines[1] + '</div>';
|
||||
}
|
||||
n.html(y_nr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
jQuery('.yiyan').each(function () {
|
||||
yiyan_nr(jQuery(this));
|
||||
}),
|
||||
setInterval(function () {
|
||||
jQuery('.yiyan').each(function () {
|
||||
yiyan_nr(jQuery(this));
|
||||
});
|
||||
}, 3e4);
|
||||
jQuery('.yiyan').on('click', function () {
|
||||
yiyan_nr(jQuery(this));
|
||||
});
|
||||
/*一言功能由 assets/js/yiyan.js 单独负责([data-jio-yiyan])*/
|
||||
|
||||
/*文章目录由 Jio section-navs 按需入队,legacy 不再重复加载。*/
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
(function($,window2,document2){"use strict";function closeNotyf($element){$element.addClass("notyn-out"),window2.setTimeout(function(){$element.remove()},1e3)}function notyf2(message,type,time,id){var $body=jQuery(document2.body);jQuery(".notyn").length||$body.append('<div class="notyn"></div>'),type=type||"success",type==="error"&&(type="danger"),time=time||5e3,time=time<100?time*1e3:time;var idAttribute=id?' id="'+id+'"':"",$notification=jQuery('<div class="noty1"'+idAttribute+'><div class="notyf '+type+'">'+message+"</div></div>"),shouldClose=!id;id&&jQuery("#"+id).length?(jQuery("#"+id).find(".notyf").removeClass().addClass("notyf "+type).html(message),$notification=jQuery("#"+id),shouldClose=!0):jQuery(".notyn").append($notification),shouldClose&&window2.setTimeout(function(){closeNotyf($notification)},time)}jQuery(document2.body).on("click",".noty1",function(){closeNotyf(jQuery(this))}),window2.notyf=notyf2})(jQuery,window,document),(function(window2){"use strict";var allowedKinds={identity:!0,badges:!0,orders:!0,vip:!0},allowedEvents={click:!0,shell:!0,"first-content":!0,ready:!0,"action-start":!0,"action-end":!0,unauthorized:!0,error:!0},sessions=Object.create(null),sequence=0,maxSessions=100;function normalize(value,fallback){var normalized=String(value||fallback||"").toLowerCase().replace(/[^a-z0-9-]/g,"");return normalized||fallback}function now(){return window2.performance&&typeof window2.performance.now=="function"?window2.performance.now():0}function markName(session,event){return"jio-modal-"+session.kind+"-"+session.id+"-"+event}function emit(session,event){if(!(!window2.performance||typeof window2.performance.mark!="function")){var name=markName(session,event);if(window2.performance.mark(name),session.marks[event]=name,typeof window2.performance.measure=="function"&&session.marks.click&&event!=="click")try{window2.performance.measure("jio-modal-"+session.kind+"-"+session.id+"-click-to-"+event,session.marks.click,name)}catch{}}}function start(kind){var safeKind=normalize(kind,"unknown");allowedKinds[safeKind]||(safeKind="unknown"),sequence+=1;var id=String(sequence),session={id,kind:safeKind,startedAt:now(),marks:Object.create(null)};sessions[id]=session,emit(session,"click");for(var ids=Object.keys(sessions);ids.length>maxSessions;)delete sessions[ids.shift()];return id}function mark(id,event){var session=sessions[String(id||"")],safeEvent=normalize(event,"error");!session||!allowedEvents[safeEvent]||emit(session,safeEvent)}function finish(id){mark(id,"ready")}function fail(id){mark(id,"error")}window2.JioModalTelemetry={start,mark,finish,error:fail}})(window),(function(window2){"use strict";function data(){return window2.jioData||window2.jio||{}}function createIdempotencyKey(){if(window2.crypto&&typeof window2.crypto.randomUUID=="function")return window2.crypto.randomUUID();if(!window2.crypto||typeof window2.crypto.getRandomValues!="function")throw new Error("当前浏览器无法生成安全的操作标识");var bytes=new Uint8Array(16);window2.crypto.getRandomValues(bytes),bytes[6]=bytes[6]&15|64,bytes[8]=bytes[8]&63|128;var hex=Array.prototype.map.call(bytes,function(value){return value.toString(16).padStart(2,"0")}).join("");return hex.slice(0,8)+"-"+hex.slice(8,12)+"-"+hex.slice(12,16)+"-"+hex.slice(16,20)+"-"+hex.slice(20)}function restBase(){var config=data(),raw=config.restUrl||config.apiUrl||config.rest_url||"",siteUrl=config.siteUrl||config.homeUrl||window2.location.origin+"/";return window2.location.protocol==="https:"&&siteUrl.substring(0,5)==="http:"&&(siteUrl="https:"+siteUrl.substring(5)),raw?String(raw).replace(/\/$/,""):String(siteUrl).replace(/\/$/,"")+"/index.php?rest_route=/jio/v1"}function appendQuery(url2,query){if(!query)return url2;var parts=[];return typeof query=="string"?parts=query.replace(/^\?/,"").split("&").filter(Boolean):typeof query=="object"&&Object.keys(query).forEach(function(key){query[key]===void 0||query[key]===null||parts.push(encodeURIComponent(key)+"="+encodeURIComponent(String(query[key])))}),parts.length?url2+(url2.indexOf("?")>=0?"&":"?")+parts.join("&"):url2}function url(path,query){path=String(path||"");var inlineQuery="",queryIndex=path.indexOf("?");if(queryIndex>=0&&(inlineQuery=path.slice(queryIndex+1),path=path.slice(0,queryIndex)),/^https?:\/\//i.test(path))return appendQuery(path,query||inlineQuery);path.charAt(0)!=="/"&&(path="/"+path);var base=restBase(),result=(base.indexOf("rest_route=")>=0,base+path);return appendQuery(result,query||inlineQuery)}function headers(options){var config=data(),source=options&&options.headers||{},result={},nonce=config.restNonce||config.nonce||"";return Object.keys(source).forEach(function(key){result[key]=source[key]}),result.Accept||(result.Accept="application/json, text/html;q=0.9, */*;q=0.8"),nonce&&!result["X-WP-Nonce"]&&(result["X-WP-Nonce"]=nonce),options&&options.body!==void 0&&options.body!==null&&!(window2.FormData&&options.body instanceof window2.FormData)&&!result["Content-Type"]&&(result["CoLine truncated
|
||||
(function($,window2,document2){"use strict";function closeNotyf($element){$element.addClass("notyn-out"),window2.setTimeout(function(){$element.remove()},1e3)}function notyf2(message,type,time,id){var $body=jQuery(document2.body);jQuery(".notyn").length||$body.append('<div class="notyn"></div>'),type=type||"success",type==="error"&&(type="danger"),time=time||5e3,time=time<100?time*1e3:time;var idAttribute=id?' id="'+id+'"':"",$notification=jQuery('<div class="noty1"'+idAttribute+'><div class="notyf '+type+'">'+message+"</div></div>"),shouldClose=!id;id&&jQuery("#"+id).length?(jQuery("#"+id).find(".notyf").removeClass().addClass("notyf "+type).html(message),$notification=jQuery("#"+id),shouldClose=!0):jQuery(".notyn").append($notification),shouldClose&&window2.setTimeout(function(){closeNotyf($notification)},time)}jQuery(document2.body).on("click",".noty1",function(){closeNotyf(jQuery(this))}),window2.notyf=notyf2})(jQuery,window,document),(function(window2){"use strict";var allowedKinds={identity:!0,badges:!0,orders:!0,vip:!0},allowedEvents={click:!0,shell:!0,"first-content":!0,ready:!0,"action-start":!0,"action-end":!0,unauthorized:!0,error:!0},sessions=Object.create(null),sequence=0,maxSessions=100;function normalize(value,fallback){var normalized=String(value||fallback||"").toLowerCase().replace(/[^a-z0-9-]/g,"");return normalized||fallback}function now(){return window2.performance&&typeof window2.performance.now=="function"?window2.performance.now():0}function markName(session,event){return"jio-modal-"+session.kind+"-"+session.id+"-"+event}function emit(session,event){if(!(!window2.performance||typeof window2.performance.mark!="function")){var name=markName(session,event);if(window2.performance.mark(name),session.marks[event]=name,typeof window2.performance.measure=="function"&&session.marks.click&&event!=="click")try{window2.performance.measure("jio-modal-"+session.kind+"-"+session.id+"-click-to-"+event,session.marks.click,name)}catch{}}}function start(kind){var safeKind=normalize(kind,"unknown");allowedKinds[safeKind]||(safeKind="unknown"),sequence+=1;var id=String(sequence),session={id,kind:safeKind,startedAt:now(),marks:Object.create(null)};sessions[id]=session,emit(session,"click");for(var ids=Object.keys(sessions);ids.length>maxSessions;)delete sessions[ids.shift()];return id}function mark(id,event){var session=sessions[String(id||"")],safeEvent=normalize(event,"error");!session||!allowedEvents[safeEvent]||emit(session,safeEvent)}function finish(id){mark(id,"ready")}function fail(id){mark(id,"error")}window2.JioModalTelemetry={start,mark,finish,error:fail}})(window),(function(window2){"use strict";function data(){return window2.jioData||window2.jio||{}}function createIdempotencyKey(){if(window2.crypto&&typeof window2.crypto.randomUUID=="function")return window2.crypto.randomUUID();if(!window2.crypto||typeof window2.crypto.getRandomValues!="function")throw new Error("当前浏览器无法生成安全的操作标识");var bytes=new Uint8Array(16);window2.crypto.getRandomValues(bytes),bytes[6]=bytes[6]&15|64,bytes[8]=bytes[8]&63|128;var hex=Array.prototype.map.call(bytes,function(value){return value.toString(16).padStart(2,"0")}).join("");return hex.slice(0,8)+"-"+hex.slice(8,12)+"-"+hex.slice(12,16)+"-"+hex.slice(16,20)+"-"+hex.slice(20)}function restBase(){var config=data(),raw=config.restUrl||config.apiUrl||config.rest_url||"",siteUrl=config.siteUrl||config.homeUrl||window2.location.origin+"/";return window2.location.protocol==="https:"&&siteUrl.substring(0,5)==="http:"&&(siteUrl="https:"+siteUrl.substring(5)),raw?String(raw).replace(/\/$/,""):String(siteUrl).replace(/\/$/,"")+"/index.php?rest_route=/jio/v1"}function appendQuery(url2,query){if(!query)return url2;var parts=[];return typeof query=="string"?parts=query.replace(/^\?/,"").split("&").filter(Boolean):typeof query=="object"&&Object.keys(query).forEach(function(key){query[key]===void 0||query[key]===null||parts.push(encodeURIComponent(key)+"="+encodeURIComponent(String(query[key])))}),parts.length?url2+(url2.indexOf("?")>=0?"&":"?")+parts.join("&"):url2}function url(path,query){path=String(path||"");var inlineQuery="",queryIndex=path.indexOf("?");if(queryIndex>=0&&(inlineQuery=path.slice(queryIndex+1),path=path.slice(0,queryIndex)),/^https?:\/\//i.test(path))return appendQuery(path,query||inlineQuery);path.charAt(0)!=="/"&&(path="/"+path);var base=restBase(),result=(base.indexOf("rest_route=")>=0,base+path);return appendQuery(result,query||inlineQuery)}function headers(options){var config=data(),source=options&&options.headers||{},result={},nonce=config.restNonce||config.nonce||"";return Object.keys(source).forEach(function(key){result[key]=source[key]}),result.Accept||(result.Accept="application/json, text/html;q=0.9, */*;q=0.8"),nonce&&!result["X-WP-Nonce"]&&(result["X-WP-Nonce"]=nonce),options&&options.body!==void 0&&options.body!==null&&!(window2.FormData&&options.body instanceof window2.FormData)&&!result["Content-Type"]&&(result["CoLine truncated
|
||||
+22
-8
@@ -26,10 +26,26 @@
|
||||
var quote = response && response.success && response.data;
|
||||
if (!quote || !quote.cn || !quote.en) throw new Error('empty quote');
|
||||
|
||||
var cn = el.querySelector('.cn');
|
||||
var en = el.querySelector('.en');
|
||||
if (cn) cn.textContent = quote.cn;
|
||||
if (en) en.textContent = quote.en;
|
||||
// 参考结构:.yiyan 初始为空,由脚本写入首行 .cn 与次行 .en。
|
||||
var body = el.querySelector('.yiyan');
|
||||
if (body) {
|
||||
var cn = body.querySelector('.cn');
|
||||
var en = body.querySelector('.en');
|
||||
if (cn && en) {
|
||||
cn.textContent = quote.en;
|
||||
en.textContent = quote.cn;
|
||||
} else {
|
||||
body.innerHTML = '';
|
||||
var lineCn = document.createElement('div');
|
||||
lineCn.className = 'cn';
|
||||
lineCn.textContent = quote.en;
|
||||
var lineEn = document.createElement('div');
|
||||
lineEn.className = 'en';
|
||||
lineEn.textContent = quote.cn;
|
||||
body.appendChild(lineCn);
|
||||
body.appendChild(lineEn);
|
||||
}
|
||||
}
|
||||
el.classList.remove('is-loading');
|
||||
el.classList.remove('is-error');
|
||||
el.classList.add('is-ready');
|
||||
@@ -37,8 +53,8 @@
|
||||
.catch(function () {
|
||||
el.classList.remove('is-loading');
|
||||
el.classList.add('is-error');
|
||||
var cn = el.querySelector('.cn');
|
||||
if (cn && !el.classList.contains('is-ready')) cn.textContent = '加载失败,点击重试';
|
||||
var body = el.querySelector('.yiyan');
|
||||
if (body && !el.classList.contains('is-ready')) body.textContent = '加载失败,点击重试';
|
||||
})
|
||||
.finally(function () {
|
||||
delete el.dataset.loading;
|
||||
@@ -70,8 +86,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
window.JioYiyan = { init: init };
|
||||
|
||||
if (window.jQuery) {
|
||||
window.jQuery(document).off('auto_fun.jio-yiyan').on('auto_fun.jio-yiyan', function () {
|
||||
init(document);
|
||||
|
||||
@@ -43,17 +43,8 @@
|
||||
.jio-widget--affix { position: sticky; top: 76px; }
|
||||
.jio-widget--only-mobile { display: none; }
|
||||
|
||||
.jio-widget-search { display: flex; min-height: 42px; padding: 4px; border: 1px solid var(--main-border-color,rgba(127,127,127,.18)); border-radius: var(--main-radius,8px); background: var(--main-bg-color, #fff); }
|
||||
.jio-widget-search label { flex: 1; display: flex; }
|
||||
.jio-widget-search input { width: 100%; padding: 8px 12px; border: 0; outline: 0; background: transparent; color: inherit; }
|
||||
.jio-widget-search button { display: flex; align-items: center; gap: 7px; padding: 7px 14px; border: 0; border-radius: var(--mini-radius,4px); background: var(--focus-color, #ff5473); color: #fff; cursor: pointer; }
|
||||
.jio-widget-search--compact button span { display: none; }
|
||||
.jio-widget-search--large { min-height: 58px; border-radius: 14px; }
|
||||
|
||||
.jio-widget-quote { margin: 0; padding: 12px 15px; border-radius: var(--jio-widget-radius); background: var(--main-bg-color, #fff); color: var(--main-color, inherit); box-shadow: 0 0 10px var(--main-shadow, rgba(116,116,116,.08)); }
|
||||
.jio-widget-quote .yiyan { line-height: 1.8; }
|
||||
.jio-widget-quote .yiyan .en { font-size: .9em; opacity: .8; }
|
||||
.jio-widget-quote.is-loading { opacity: .65; }
|
||||
/* 搜索框与一言复用 main.css 中的参考卡片(.search-input / .yiyan-box),
|
||||
* 这里不再重复定义表面样式,避免与卡片叠加。 */
|
||||
|
||||
/* The Jio base stylesheet already carries the icon-card and utility rules.
|
||||
* Restore the one renamed primitive used verbatim by these two widget renderers. */
|
||||
|
||||
@@ -74,11 +74,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function initQuote(figure) {
|
||||
if (!once(figure, 'Quote')) return;
|
||||
if (window.JioYiyan) window.JioYiyan.init(figure);
|
||||
}
|
||||
|
||||
function errorMarkup(page, append) {
|
||||
var i18n = config.i18n || {};
|
||||
return '<div class="jio-widget-request-error" role="alert"><span>' + (i18n.error || '加载失败,请重试。') + '</span><button type="button" data-widget-retry data-retry-page="' + page + '" data-retry-append="' + (append ? '1' : '0') + '">' + (i18n.retry || '重试') + '</button></div>';
|
||||
@@ -357,7 +352,6 @@
|
||||
function scan(root) {
|
||||
var scope = root || document;
|
||||
scope.querySelectorAll('.jio-widget-video[data-video-url]').forEach(initVideo);
|
||||
scope.querySelectorAll('.jio-widget-quote').forEach(initQuote);
|
||||
if (scope.matches && scope.matches('[data-widget-items]')) initItems(scope);
|
||||
scope.querySelectorAll('[data-widget-items]').forEach(initItems);
|
||||
scope.querySelectorAll('.widget-tab-post').forEach(initTabs);
|
||||
|
||||
@@ -249,7 +249,7 @@ if (!function_exists('jio_single_render_content_footer')) :
|
||||
<?php if (!empty($settings['yiyan_footer'])) : ?>
|
||||
<?php
|
||||
jio_render_yiyan_block([
|
||||
'class' => 'article-yiyan yiyan-box jio-yiyan yiyan--footer',
|
||||
'class' => 'article-yiyan theme-box text-center radius8 main-shadow yiyan-box jio-yiyan',
|
||||
]);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
@@ -604,7 +604,7 @@ if (!function_exists('jio_single_render_article')) :
|
||||
<?php if (!empty($settings['yiyan_header'])) : ?>
|
||||
<?php
|
||||
jio_render_yiyan_block([
|
||||
'class' => 'article-yiyan yiyan-box jio-yiyan yiyan--header theme-box text-center radius8 main-shadow',
|
||||
'class' => 'article-yiyan theme-box text-center radius8 main-shadow yiyan-box jio-yiyan',
|
||||
]);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
@@ -662,10 +662,9 @@ if (!function_exists('jio_single_render_after_box')) :
|
||||
'class' => 'yiyan-box main-bg theme-box text-center box-body radius8 main-shadow jio-yiyan',
|
||||
]);
|
||||
}
|
||||
|
||||
if (!empty($settings['authordesc'])) {
|
||||
jio_single_render_author_card($ctx);
|
||||
}
|
||||
if (!empty($settings['authordesc'])) {
|
||||
jio_single_render_author_card($ctx);
|
||||
}
|
||||
|
||||
jio_single_render_prevnext($ctx);
|
||||
jio_single_render_related($ctx);
|
||||
|
||||
@@ -60,6 +60,7 @@ if (!function_exists('jio_render_yiyan_block')) :
|
||||
if (strpos($class, 'jio-yiyan') === false) {
|
||||
$class = trim($class . ' jio-yiyan');
|
||||
}
|
||||
// 与参考结构一致:.yiyan 初始为空,由脚本写入 .cn(首行)与 .en(次行)。
|
||||
$html = '<div class="' . esc_attr($class) . '"'
|
||||
. ' data-jio-yiyan'
|
||||
. ' data-endpoint="' . esc_url(admin_url('admin-ajax.php')) . '"'
|
||||
@@ -68,7 +69,7 @@ if (!function_exists('jio_render_yiyan_block')) :
|
||||
. ' role="button" tabindex="0"'
|
||||
. ' aria-label="' . esc_attr__('点击切换一言', 'jio') . '"'
|
||||
. ' aria-live="polite">'
|
||||
. '<div class="yiyan"><div class="en"></div><div class="cn">' . esc_html__('加载中…', 'jio') . '</div></div>'
|
||||
. '<div class="yiyan"></div>'
|
||||
. '</div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
@@ -300,63 +300,43 @@ if (!function_exists('jio_get_search_box')) :
|
||||
// Popular keywords.
|
||||
$keywords_html = '';
|
||||
if (!empty($args['show_keywords'])) {
|
||||
$show = true;
|
||||
if (class_exists('\Jio\Settings\Settings') && method_exists('\Jio\Settings\Settings', 'hot_search_enabled')) {
|
||||
$show = (bool) \Jio\Settings\Settings::hot_search_enabled();
|
||||
}
|
||||
if ($show) {
|
||||
$keywords = function_exists('jio_get_search_hot_keywords') ? jio_get_search_hot_keywords() : [];
|
||||
$limit = (int) $args['popular_limit'];
|
||||
$keyword_link = jio_get_search_keywords_but(is_array($keywords) ? $keywords : [], 'popular', $limit);
|
||||
if ($keyword_link !== '') {
|
||||
$keywords_html = '<div class="search-keywords">'
|
||||
. '<p class="muted-color"><span>' . esc_html((string) $args['keywords_title']) . '</span></p>'
|
||||
. '<div>' . $keyword_link . '</div>'
|
||||
. '</div>';
|
||||
}
|
||||
$keywords = function_exists('jio_get_search_hot_keywords') ? jio_get_search_hot_keywords() : [];
|
||||
$limit = (int) $args['popular_limit'];
|
||||
$keyword_link = jio_get_search_keywords_but(is_array($keywords) ? $keywords : [], 'popular', $limit);
|
||||
if ($keyword_link !== '') {
|
||||
$keywords_html = '<div class="search-keywords">'
|
||||
. '<p class="muted-color"><span>' . esc_html((string) $args['keywords_title']) . '</span></p>'
|
||||
. '<div>' . $keyword_link . '</div>'
|
||||
. '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
// History.
|
||||
$history_html = '';
|
||||
if (!empty($args['show_history'])) {
|
||||
$show_h = true;
|
||||
if (function_exists('jio_search_history_enabled')) {
|
||||
$show_h = jio_search_history_enabled();
|
||||
} elseif (class_exists('\Jio\Settings\Settings') && method_exists('\Jio\Settings\Settings', 'search_history_enabled')) {
|
||||
$show_h = (bool) \Jio\Settings\Settings::search_history_enabled();
|
||||
}
|
||||
if ($show_h) {
|
||||
$hist = jio_get_search_history_keywords();
|
||||
$keyword_link = jio_get_search_keywords_but($hist, 'history');
|
||||
if ($keyword_link !== '') {
|
||||
$history_html = '<div class="search-keywords history-search">';
|
||||
$history_html .= '<p class="muted-color"><span>' . esc_html__('历史搜索', 'jio') . '</span>';
|
||||
$history_html .= '<a class="pull-right trash-history-search muted-3-color" href="javascript:;" data-cookie-path="'
|
||||
. esc_attr(COOKIEPATH ?: '/') . '" data-cookie-domain="' . esc_attr(COOKIE_DOMAIN) . '" aria-label="'
|
||||
. esc_attr__('清空历史', 'jio') . '"><i class="fa fas fa-trash-alt em12" aria-hidden="true"></i></a></p>';
|
||||
$history_html .= '<div>' . $keyword_link . '</div></div>';
|
||||
}
|
||||
$hist = jio_get_search_history_keywords();
|
||||
$keyword_link = jio_get_search_keywords_but($hist, 'history');
|
||||
if ($keyword_link !== '') {
|
||||
$history_html = '<div class="search-keywords history-search">';
|
||||
$history_html .= '<p class="muted-color"><span>' . esc_html__('历史搜索', 'jio') . '</span>';
|
||||
$history_html .= '<a class="pull-right trash-history-search muted-3-color" href="javascript:;" data-cookie-path="'
|
||||
. esc_attr(COOKIEPATH ?: '/') . '" data-cookie-domain="' . esc_attr(COOKIE_DOMAIN) . '" aria-label="'
|
||||
. esc_attr__('清空历史', 'jio') . '"><i class="fa fas fa-trash-alt em12" aria-hidden="true"></i></a></p>';
|
||||
$history_html .= '<div>' . $keyword_link . '</div></div>';
|
||||
}
|
||||
}
|
||||
|
||||
// Hot posts (thumb swiper).
|
||||
$posts_html = '';
|
||||
if (!empty($args['show_posts'])) {
|
||||
$show_p = true;
|
||||
if (class_exists('\Jio\Settings\Settings') && method_exists('\Jio\Settings\Settings', 'search_posts_enabled')) {
|
||||
$show_p = (bool) \Jio\Settings\Settings::search_posts_enabled();
|
||||
}
|
||||
if ($show_p && function_exists('jio_get_search_posts')) {
|
||||
$slides = jio_get_search_posts(6, 'views', true);
|
||||
if ($slides !== '') {
|
||||
$posts_html = '<div class="padding-10 relates relates-thumb">';
|
||||
$posts_html .= '<p class="muted-color">' . esc_html__('热门文章', 'jio') . '</p>';
|
||||
$posts_html .= '<div class="swiper-container swiper-scroll">';
|
||||
$posts_html .= '<div class="swiper-wrapper">' . $slides . '</div>';
|
||||
$posts_html .= '<div class="swiper-button-prev"></div><div class="swiper-button-next"></div>';
|
||||
$posts_html .= '</div></div>';
|
||||
}
|
||||
if (!empty($args['show_posts']) && function_exists('jio_get_search_posts')) {
|
||||
$slides = jio_get_search_posts(6, 'views', true);
|
||||
if ($slides !== '') {
|
||||
$posts_html = '<div class="padding-10 relates relates-thumb">';
|
||||
$posts_html .= '<p class="muted-color">' . esc_html__('热门文章', 'jio') . '</p>';
|
||||
$posts_html .= '<div class="swiper-container swiper-scroll">';
|
||||
$posts_html .= '<div class="swiper-wrapper">' . $slides . '</div>';
|
||||
$posts_html .= '<div class="swiper-button-prev"></div><div class="swiper-button-next"></div>';
|
||||
$posts_html .= '</div></div>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ final class AssetManager {
|
||||
wp_register_style('jio-pay-box', $uri . '/assets/css/frontend/pay-box.css', ['jio-public'], is_file($pay_css) ? (string) filemtime($pay_css) : null);
|
||||
$yiyan_js = $root . '/assets/js/yiyan.js';
|
||||
wp_register_script('jio-yiyan', $uri . '/assets/js/yiyan.js', ['loader_js'], is_file($yiyan_js) ? (string) filemtime($yiyan_js) : null, true);
|
||||
wp_register_script(self::SCRIPT_HANDLE, $uri . '/assets/widgets/frontend.js', ['loader_js', 'jio-yiyan'], is_file($js) ? (string) filemtime($js) : null, true);
|
||||
wp_register_script(self::SCRIPT_HANDLE, $uri . '/assets/widgets/frontend.js', ['loader_js'], is_file($js) ? (string) filemtime($js) : null, true);
|
||||
$third_party = $uri . '/assets/widgets/third-party/';
|
||||
wp_register_script('jio-widget-hls', $third_party . 'hls.min.js', [], 'reference-pinned', true);
|
||||
wp_register_script('jio-widget-flv', $third_party . 'flv.min.js', [], 'reference-pinned', true);
|
||||
@@ -77,6 +77,8 @@ final class AssetManager {
|
||||
wp_enqueue_script('jio-widget-' . $asset);
|
||||
} elseif ($asset === 'tilt') {
|
||||
wp_enqueue_script('jio-widget-tilt');
|
||||
} elseif ($asset === 'yiyan') {
|
||||
wp_enqueue_script('jio-yiyan');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,10 @@ final class FrontendRenderer {
|
||||
echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return;
|
||||
}
|
||||
if (in_array($definition->slug(), ['search', 'quote'], true)) {
|
||||
self::render_reference_widget($definition, $instance, $widget, $content, true);
|
||||
return;
|
||||
}
|
||||
if (in_array($definition->slug(), ['user_card', 'author_card', 'tab_posts', 'posts'], true)) {
|
||||
self::render_reference_widget($definition, $instance, $widget, $content);
|
||||
return;
|
||||
@@ -90,7 +94,13 @@ final class FrontendRenderer {
|
||||
echo (string) ($args['after_widget'] ?? '</section>'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
private static function render_reference_widget(WidgetDefinition $definition, array $instance, SchemaWidget $widget, string $content): void {
|
||||
/**
|
||||
* 参考主题侧栏结构:widget-container > 标题 + 内容。
|
||||
*
|
||||
* 搜索框 / 一言自带卡片(.zib-widget.widget-search / .yiyan-box),
|
||||
* 此时不再套 .widget-content 与第二层卡片;其余模块保持 .widget-content 结构层。
|
||||
*/
|
||||
private static function render_reference_widget(WidgetDefinition $definition, array $instance, SchemaWidget $widget, string $content, bool $own_card = false): void {
|
||||
$classes = ['jio-widget-box-wrap', 'jio-' . str_replace('_', '-', $definition->slug()) . '-wrap'];
|
||||
if (in_array($definition->slug(), ['user_card', 'author_card'], true)) {
|
||||
$classes[] = 'jio-user-widget-wrap';
|
||||
@@ -103,12 +113,12 @@ final class FrontendRenderer {
|
||||
$classes[] = 'jio-widget--affix';
|
||||
}
|
||||
|
||||
$content_classes = ['widget-content'];
|
||||
$animation = '';
|
||||
if (!empty($instance['animation_in'])) {
|
||||
$content_classes[] = 'obs-animate ani-' . sanitize_html_class((string) $instance['animation_in']);
|
||||
}
|
||||
if (!empty($instance['animation_repeat'])) {
|
||||
$content_classes[] = 'obs-animate-repeat';
|
||||
$animation = ' obs-animate ani-' . sanitize_html_class((string) $instance['animation_in']);
|
||||
if (!empty($instance['animation_repeat'])) {
|
||||
$animation .= ' obs-animate-repeat';
|
||||
}
|
||||
}
|
||||
|
||||
$style = self::style($instance);
|
||||
@@ -116,7 +126,11 @@ final class FrontendRenderer {
|
||||
echo '<div class="' . esc_attr(implode(' ', $classes)) . '" data-jio-widget="' . esc_attr($definition->slug()) . '" data-widget-id="' . esc_attr((string) $widget->id) . '"' . $affix_attr . ($style !== '' ? ' style="' . esc_attr($style) . '"' : '') . '>';
|
||||
echo '<div class="widget-container"><div>';
|
||||
echo self::reference_title($instance); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<div class="' . esc_attr(implode(' ', $content_classes)) . '">' . $content . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
if ($own_card) {
|
||||
echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
} else {
|
||||
echo '<div class="widget-content' . esc_attr($animation) . '">' . $content . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
echo '</div></div></div>';
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,27 @@ final class GeneralRenderer {
|
||||
}
|
||||
|
||||
private static function render_search(array $i): string {
|
||||
$action = esc_url(home_url('/'));
|
||||
$placeholder = esc_attr((string) $i['placeholder']);
|
||||
$style = sanitize_html_class((string) $i['search_style']);
|
||||
return '<form class="jio-widget-search jio-widget-search--' . $style . '" role="search" method="get" action="' . $action . '"><label><span class="screen-reader-text">' . esc_html__('搜索:', 'jio') . '</span><input type="search" name="s" placeholder="' . $placeholder . '" autocomplete="off"></label><button type="submit" aria-label="' . esc_attr__('搜索', 'jio') . '"><i class="fa fas fa-search" aria-hidden="true"></i><span>' . esc_html__('搜索', 'jio') . '</span></button></form>';
|
||||
if (!function_exists('jio_get_search_box')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$selected = array_values(array_filter(array_map('absint', preg_split('/[,,\s]+/', (string) ($i['in_cat'] ?? '')) ?: [])));
|
||||
$more_cats = array_values(array_filter(array_map('absint', preg_split('/[,,\s]+/', (string) ($i['more_cats'] ?? '')) ?: [])));
|
||||
$box = (string) jio_get_search_box([
|
||||
'class' => '',
|
||||
'show_keywords' => !empty($i['show_keywords']),
|
||||
'show_history' => !empty($i['show_history']),
|
||||
'keywords_title' => trim((string) ($i['keywords_title'] ?? '')) !== '' ? (string) $i['keywords_title'] : '热门搜索',
|
||||
'placeholder' => trim((string) ($i['placeholder'] ?? '')) !== '' ? (string) $i['placeholder'] : '开启精彩搜索',
|
||||
'show_input_cat' => !empty($i['show_input_cat']),
|
||||
'in_cat' => $selected ? (int) $selected[0] : 0,
|
||||
'more_cats' => $more_cats,
|
||||
]);
|
||||
if ($box === '') {
|
||||
return '';
|
||||
}
|
||||
// 参考主题:一键外框 .zib-widget.widget-search → 本项目同等卡片 .jio-panel.widget-search。
|
||||
return '<div class="jio-panel widget-search">' . $box . '</div>';
|
||||
}
|
||||
|
||||
private static function render_posts_toc(array $i): string {
|
||||
@@ -34,9 +51,13 @@ final class GeneralRenderer {
|
||||
}
|
||||
|
||||
private static function render_quote(array $i): string {
|
||||
return function_exists('jio_get_yiyan_markup')
|
||||
? jio_get_yiyan_markup(['class' => 'jio-widget-quote'])
|
||||
: '';
|
||||
if (!function_exists('jio_get_yiyan_markup')) {
|
||||
return '';
|
||||
}
|
||||
// 参考主题:.yiyan-box 既是卡片也是点击切换的根元素,内部只有 .yiyan。
|
||||
return jio_get_yiyan_markup([
|
||||
'class' => 'yiyan-box main-bg text-center box-body radius8 main-shadow',
|
||||
]);
|
||||
}
|
||||
|
||||
private static function render_icon_cards(array $i): string {
|
||||
|
||||
@@ -78,6 +78,7 @@ final class WidgetCatalog {
|
||||
],
|
||||
'fields' => WidgetSchemas::for($slug),
|
||||
'assets' => self::assets($slug),
|
||||
'title_default' => $slug === 'search' ? '搜索' : '',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -88,6 +89,9 @@ final class WidgetCatalog {
|
||||
if (in_array($slug, ['slider', 'slider_media_combo', 'reviews', 'oneline_posts'], true)) {
|
||||
return ['swiper'];
|
||||
}
|
||||
if ($slug === 'quote') {
|
||||
return ['yiyan'];
|
||||
}
|
||||
if ($slug === 'video') {
|
||||
return ['dplayer', 'hls', 'flv', 'dash'];
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ final class WidgetDefinition {
|
||||
private array $fields;
|
||||
private array $common;
|
||||
private array $assets;
|
||||
private string $title_default;
|
||||
|
||||
public function __construct(array $definition) {
|
||||
$slug = (string) ($definition['slug'] ?? '');
|
||||
@@ -50,6 +51,7 @@ final class WidgetDefinition {
|
||||
(array) ($definition['common'] ?? [])
|
||||
);
|
||||
$this->assets = array_values(array_unique(array_map('strval', (array) ($definition['assets'] ?? []))));
|
||||
$this->title_default = trim((string) ($definition['title_default'] ?? ''));
|
||||
}
|
||||
|
||||
public function slug(): string {
|
||||
@@ -89,7 +91,16 @@ final class WidgetDefinition {
|
||||
}
|
||||
|
||||
public function fields(): array {
|
||||
return array_merge(CommonFields::for_definition($this->common), $this->fields);
|
||||
$fields = array_merge(CommonFields::for_definition($this->common), $this->fields);
|
||||
if ($this->title_default !== '' && !empty($this->common['title'])) {
|
||||
foreach ($fields as $index => $field) {
|
||||
if (($field['id'] ?? '') === 'title') {
|
||||
$fields[$index]['default'] = $this->title_default;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/** Admin form layout: reference header (description, reminder), common params, then the "模块内容配置" subheading. */
|
||||
|
||||
@@ -33,8 +33,19 @@ final class WidgetSchemas {
|
||||
switch ($slug) {
|
||||
case 'search':
|
||||
return [
|
||||
['id' => 'placeholder', 'type' => 'text', 'label' => '提示文字', 'default' => '输入关键词搜索'],
|
||||
['id' => 'search_style', 'type' => 'radio', 'label' => '显示样式', 'default' => 'button', 'options' => ['button' => '按钮式', 'compact' => '紧凑式', 'large' => '大尺寸']],
|
||||
['id' => 'placeholder', 'type' => 'text', 'label' => '提示文字', 'default' => '开启精彩搜索'],
|
||||
['id' => 'show_keywords', 'type' => 'switcher', 'label' => '显示热门搜索关键词', 'default' => false],
|
||||
['id' => 'show_history', 'type' => 'switcher', 'label' => '显示用户搜索历史', 'default' => false],
|
||||
['id' => 'keywords_title', 'type' => 'text', 'label' => '热门搜索-标题', 'default' => '热门搜索', 'dependency' => ['show_keywords', '!=', '']],
|
||||
['id' => 'show_input_cat', 'type' => 'switcher', 'label' => '显示分类', 'default' => false],
|
||||
[
|
||||
'id' => 'in_cat', 'type' => 'text', 'label' => '默认已选择的分类', 'default' => '', 'sanitize' => 'ids',
|
||||
'description' => '填写分类ID,可留空', 'dependency' => ['show_input_cat', '!=', ''],
|
||||
],
|
||||
[
|
||||
'id' => 'more_cats', 'type' => 'text', 'label' => '更多分类的ID', 'default' => '', 'sanitize' => 'ids',
|
||||
'description' => '默认为全部分类,如需自定义则将分类的ID填入下方,多个ID用逗号隔开', 'dependency' => ['show_input_cat', '!=', ''],
|
||||
],
|
||||
];
|
||||
case 'posts_toc':
|
||||
return [
|
||||
|
||||
Vendored
+14
-4
@@ -183,10 +183,15 @@
|
||||
"layout_pin_m",
|
||||
"layout_bg",
|
||||
"placeholder",
|
||||
"search_style"
|
||||
"show_keywords",
|
||||
"show_history",
|
||||
"keywords_title",
|
||||
"show_input_cat",
|
||||
"in_cat",
|
||||
"more_cats"
|
||||
],
|
||||
"settings": {
|
||||
"title": "Jio · Search",
|
||||
"title": "搜索",
|
||||
"subtitle": "固定内容与交互状态视觉验收",
|
||||
"title_style": "",
|
||||
"title_highlight": "Jio",
|
||||
@@ -247,8 +252,13 @@
|
||||
"size": "cover"
|
||||
}
|
||||
},
|
||||
"placeholder": "输入关键词搜索",
|
||||
"search_style": "button"
|
||||
"placeholder": "开启精彩搜索",
|
||||
"show_keywords": true,
|
||||
"show_history": true,
|
||||
"keywords_title": "热门搜索",
|
||||
"show_input_cat": true,
|
||||
"in_cat": "101",
|
||||
"more_cats": "101,102"
|
||||
},
|
||||
"root_selector": "[data-jio-widget=\"search\"]",
|
||||
"states": [
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const { execFileSync } = require('node:child_process');
|
||||
|
||||
const root = path.resolve(__dirname, '..', '..');
|
||||
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
|
||||
|
||||
test('搜索框与一言小工具只渲染参考主题的一张卡片', () => {
|
||||
const rendered = JSON.parse(
|
||||
execFileSync(process.env.PHP_BINARY || 'php', [path.join(__dirname, 'search-quote-render-harness.php')], {
|
||||
encoding: 'utf8',
|
||||
})
|
||||
);
|
||||
|
||||
// 参考主题这两个小工具忽略 before_widget,卡片由自身输出一次。
|
||||
assert.doesNotMatch(rendered.search, /jio-widget-shell/);
|
||||
assert.doesNotMatch(rendered.quote, /jio-widget-shell/);
|
||||
|
||||
// 搜索框:widget-container > 标题 + 单张 .widget-search 卡片,且复用共享搜索组件。
|
||||
assert.equal((rendered.search.match(/class="jio-panel/g) || []).length, 1);
|
||||
assert.match(rendered.search, /<div class="widget-container"><div><div class="box-body notop"><div class="title-theme">/);
|
||||
assert.match(rendered.search, /class="jio-panel widget-search"><div class="search-input">/);
|
||||
assert.equal((rendered.search.match(/class="search-input"/g) || []).length, 1);
|
||||
|
||||
// 一言:widget-container > 标题 + 单张 .yiyan-box 卡片(点击根元素即卡片)。
|
||||
assert.equal((rendered.quote.match(/class="yiyan-box/g) || []).length, 1);
|
||||
assert.match(rendered.quote, /<div class="widget-container"><div><div class="box-body notop"><div class="title-theme">/);
|
||||
assert.match(rendered.quote, /class="yiyan-box main-bg text-center box-body radius8 main-shadow jio-yiyan" data-jio-yiyan>/);
|
||||
assert.match(rendered.quote, /<div class="yiyan"><\/div>/);
|
||||
});
|
||||
|
||||
test('搜索框设置沿用参考主题字段,不再提供自造样式选项', () => {
|
||||
const schema = read('src/WidgetSystem/WidgetSchemas.php');
|
||||
const renderer = read('src/WidgetSystem/Renderers/GeneralRenderer.php');
|
||||
const frontend = read('src/WidgetSystem/FrontendRenderer.php');
|
||||
|
||||
for (const field of ["'id' => 'show_keywords'", "'id' => 'show_history'", "'id' => 'keywords_title'", "'id' => 'show_input_cat'", "'id' => 'in_cat'", "'id' => 'more_cats'"]) {
|
||||
assert.match(schema, new RegExp(field.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
||||
}
|
||||
assert.doesNotMatch(schema, /search_style/);
|
||||
assert.doesNotMatch(renderer, /jio-widget-search/);
|
||||
assert.match(renderer, /function_exists\('jio_get_search_box'\)/);
|
||||
|
||||
// 与 TOC 一样由内容自带卡片壳,不走通用 .jio-panel 包裹分支。
|
||||
assert.match(frontend, /\[['"]search['"], ['"]quote['"]\]/);
|
||||
assert.match(frontend, /render_reference_widget\(\$definition, \$instance, \$widget, \$content, true\)/);
|
||||
assert.match(frontend, /bool \$own_card = false/);
|
||||
});
|
||||
|
||||
test('文章内一言沿用参考主题的类名组合,不再使用自定义修饰类', () => {
|
||||
const single = read('inc/helpers/jio-single-render.php');
|
||||
const css = read('assets/css/frontend/single-post/hidden-content.css');
|
||||
|
||||
assert.equal((single.match(/'article-yiyan theme-box text-center radius8 main-shadow yiyan-box jio-yiyan'/g) || []).length, 2);
|
||||
assert.match(single, /'yiyan-box main-bg theme-box text-center box-body radius8 main-shadow jio-yiyan'/);
|
||||
assert.doesNotMatch(single, /yiyan--header|yiyan--footer|yiyan--box/);
|
||||
assert.doesNotMatch(css, /yiyan--header|yiyan--footer|yiyan--box/);
|
||||
});
|
||||
|
||||
test('遗留的 qv-yiyan.php 渲染请求已移除', () => {
|
||||
const runtime = read('assets/js/runtime/main.js');
|
||||
assert.doesNotMatch(runtime, /qv-yiyan\.php/);
|
||||
assert.doesNotMatch(runtime, /yiyan_nr\(/);
|
||||
assert.match(read('assets/js/yiyan.js'), /action=jio_yiyan/);
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* Render the search and quote widgets through production code and report the
|
||||
* markup, so the contract test can assert the reference single-card shell.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jio\WidgetSystem {
|
||||
final class AssetManager {
|
||||
public static function enqueue_for(WidgetDefinition $definition): void {}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
require __DIR__ . '/bootstrap.php';
|
||||
|
||||
use Jio\WidgetSystem\SchemaWidget;
|
||||
use Jio\WidgetSystem\WidgetDefinition;
|
||||
use Jio\WidgetSystem\WidgetRegistry;
|
||||
|
||||
if (!function_exists('jio_get_search_box')) {
|
||||
function jio_get_search_box(array $args = [], bool $echo = false) {
|
||||
return '<div class="search-input"><form class="search-form"></form></div>';
|
||||
}
|
||||
}
|
||||
if (!function_exists('jio_get_yiyan_markup')) {
|
||||
function jio_get_yiyan_markup(array $args = []): string {
|
||||
return '<div class="' . esc_attr((string) ($args['class'] ?? 'jio-yiyan')) . ' jio-yiyan" data-jio-yiyan><div class="yiyan"></div></div>';
|
||||
}
|
||||
}
|
||||
|
||||
$cases = [];
|
||||
foreach (['search', 'quote'] as $slug) {
|
||||
$definition = WidgetRegistry::get($slug);
|
||||
$widget = new SchemaWidget($definition);
|
||||
$widget->_set(1);
|
||||
$instance = $definition->normalize(['title' => '示例标题', 'placeholder' => '开启精彩搜索']);
|
||||
ob_start();
|
||||
$widget->widget(['before_widget' => '<section class="jio-widget-shell">', 'after_widget' => '</section>'], $instance);
|
||||
$cases[$slug] = (string) ob_get_clean();
|
||||
}
|
||||
|
||||
echo json_encode($cases, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
|
||||
}
|
||||
@@ -20,15 +20,22 @@ test('article and modern widget yiyan use the reference bilingual quote source a
|
||||
assert.match(helper, /\/yiyan\/qv-yiyan\.txt/);
|
||||
assert.match(helper, /wp_ajax_nopriv_jio_yiyan/);
|
||||
assert.match(helper, /'en'\s*=>\s*\$lines\[\$i\],\s*'cn'\s*=>\s*\$lines\[\$i\s*\+\s*1\]/);
|
||||
assert.match(helper, /class="yiyan"><div class="en"><\/div><div class="cn">/);
|
||||
// 参考结构:.yiyan 初始为空,由脚本写入 .cn/.en。
|
||||
assert.match(helper, /class="yiyan"><\/div>/);
|
||||
// 参考主题:句库首行进 .cn(正文尺寸),次行进 .en(0.8em)。
|
||||
assert.match(client, /lineCn\.textContent = quote\.en/);
|
||||
assert.match(client, /lineEn\.textContent = quote\.cn/);
|
||||
assert.match(client, /REFRESH_MS\s*=\s*30000/);
|
||||
assert.match(client, /on\('auto_fun\.jio-yiyan', function \(\) \{\s*init\(document\)/);
|
||||
assert.match(client, /event\.key === 'Enter' \|\| event\.key === ' '/);
|
||||
assert.match(widgetClient, /window\.JioYiyan\.init\(figure\)/);
|
||||
assert.match(renderer, /jio_get_yiyan_markup\(\['class' => 'jio-widget-quote'\]\)/);
|
||||
// 小工具端不再单独初始化:yiyan.js 直接监听 [data-jio-yiyan]。
|
||||
assert.match(widgetClient, /scope\.querySelectorAll\('\.jio-widget-video\[data-video-url\]'\)/);
|
||||
assert.doesNotMatch(widgetClient, /JioYiyan/);
|
||||
assert.match(renderer, /yiyan-box main-bg text-center box-body radius8 main-shadow/);
|
||||
assert.match(renderer, /jio_get_yiyan_markup/);
|
||||
assert.doesNotMatch(rest, /v1\.hitokoto\.cn|function get_quote/);
|
||||
assert.match(schema, /case 'quote':\s*return \[\];/);
|
||||
assert.match(widgetStyles, /\.jio-widget-quote \.yiyan \.en/);
|
||||
assert.doesNotMatch(widgetStyles, /\.jio-widget-quote/);
|
||||
assert.ok(catalog.length > 10, 'the bundled quote file should contain a useful quote set');
|
||||
assert.equal((catalog.length - 1) % 2, 0, 'after the title, quote lines must form English/Chinese pairs');
|
||||
});
|
||||
Reference in new issue
Block a user