fix(theme): align reference layouts and restore passing contracts

Align homepage and category discovery, modern widgets, admin controls, quotes, and comments with the reference theme. Remove superseded paths and add rendering and behavior coverage. Update stale asset and finance contracts; all 760 Node tests and 139 widget assertions pass.
This commit is contained in:
kate522 committed 2026-10-29 19:16:03 +08:00
1 parent b520d29368
commit 8aa116ec43
63 files changed
+1985 -2304

No files matched your search

+154 -7
View File
@@ -23,6 +23,7 @@
evaluateDependencies($root);
updateWidgetTitle($root);
updatePlacementWarning($root);
updateRepeaterControls($root);
}
/* terms 字段:以“已选标签”为唯一真源,同步隐藏输入(选择顺序)与复选框。 */
@@ -63,17 +64,91 @@
$hint.toggleClass('is-warning', (size === 'wide' && isSidebar) || (size === 'sidebar' && !isSidebar && area !== ''));
}
function injectTransferToolbar($anchor, sidebarId) {
if (!$anchor?.length || !sidebarId || $anchor.next('.aksrt-widget-transfer-toolbar').length) return;
const $toolbar = $('<div class="aksrt-widget-transfer-toolbar" role="group"></div>');
[
['export', config.i18n?.export || '导出'],
['import', config.i18n?.import || '导入'],
['template', config.i18n?.template || '应用模板'],
].forEach(([action, label]) => {
$('<button type="button" class="button button-small"></button>')
.text(label)
.attr('data-aksrt-transfer-action', action)
.attr('data-sidebar-id', sidebarId)
.appendTo($toolbar);
});
$anchor.after($toolbar);
}
function scanWidgetAreas() {
$('.widgets-holder-wrap:not(#available-widgets):not(.inactive-sidebar)').each(function () {
const $wrap = $(this);
const $sortables = $wrap.find('.widgets-sortables').first();
const sidebarId = String($sortables.attr('id') || '');
if (!sidebarId) return;
const $description = $sortables.find('.sidebar-description .description').first();
const $anchor = $description.length ? $description : $sortables.find('.description').first();
if ($anchor.length) injectTransferToolbar($anchor, sidebarId);
});
$('.control-section-sidebar').each(function () {
const $section = $(this);
const sectionId = String($section.attr('id') || '');
const prefix = 'sub-accordion-section-sidebar-widgets-';
if (!sectionId.startsWith(prefix)) return;
const sidebarId = sectionId.slice(prefix.length);
const $description = $section.find('.section-meta .description').first();
const $anchor = $description.length ? $description : $section.find('.accordion-section-title, .customize-section-title').first();
if ($anchor.length) injectTransferToolbar($anchor, sidebarId);
});
$('.customize-control-widget_form').each(function () {
const $control = $(this);
const $nav = $control.find('.widget-reorder-nav').first();
if (!$nav.length || $nav.find('.aksrt-widget-customizer-remove').length) return;
$('<button type="button" class="button-link-delete aksrt-widget-customizer-remove" aria-label="移除此小工具">移除</button>').appendTo($nav);
});
}
function openTransferModal(action, sidebarId) {
const $modal = $('#aksrt-widget-transfer-modal');
if (!$modal.length) return;
const sidebars = config.sidebars || {};
const areaName = sidebars[sidebarId] || sidebarId;
$modal.find('.aksrt-widget-transfer-modal__area').text(areaName);
$modal.find('input[name="sidebar"], input[name="target_sidebar"]').val(sidebarId);
$modal.find('[data-transfer-tab]').removeClass('is-active');
$modal.find(`[data-transfer-tab="${action}"]`).addClass('is-active');
$modal.find('[data-transfer-panel]').prop('hidden', true);
$modal.find(`[data-transfer-panel="${action}"]`).prop('hidden', false);
$modal.prop('hidden', false).addClass('is-open').attr('aria-hidden', 'false');
$modal.find('[data-transfer-panel="' + action + '"] button, [data-transfer-panel="' + action + '"] input, [data-transfer-panel="' + action + '"] select').filter(':visible').first().trigger('focus');
}
function closeTransferModal() {
$('#aksrt-widget-transfer-modal').removeClass('is-open').attr('aria-hidden', 'true').prop('hidden', true);
}
function loadForm(container) {
const $container = $(container);
if ($container.data('loading') || $container.data('loaded')) return;
const $widget = $container.closest('.widget, .customize-control-widget_form');
const inputName = String($widget.find('input[name^="widget-"]').first().attr('name') || '');
const number = core.resolveWidgetNumber(inputName, $widget.attr('id'), $container.data('widget-number'));
// New-widget templates use __i__ until WordPress assigns a real instance number.
if (!number) return;
$container.data('loading', true).find('.aksrt-widget-form-lazy__status').text(config.i18n?.loading || 'Loading…');
$.post(config.ajaxUrl, {
action: config.action,
nonce: config.nonce,
id_base: $container.data('id-base'),
widget_number: $container.data('widget-number'),
widget_number: number,
}).done((response) => {
if (!response?.success || !response.data?.html) throw new Error('Invalid response');
if (!response?.success || !response.data?.html) {
$container.data('loading', false).find('.aksrt-widget-form-lazy__status').text(response?.data?.message || config.i18n?.error || 'Failed to load.');
return;
}
const $form = $(response.data.html);
$container.replaceWith($form);
initForm($form);
@@ -94,6 +169,31 @@
if (!rowIndexes.length) return;
this.name = core.replaceRepeaterIndexes(this.name, rowIndexes);
});
updateRepeaterTitles($form);
}
function updateRepeaterTitles($form) {
$form.find('.aksrt-widget-repeater__rows').each(function () {
$(this).children('.aksrt-widget-repeater__row').each(function (index) {
const $row = $(this);
const $title = $row.find('.aksrt-widget-repeater__title').first();
const prefix = String($title.data('title-prefix') || '项目');
const $firstControl = $row.children('.aksrt-widget-repeater__fields').find('input:not([type="hidden"]), select, textarea').first();
const value = String($firstControl.val() || '').trim();
$title.text(prefix + (index + 1) + (value ? ':' + value : ''));
});
});
}
function updateRepeaterControls($root) {
$root.filter('.aksrt-widget-repeater').add($root.find('.aksrt-widget-repeater')).each(function () {
const $repeater = $(this);
const count = $repeater.children('.aksrt-widget-repeater__rows').children('.aksrt-widget-repeater__row').length;
const min = Number($repeater.data('min-items') || 0);
const max = Number($repeater.data('max-items') || 50);
$repeater.children('.aksrt-widget-repeater__rows').children('.aksrt-widget-repeater__row').children('.aksrt-widget-repeater__bar').children('.aksrt-widget-repeater__remove').prop('disabled', count <= min);
$repeater.children('.aksrt-widget-repeater__add').prop('disabled', count >= max);
});
}
function fieldValue($form, id) {
@@ -116,12 +216,29 @@
}
$(document)
.on('click', '[data-aksrt-transfer-action]', function () {
openTransferModal(String($(this).data('aksrt-transfer-action')), String($(this).data('sidebar-id')));
})
.on('click', '[data-aksrt-transfer-close]', closeTransferModal)
.on('click', '[data-transfer-tab]', function () {
const $modal = $(this).closest('.aksrt-widget-transfer-modal');
const panel = String($(this).data('transfer-tab'));
$modal.find('[data-transfer-tab]').removeClass('is-active');
$(this).addClass('is-active');
$modal.find('[data-transfer-panel]').prop('hidden', true);
$modal.find(`[data-transfer-panel="${panel}"]`).prop('hidden', false);
})
.on('click', '.aksrt-widget-customizer-remove', function (event) {
event.preventDefault();
$(this).closest('.customize-control-widget_form').find('.widget-control-remove').first().trigger('click');
})
.on('click', '.aksrt-widget-form-lazy__load', function () { loadForm($(this).closest('.aksrt-widget-form-lazy')); })
.on('click', '.widget.open .aksrt-widget-form-lazy', function () { loadForm(this); })
.on('click', '.widget.open .aksrt-widget-form-lazy, .customize-control-widget_form .aksrt-widget-form-lazy', function () { loadForm(this); })
.on('change input', '.aksrt-widget-form input, .aksrt-widget-form select, .aksrt-widget-form textarea', function () {
const $form = $(this).closest('.aksrt-widget-form');
evaluateDependencies($form);
updateWidgetTitle($form);
updateRepeaterTitles($form);
})
.on('click', '.aksrt-widget-repeater__add', function () {
const $repeater = $(this).closest('.aksrt-widget-repeater');
@@ -134,11 +251,17 @@
const $row = $(html).appendTo($rows);
initForm($row);
renumberRepeaters.call($rows[0]);
updateRepeaterControls($repeater);
})
.on('click', '.aksrt-widget-repeater__remove', function () {
const $rows = $(this).closest('.aksrt-widget-repeater__rows');
.on('click', '.aksrt-widget-repeater__remove', function (event) {
event.preventDefault();
event.stopPropagation();
const $repeater = $(this).closest('.aksrt-widget-repeater');
const $rows = $repeater.children('.aksrt-widget-repeater__rows');
if ($rows.children('.aksrt-widget-repeater__row').length <= Number($repeater.data('min-items') || 0)) return;
$(this).closest('.aksrt-widget-repeater__row').remove();
renumberRepeaters.call($rows[0]);
updateRepeaterControls($repeater);
})
.on('click', '.aksrt-widget-terms__remove', function () {
$(this).closest('.aksrt-widget-terms__chip').remove();
@@ -150,6 +273,7 @@
const id = String(this.value);
const name = (option.querySelector('[data-term-name]') || option).getAttribute('data-term-name');
if (this.checked) addTermChip(wrap, id, name || id);
else $(wrap).find('.aksrt-widget-terms__chip').filter((_index, chip) => String($(chip).data('term-id')) === id).remove();
syncTerms(wrap);
})
.on('input', '.aksrt-widget-terms__search', function () {
@@ -186,17 +310,40 @@
nonce: config.transferNonce,
template: $form.find('[name="template"]').val(),
}).done((response) => {
if (!response?.success) throw new Error('Invalid response');
if (!response?.success || !response.data) {
$output.empty().append($('<p class="notice notice-error"></p>').text(response?.data?.message || config.i18n?.error || '预览加载失败,请重试。'));
return;
}
$output.html(response.data.html || '<p>模板为空。</p>');
}).fail(() => $output.html('<p class="notice notice-error">预览加载失败。</p>'));
}).fail((xhr) => {
const message = xhr?.responseJSON?.data?.message || config.i18n?.error || '预览加载失败,请重试。';
$output.empty().append($('<p class="notice notice-error"></p>').text(message));
});
});
$(document).on('widget-added widget-updated', function (_event, widget) {
$(widget).find('.aksrt-widget-form-lazy').each(function () { loadForm(this); });
updatePlacementWarning(widget);
scanWidgetAreas();
});
if (window.wp?.customize?.bind) {
window.wp.customize.bind('ready', function () {
$('#customize-theme-controls').on('expanded', function (_event, section) {
if (!section || !String(section.id || section).includes('sidebar-widgets')) return;
window.setTimeout(function () {
scanWidgetAreas();
$('.customize-control-widget_form .aksrt-widget-form-lazy').each(function () { loadForm(this); });
}, 100);
});
});
}
$(function () {
scanWidgetAreas();
$(document).on('keydown', function (event) {
if (event.key === 'Escape') closeTransferModal();
});
$('.aksrt-widget-form').each(function () { initForm(this); });
$('.widget.open .aksrt-widget-form-lazy').each(function () { loadForm(this); });
});