feat(widgets): replicate 12 reference widgets for full Zibll parity
- rewrite schemas for posts, tab_posts, oneline_posts, hot_posts, term_cards, term_aggregation, media_cards, combo_info, partners, recent_comments, posts_toc and slider_media_combo to mirror the modern reference modules field by field (options, defaults, dependencies, min/max/step, subheadings) - port reference renderers: hot ranking with TOP badges, category aggregation card, graphic cover cards, partners CSS marquee, combo info cards with auto band palette, recent comment list - rename 分类与标签聚合卡片 to 分类聚合卡片 and restrict it to categories (no tags/topics branch in this project) - drop topics filter fields and the topics query branch; align orderby value domain with supported post meta - add searchable sortable terms admin field type and spinner unit suffix rendering - unify widget pagination and lazy loading on the REST client with the runtime-owned ias reveal trigger; remove the legacy post_ajax_trigger dual path - align section-navs TOC with the reference contract (wznav ids, 3-heading minimum, zib-widget box)
This commit is contained in:
+84
-74
@@ -72,41 +72,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function initToc(toc) {
|
||||
if (!once(toc, 'Toc')) return;
|
||||
var scope = document.querySelector('.article-content, .wp-posts-content, article .entry-content');
|
||||
var headings = scope ? Array.prototype.slice.call(scope.querySelectorAll('h2,h3,h4')) : [];
|
||||
var minimum = Number(toc.dataset.minHeadings || 3);
|
||||
var list = toc.querySelector('.aksrt-widget-toc__list');
|
||||
if (headings.length < minimum || !list) {
|
||||
toc.hidden = true;
|
||||
return;
|
||||
}
|
||||
headings.forEach(function (heading, index) {
|
||||
if (!heading.id) heading.id = 'aksrt-heading-' + (index + 1);
|
||||
var item = document.createElement('li');
|
||||
item.className = 'level-' + heading.tagName.toLowerCase();
|
||||
var link = document.createElement('a');
|
||||
link.href = '#' + heading.id;
|
||||
link.textContent = heading.textContent.trim();
|
||||
link.addEventListener('click', function (event) {
|
||||
event.preventDefault();
|
||||
window.scrollTo({ top: heading.getBoundingClientRect().top + window.scrollY - Number(toc.dataset.scrollOffset || 70), behavior: reducedMotion ? 'auto' : 'smooth' });
|
||||
history.replaceState(null, '', link.href);
|
||||
});
|
||||
item.appendChild(link);
|
||||
list.appendChild(item);
|
||||
});
|
||||
var empty = toc.querySelector('.aksrt-widget-toc__empty');
|
||||
if (empty) empty.remove();
|
||||
var toggle = toc.querySelector('.aksrt-widget-toc__toggle');
|
||||
if (toggle) toggle.addEventListener('click', function () {
|
||||
var expanded = toggle.getAttribute('aria-expanded') === 'true';
|
||||
toggle.setAttribute('aria-expanded', expanded ? 'false' : 'true');
|
||||
toc.classList.toggle('is-collapsed', expanded);
|
||||
});
|
||||
}
|
||||
|
||||
function updateQuote(figure) {
|
||||
if (figure.dataset.source !== 'api' || !config.quoteUrl) return Promise.resolve();
|
||||
var button = figure.querySelector('button');
|
||||
@@ -141,26 +106,39 @@
|
||||
return url;
|
||||
}
|
||||
|
||||
function loaderOf(container) {
|
||||
return container.querySelector('.post_ajax_loader');
|
||||
}
|
||||
|
||||
function setBusy(container, busy) {
|
||||
if (busy) {
|
||||
container.dataset.loading = '1';
|
||||
container.setAttribute('aria-busy', 'true');
|
||||
var loader = loaderOf(container);
|
||||
if (loader) loader.style.display = '';
|
||||
} else {
|
||||
delete container.dataset.loading;
|
||||
container.setAttribute('aria-busy', 'false');
|
||||
var loader = loaderOf(container);
|
||||
if (loader) loader.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function loadItems(container, page, append) {
|
||||
var owner = container.closest('[data-widget]') || container;
|
||||
var widget = owner.dataset.widget || container.dataset.widget;
|
||||
var instance = owner.dataset.instance || container.dataset.instance;
|
||||
var segment = container.dataset.segment || owner.dataset.segment || '';
|
||||
if (!widget || !instance || !config.restUrl || container.dataset.loading === '1') return;
|
||||
container.dataset.loading = '1';
|
||||
container.classList.add('is-loading');
|
||||
container.setAttribute('aria-busy', 'true');
|
||||
setBusy(container, true);
|
||||
fetch(itemsUrl(widget, instance, page, segment), { credentials: 'same-origin', headers: { Accept: 'application/json' } })
|
||||
.then(function (response) { if (!response.ok) throw new Error('items'); return response.json(); })
|
||||
.then(function (data) {
|
||||
var oldPagination = container.querySelector('.aksrt-widget-pagination, .aksrt-widget-load-more');
|
||||
if (oldPagination) oldPagination.remove();
|
||||
var fragment = document.createElement('div');
|
||||
fragment.innerHTML = String(data.html || '');
|
||||
Array.prototype.slice.call(container.querySelectorAll(':scope > .ajax-pag')).forEach(function (node) { node.remove(); });
|
||||
if (append) {
|
||||
var target = container.querySelector('.aksrt-widget-posts, .posts-row, .swiper-wrapper') || container;
|
||||
var source = fragment.querySelector('.aksrt-widget-posts, .posts-row, .swiper-wrapper');
|
||||
Array.prototype.slice.call((source || fragment).children).forEach(function (node) { target.appendChild(node); });
|
||||
Array.prototype.slice.call(fragment.children).forEach(function (node) { container.appendChild(node); });
|
||||
} else {
|
||||
container.innerHTML = fragment.innerHTML;
|
||||
}
|
||||
@@ -169,11 +147,7 @@
|
||||
scan(container);
|
||||
})
|
||||
.catch(function () { container.innerHTML = errorMarkup(); })
|
||||
.finally(function () {
|
||||
delete container.dataset.loading;
|
||||
container.classList.remove('is-loading');
|
||||
container.setAttribute('aria-busy', 'false');
|
||||
});
|
||||
.finally(function () { setBusy(container, false); });
|
||||
}
|
||||
|
||||
function initItems(container) {
|
||||
@@ -181,35 +155,49 @@
|
||||
if (container.classList.contains('is-loading')) loadItems(container, 1, false);
|
||||
container.addEventListener('click', function (event) {
|
||||
var retry = event.target.closest('[data-widget-retry]');
|
||||
var more = event.target.closest('.aksrt-widget-load-more');
|
||||
var pageButton = event.target.closest('[data-widget-page]');
|
||||
if (retry) loadItems(container, Number(container.dataset.page || 1), false);
|
||||
if (more) loadItems(container, Number(more.dataset.nextPage || 2), true);
|
||||
if (pageButton) loadItems(container, Number(pageButton.dataset.widgetPage || 1), false);
|
||||
var trigger = event.target.closest('[data-next-page]');
|
||||
var pageLink = event.target.closest('.page-numbers[data-widget-page]');
|
||||
if (retry) {
|
||||
loadItems(container, Number(container.dataset.page || 1), false);
|
||||
return;
|
||||
}
|
||||
if (trigger) {
|
||||
// data-widget-ias marks the hidden reveal trigger the runtime clicks
|
||||
// when the lazy container scrolls into view; it reloads page one.
|
||||
event.preventDefault();
|
||||
if (trigger.dataset.widgetIas === '1') loadItems(container, 1, false);
|
||||
else loadItems(container, Number(trigger.dataset.nextPage || 2), true);
|
||||
return;
|
||||
}
|
||||
if (pageLink) {
|
||||
event.preventDefault();
|
||||
loadItems(container, Number(pageLink.dataset.widgetPage || 1), false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initTabs(tabs) {
|
||||
if (!once(tabs, 'Tabs')) return;
|
||||
tabs.addEventListener('keydown', function (event) { moveTabFocus(event, tabs); });
|
||||
tabs.addEventListener('keydown', function (event) { moveTabFocus(event, tabs); });
|
||||
tabs.addEventListener('click', function (event) {
|
||||
var button = event.target.closest('[role="tab"][data-segment]');
|
||||
if (!button) return;
|
||||
event.preventDefault();
|
||||
tabs.querySelectorAll('[role="tab"]').forEach(function (tab) {
|
||||
tab.setAttribute('aria-selected', tab === button ? 'true' : 'false');
|
||||
tab.setAttribute('tabindex', tab === button ? '0' : '-1');
|
||||
if (tab.parentElement) tab.parentElement.classList.toggle('active', tab === button);
|
||||
});
|
||||
tabs.querySelectorAll('.tab-content > .tab-pane').forEach(function (item) {
|
||||
var active = item.id === button.getAttribute('aria-controls');
|
||||
item.classList.toggle('active', active); item.classList.toggle('in', active);
|
||||
});
|
||||
var panel = tabs.querySelector('[data-widget-items][data-segment="' + button.dataset.segment + '"]');
|
||||
if (!panel) panel = tabs.querySelector('[data-widget-items]');
|
||||
event.preventDefault();
|
||||
tabs.querySelectorAll('[role="tab"]').forEach(function (tab) {
|
||||
tab.setAttribute('aria-selected', tab === button ? 'true' : 'false');
|
||||
tab.setAttribute('tabindex', tab === button ? '0' : '-1');
|
||||
if (tab.parentElement) tab.parentElement.classList.toggle('active', tab === button);
|
||||
});
|
||||
tabs.querySelectorAll('.tab-content > .tab-pane').forEach(function (item) {
|
||||
var active = item.id === button.getAttribute('aria-controls');
|
||||
item.classList.toggle('active', active); item.classList.toggle('in', active);
|
||||
});
|
||||
var panel = tabs.querySelector('[data-widget-items][data-segment="' + button.dataset.segment + '"]');
|
||||
if (!panel) panel = tabs.querySelector('[data-widget-items]');
|
||||
if (!panel) return;
|
||||
panel.dataset.segment = button.dataset.segment;
|
||||
panel.setAttribute('aria-labelledby', button.id);
|
||||
loadItems(panel, 1, false);
|
||||
panel.setAttribute('aria-labelledby', button.id);
|
||||
loadItems(panel, 1, false);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -232,15 +220,15 @@
|
||||
|
||||
function initFeatures(features) {
|
||||
if (!once(features, 'Features')) return;
|
||||
features.addEventListener('keydown', function (event) { moveTabFocus(event, features); });
|
||||
features.addEventListener('keydown', function (event) { moveTabFocus(event, features); });
|
||||
features.addEventListener('click', function (event) {
|
||||
var button = event.target.closest('[data-feature-index]');
|
||||
if (!button) return;
|
||||
var index = button.dataset.featureIndex;
|
||||
features.querySelectorAll('[data-feature-index]').forEach(function (tab) {
|
||||
tab.setAttribute('aria-selected', tab === button ? 'true' : 'false');
|
||||
tab.setAttribute('tabindex', tab === button ? '0' : '-1');
|
||||
});
|
||||
features.querySelectorAll('[data-feature-index]').forEach(function (tab) {
|
||||
tab.setAttribute('aria-selected', tab === button ? 'true' : 'false');
|
||||
tab.setAttribute('tabindex', tab === button ? '0' : '-1');
|
||||
});
|
||||
features.querySelectorAll('[data-feature-panel]').forEach(function (panel) { panel.hidden = panel.dataset.featurePanel !== index; });
|
||||
});
|
||||
}
|
||||
@@ -262,16 +250,38 @@
|
||||
requestAnimationFrame(frame);
|
||||
}
|
||||
|
||||
/* 幻灯片加图文视频卡片:以左侧幻灯片实际高度重算右侧卡片比例。
|
||||
* 合作伙伴滚动由运行时 main.js 初始化(.zib-partners-scroll 唯一所有者)。 */
|
||||
function measureSliderGraphic(widget) {
|
||||
if (once(widget, 'Combo')) return;
|
||||
var slider = widget.querySelector('.slider-col .zib-slider') || widget.querySelector('.slider-col');
|
||||
var covers = widget.querySelector('.cover-col');
|
||||
if (!slider || !covers) return;
|
||||
var row = Number(widget.dataset.row || 2);
|
||||
var col = Number(widget.dataset.col || 2);
|
||||
var gap = 10;
|
||||
function update() {
|
||||
var height = slider.offsetHeight;
|
||||
var width = covers.offsetWidth;
|
||||
if (!height || !width) return;
|
||||
var ratio = (((height - (col - 1) * gap) / col) / ((width - (row - 1) * gap) / row)) * 100;
|
||||
covers.style.setProperty('--cover-ratio', ratio.toFixed(2) + '%');
|
||||
}
|
||||
update();
|
||||
window.addEventListener('resize', update, { passive: true });
|
||||
if ('ResizeObserver' in window) new ResizeObserver(update).observe(slider);
|
||||
}
|
||||
|
||||
function scan(root) {
|
||||
var scope = root || document;
|
||||
scope.querySelectorAll('.aksrt-widget-video[data-video-url]').forEach(initVideo);
|
||||
scope.querySelectorAll('.aksrt-widget-toc').forEach(initToc);
|
||||
scope.querySelectorAll('.aksrt-widget-quote').forEach(initQuote);
|
||||
scope.querySelectorAll('[data-widget-items]').forEach(initItems);
|
||||
scope.querySelectorAll('.aksrt-widget-tabs, .widget-tab-post').forEach(initTabs);
|
||||
scope.querySelectorAll('.aksrt-faq').forEach(initFaq);
|
||||
scope.querySelectorAll('.aksrt-feature-intro').forEach(initFeatures);
|
||||
scope.querySelectorAll('[data-count-up]').forEach(initCount);
|
||||
scope.querySelectorAll('.widget-slider-graphic').forEach(measureSliderGraphic);
|
||||
if (typeof window.VanillaTilt !== 'undefined') scope.querySelectorAll('[data-aksrt-tilt]').forEach(function (el) { if (once(el, 'Tilt')) window.VanillaTilt.init(el); });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user