Files
wordpress-theme-aksrt/assets/js/admin-nav-menu-senior.js
T
kate522andClaude Opus 5 e6d9ff49a2 fix(navigation): align mega-menu rendering and menu-item backend with the reference
Renderer:
- Graphic-card images carry fit-cover so they crop into the fixed card box
  instead of stretching it and pushing the title out of alignment.
- Mega-menu link icons use fa-fw (fixed glyph column) instead of the
  undefined menu-item-icon class, so link titles line up.

Backend:
- Restore show_policy (login / vip / vip_2 / auth) on menu items; the field
  was missing entirely, so items could not be gated by identity.
- Default submenu_type to graphic_card, badge_class to jb-red, arrangement
  to swiper, size to md.
- Clamp img_scale to 20-300 to match the reference's spinner bounds.
- Drop the now-meaningless "none" submenu_type option: the senior-submenu
  switch is itself the on/off control.
- Admin JS gains the align control (left/center/space-around).

Cleanup:
- Remove the unused header_actions nav menu location.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-05 10:51:36 +08:00

279 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Nav menu senior submenu visual editors (graphic cards / multi-column).
* Enhances WP Appearance → Menus fields for jio_menu_options JSON.
*
* @package Jio
*/
(function ($) {
'use strict';
function parseJSON(raw, fallback) {
try {
var data = JSON.parse(raw || '');
return data && typeof data === 'object' ? data : fallback;
} catch (e) {
return fallback;
}
}
function graphicTemplate() {
return {
arrangement: 'swiper',
size: 'md',
img_scale: 100,
align: '',
items: [{ img: '', title: '', badge: '', badge_class: 'jb-red', link: { url: '', text: '', target: '' } }],
};
}
function multiTemplate() {
return {
columns: [
{
title: '',
icon: '',
img_icon: '',
link: { url: '', text: '', target: '' },
items: [{ title: '', icon: '', img_icon: '', link: { url: '', text: '', target: '' } }],
},
],
};
}
function field(name, label, value, type, withMedia) {
type = type || 'text';
var mediaBtn = withMedia
? ' <button type="button" class="button jio-sme-pick-img" data-for="' + name + '">选择图片</button>'
: '';
return (
'<label class="jio-sme-field"><span>' +
label +
mediaBtn +
'</span><input type="' +
type +
'" data-name="' +
name +
'" value="' +
String(value || '').replace(/"/g, '&quot;') +
'" class="widefat"></label>'
);
}
function renderGraphicUI($wrap, data) {
var html = '<div class="jio-sme-toolbar">';
html += '<button type="button" class="button jio-sme-add-card">添加卡片</button>';
html += ' <label style="margin-left:8px;">排列 ';
html += '<select data-name="arrangement">';
html += '<option value=""' + (!data.arrangement ? ' selected' : '') + '>自动换行</option>';
html += '<option value="swiper"' + (data.arrangement === 'swiper' ? ' selected' : '') + '>单行滚动</option>';
html += '</select></label>';
html += '</div><div class="jio-sme-cards">';
(data.items || []).forEach(function (item, i) {
html += '<div class="jio-sme-card" data-index="' + i + '">';
html += '<div class="jio-sme-card-head"><strong>卡片 #' + (i + 1) + '</strong>';
html += ' <button type="button" class="button-link-delete jio-sme-del-card">删除</button></div>';
html += field('img', '图片 URL', item.img || '', 'text', true);
html += field('title', '标题', item.title || '');
html += field('badge', '徽章', item.badge || '');
html += field('badge_class', '徽章 class', item.badge_class || '');
html += field('link.url', '链接', (item.link && item.link.url) || '');
html += '</div>';
});
html += '</div>';
html += field('size', '尺寸 sm/md/lg/xs', data.size || 'md');
html += field('img_scale', '图片比例%(20-300)', data.img_scale || 100, 'number');
html += ' <label>对齐 <select data-name="align">';
html += '<option value=""' + (!data.align ? ' selected' : '') + '>靠左</option>';
html += '<option value="jc"' + (data.align === 'jc' ? ' selected' : '') + '>居中</option>';
html += '<option value="jsa"' + (data.align === 'jsa' ? ' selected' : '') + '>平均分布</option>';
html += '</select></label>';
$wrap.html(html);
}
function renderMultiUI($wrap, data) {
var html = '<div class="jio-sme-toolbar">';
html += '<button type="button" class="button jio-sme-add-col">添加栏目</button>';
html += '</div><div class="jio-sme-cols">';
(data.columns || []).forEach(function (col, i) {
html += '<div class="jio-sme-col" data-index="' + i + '">';
html += '<div class="jio-sme-card-head"><strong>栏目 #' + (i + 1) + '</strong>';
html += ' <button type="button" class="button-link-delete jio-sme-del-col">删除栏目</button></div>';
html += field('title', '栏目标题', col.title || '');
html += field('icon', '图标 class', col.icon || '');
html += field('link.url', '栏目链接', (col.link && col.link.url) || '');
html += '<div class="jio-sme-items">';
(col.items || []).forEach(function (item, j) {
html += '<div class="jio-sme-item" data-j="' + j + '">';
html += field('items.' + j + '.title', '链接标题', item.title || '');
html += field('items.' + j + '.link.url', '链接 URL', (item.link && item.link.url) || '');
html += field('items.' + j + '.icon', '图标', item.icon || '');
html += '</div>';
});
html += '<button type="button" class="button jio-sme-add-item">添加链接</button>';
html += '</div></div>';
});
html += '</div>';
$wrap.html(html);
}
function readGraphic($wrap) {
var data = graphicTemplate();
data.arrangement = $wrap.find('[data-name="arrangement"]').val() || '';
data.size = $wrap.find('[data-name="size"]').val() || 'md';
data.align = $wrap.find('[data-name="align"]').val() || '';
data.img_scale = parseInt($wrap.find('[data-name="img_scale"]').val(), 10) || 100;
data.items = [];
$wrap.find('.jio-sme-card').each(function () {
var $c = $(this);
data.items.push({
img: $c.find('[data-name="img"]').val() || '',
title: $c.find('[data-name="title"]').val() || '',
badge: $c.find('[data-name="badge"]').val() || '',
badge_class: $c.find('[data-name="badge_class"]').val() || '',
link: { url: $c.find('[data-name="link.url"]').val() || '', text: '', target: '' },
});
});
return data;
}
function readMulti($wrap) {
var data = { columns: [] };
$wrap.find('.jio-sme-col').each(function () {
var $col = $(this);
var col = {
title: $col.find('[data-name="title"]').first().val() || '',
icon: $col.find('[data-name="icon"]').first().val() || '',
img_icon: '',
link: { url: $col.find('[data-name="link.url"]').first().val() || '', text: '', target: '' },
items: [],
};
$col.find('.jio-sme-item').each(function () {
var $it = $(this);
col.items.push({
title: $it.find('input[data-name$=".title"]').val() || '',
icon: $it.find('input[data-name$=".icon"]').val() || '',
img_icon: '',
link: { url: $it.find('input[data-name$=".link.url"]').val() || '', text: '', target: '' },
});
});
data.columns.push(col);
});
return data;
}
function enhanceItem($item) {
if ($item.data('jioSme')) return;
$item.data('jioSme', 1);
var $graphicTa = $item.find('textarea[name*="[graphic_card_opts_json]"]');
var $multiTa = $item.find('textarea[name*="[multi_column_links_opts_json]"]');
var $type = $item.find('select[name*="[submenu_type]"]');
if (!$graphicTa.length && !$multiTa.length) return;
var $ui = $('<div class="jio-sme-ui" style="margin:8px 0;padding:10px;border:1px solid #dcdcde;background:#fff;border-radius:4px;"></div>');
$graphicTa.closest('p').before($ui);
function sync() {
var type = $type.val();
if (type === 'graphic_card') {
$graphicTa.closest('p').hide();
$multiTa.closest('p').hide();
var g = parseJSON($graphicTa.val(), graphicTemplate());
renderGraphicUI($ui, g);
$ui.show();
} else if (type === 'multi_column_links') {
$graphicTa.closest('p').hide();
$multiTa.closest('p').hide();
var m = parseJSON($multiTa.val(), multiTemplate());
renderMultiUI($ui, m);
$ui.show();
} else {
$ui.hide().empty();
$graphicTa.closest('p').show();
$multiTa.closest('p').show();
}
}
$type.on('change', sync);
$ui.on('click', '.jio-sme-add-card', function (e) {
e.preventDefault();
var g = readGraphic($ui);
g.items.push({ img: '', title: '', badge: '', badge_class: 'jb-red', link: { url: '', text: '', target: '' } });
renderGraphicUI($ui, g);
});
$ui.on('click', '.jio-sme-del-card', function (e) {
e.preventDefault();
$(this).closest('.jio-sme-card').remove();
});
$ui.on('click', '.jio-sme-add-col', function (e) {
e.preventDefault();
var m = readMulti($ui);
m.columns.push({
title: '',
icon: '',
img_icon: '',
link: { url: '', text: '', target: '' },
items: [{ title: '', icon: '', img_icon: '', link: { url: '', text: '', target: '' } }],
});
renderMultiUI($ui, m);
});
$ui.on('click', '.jio-sme-del-col', function (e) {
e.preventDefault();
$(this).closest('.jio-sme-col').remove();
});
$ui.on('click', '.jio-sme-add-item', function (e) {
e.preventDefault();
var $col = $(this).closest('.jio-sme-col');
var m = readMulti($ui);
var idx = $col.index();
if (m.columns[idx]) {
m.columns[idx].items.push({ title: '', icon: '', img_icon: '', link: { url: '', text: '', target: '' } });
}
renderMultiUI($ui, m);
});
// Before save, write UI → textarea
$('#update-nav-menu').on('submit.jioSme', function () {
var type = $type.val();
if (type === 'graphic_card') {
$graphicTa.val(JSON.stringify(readGraphic($ui), null, 2));
} else if (type === 'multi_column_links') {
$multiTa.val(JSON.stringify(readMulti($ui), null, 2));
}
});
// Hide raw JSON by default; toggle available via double-click title
$graphicTa.closest('p').find('label').attr('title', '双击显示原始 JSON');
sync();
}
function boot() {
$('#menu-to-edit .menu-item').each(function () {
enhanceItem($(this));
});
}
$(document).on('click', '.jio-sme-pick-img', function (e) {
e.preventDefault();
var $btn = $(this);
var name = $btn.data('for');
var $input = $btn.closest('.jio-sme-field').find('input[data-name="' + name + '"]');
if (typeof wp === 'undefined' || !wp.media) {
window.alert('媒体库不可用');
return;
}
var frame = wp.media({ title: '选择图片', button: { text: '使用此图' }, multiple: false, library: { type: 'image' } });
frame.on('select', function () {
var att = frame.state().get('selection').first().toJSON();
if (att && att.url) $input.val(att.url).trigger('change');
});
frame.open();
});
$(boot);
$(document).on('menu-item-added', function () {
setTimeout(boot, 50);
});
})(jQuery);