fix(homepage): unify runtime rendering contract
This commit is contained in:
1 parent
bd6f55c42e
commit
bcebd37807
13 files changed
+951
-926
No files matched your search
@@ -34,8 +34,9 @@
|
||||
var observer = null;
|
||||
var iasEnabled = false;
|
||||
var successfulAutoLoads = 0;
|
||||
var target = container.previousElementSibling;
|
||||
if (target && target.classList && target.classList.contains("content-stream__footer")) {
|
||||
var homepagePanel = container.closest("[data-home-tab-panel]");
|
||||
var target = homepagePanel || container.previousElementSibling;
|
||||
if (!homepagePanel && target && target.classList && target.classList.contains("content-stream__footer")) {
|
||||
target = target.previousElementSibling;
|
||||
}
|
||||
if (isComment) {
|
||||
@@ -161,7 +162,11 @@
|
||||
temp.innerHTML = res.data.html;
|
||||
var newItems = temp.children;
|
||||
while (newItems.length > 0) {
|
||||
target.appendChild(newItems[0]);
|
||||
if (homepagePanel && container.parentNode === target) {
|
||||
target.insertBefore(newItems[0], container);
|
||||
} else {
|
||||
target.appendChild(newItems[0]);
|
||||
}
|
||||
}
|
||||
if (isComment && window.AksrtFrontend) {
|
||||
AksrtFrontend.rehydrate(target, "ajax");
|
||||
|
||||
+93
-26
@@ -278,10 +278,12 @@
|
||||
* Sets data-view, re-binds lazy images, and dispatches events.
|
||||
*/
|
||||
function notifyPostsRendered(panel, viewMode) {
|
||||
var postsContainer = panel.querySelector('.aksrt-homepage__posts, .posts-row');
|
||||
if (postsContainer) {
|
||||
postsContainer.setAttribute('data-view', viewMode || getDefaultView());
|
||||
}
|
||||
var postsContainer = panel.matches('.aksrt-homepage__posts, .posts-row')
|
||||
? panel
|
||||
: panel.querySelector('.aksrt-homepage__posts, .posts-row');
|
||||
if (postsContainer) {
|
||||
postsContainer.setAttribute('data-view', viewMode || getDefaultView());
|
||||
}
|
||||
|
||||
hydrateLazyImages(panel);
|
||||
dispatchRenderedEvent(panel, {
|
||||
@@ -294,6 +296,37 @@
|
||||
* Unified AJAX panel loader
|
||||
* ============================================================ */
|
||||
|
||||
function renderPanelPager(panel, options, hasMore) {
|
||||
var existing = panel.querySelector('.aksrt-homepage__panel-footer');
|
||||
if (existing) existing.remove();
|
||||
if (!hasMore) return;
|
||||
|
||||
var footer = document.createElement('div');
|
||||
footer.className = 'aksrt-homepage__panel-footer';
|
||||
var button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.className = 'aksrt-homepage__more';
|
||||
button.textContent = (window.aksrtData && aksrtData.ajaxTrigger) || '加载更多';
|
||||
button.addEventListener('click', function () {
|
||||
button.disabled = true;
|
||||
button.textContent = (window.aksrtData && aksrtData.ajaxLoading) || '正在加载...';
|
||||
requestHomepagePanel(panel, {
|
||||
termId: options.termId,
|
||||
page: options.page + 1,
|
||||
perPage: options.perPage,
|
||||
sort: options.sort,
|
||||
viewMode: options.viewMode,
|
||||
pageUrl: options.pageUrl,
|
||||
panel: options.panel,
|
||||
source: options.source,
|
||||
tabOrderby: options.tabOrderby,
|
||||
append: true
|
||||
});
|
||||
});
|
||||
footer.appendChild(button);
|
||||
panel.appendChild(footer);
|
||||
}
|
||||
|
||||
function buildErrorState(panel, requestOptions) {
|
||||
var wrapper = document.createElement('div');
|
||||
wrapper.className = 'aksrt-homepage__tab-error';
|
||||
@@ -334,7 +367,8 @@
|
||||
pageUrl: requestOptions.pageUrl || window.location.href,
|
||||
panel: requestOptions.panel || panel.getAttribute('data-home-tab-panel') || 'latest',
|
||||
source: requestOptions.source || getPanelSource(panel),
|
||||
tabOrderby: requestOptions.tabOrderby || getPanelTabOrderby(panel) || ''
|
||||
tabOrderby: requestOptions.tabOrderby || getPanelTabOrderby(panel) || '',
|
||||
append: requestOptions.append === true
|
||||
};
|
||||
|
||||
var restUrl = buildRestUrl(options);
|
||||
@@ -352,14 +386,16 @@
|
||||
url: restUrl
|
||||
});
|
||||
|
||||
// Show loading skeleton
|
||||
panel.innerHTML = '';
|
||||
panel.appendChild(buildSkeleton(options.perPage > 6 ? 4 : 3));
|
||||
// Full refreshes replace the panel; append requests keep existing cards.
|
||||
if (!options.append) {
|
||||
panel.innerHTML = '';
|
||||
panel.appendChild(buildSkeleton(options.perPage > 6 ? 4 : 3));
|
||||
}
|
||||
|
||||
function markLoaded() {
|
||||
panel.dataset.loaded = 'true';
|
||||
panel.dataset.loadedPage = String(options.page);
|
||||
panel.dataset.loadedSort = options.sort;
|
||||
panel.dataset.loadedSort = options.tabOrderby || options.sort;
|
||||
panel.dataset.loadedTermId = String(options.termId);
|
||||
}
|
||||
|
||||
@@ -374,12 +410,21 @@
|
||||
return response.json();
|
||||
})
|
||||
.then(function (data) {
|
||||
panel.innerHTML = '';
|
||||
if (!options.append) panel.innerHTML = '';
|
||||
markLoaded();
|
||||
|
||||
if (data && data.html) {
|
||||
// 2. Inject HTML
|
||||
panel.innerHTML = data.html;
|
||||
// 2. Inject or append article nodes without nesting a posts-row wrapper.
|
||||
if (options.append) {
|
||||
var oldFooter = panel.querySelector('.aksrt-homepage__panel-footer');
|
||||
if (oldFooter) oldFooter.remove();
|
||||
var fragment = document.createElement('div');
|
||||
fragment.innerHTML = data.html;
|
||||
while (fragment.firstChild) panel.appendChild(fragment.firstChild);
|
||||
} else {
|
||||
panel.innerHTML = data.html;
|
||||
}
|
||||
renderPanelPager(panel, options, !!data.has_more);
|
||||
|
||||
// 3. Post-inject event
|
||||
dispatchAfterEvent(panel, {
|
||||
@@ -426,7 +471,9 @@
|
||||
window.setTimeout(doFetch, 3000);
|
||||
return;
|
||||
}
|
||||
panel.innerHTML = '';
|
||||
if (!options.append) panel.innerHTML = '';
|
||||
var failedFooter = panel.querySelector('.aksrt-homepage__panel-footer');
|
||||
if (failedFooter) failedFooter.remove();
|
||||
panel.appendChild(buildErrorState(panel, options));
|
||||
});
|
||||
}
|
||||
@@ -535,9 +582,10 @@
|
||||
});
|
||||
});
|
||||
|
||||
// Mark server-rendered panels as already loaded
|
||||
// Mark server-rendered panels as already loaded. The panel itself owns
|
||||
// the posts-row contract, so checking descendants would miss SSR items.
|
||||
panels.forEach(function (panel) {
|
||||
if (!panel.querySelector('.aksrt-homepage__posts, .posts-row')) return;
|
||||
if (getRenderedPostCount(panel) < 1) return;
|
||||
panel.dataset.loaded = 'true';
|
||||
panel.dataset.loadedPage = '1';
|
||||
panel.dataset.loadedSort = getCurrentSort(stream);
|
||||
@@ -736,16 +784,22 @@
|
||||
* ============================================================ */
|
||||
|
||||
function applyViewMode(buttons, postsContainers, mode) {
|
||||
buttons.forEach(function (btn) {
|
||||
var btnMode = btn.getAttribute('data-view-mode');
|
||||
btn.classList.toggle('is-active', btnMode === mode);
|
||||
});
|
||||
Array.prototype.forEach.call(postsContainers, function (container) {
|
||||
container.setAttribute('data-view', mode);
|
||||
});
|
||||
}
|
||||
buttons.forEach(function (btn) {
|
||||
var btnMode = btn.getAttribute('data-view-mode');
|
||||
var isActive = btnMode === mode;
|
||||
btn.classList.toggle('is-active', isActive);
|
||||
btn.setAttribute('aria-pressed', isActive ? 'true' : 'false');
|
||||
});
|
||||
Array.prototype.forEach.call(postsContainers, function (container) {
|
||||
container.setAttribute('data-view', mode);
|
||||
container.querySelectorAll('.posts-item').forEach(function (item) {
|
||||
item.classList.toggle('card', mode === 'card');
|
||||
item.classList.toggle('list', mode === 'list');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initViewToggle() {
|
||||
function initViewToggle() {
|
||||
var toggles = document.querySelectorAll('[data-aksrt-view-toggle]');
|
||||
|
||||
toggles.forEach(function (toggle) {
|
||||
@@ -754,7 +808,7 @@
|
||||
if (!stream) return;
|
||||
|
||||
function getPostsContainers() {
|
||||
return stream.querySelectorAll('.aksrt-homepage__posts, .posts-row');
|
||||
return stream.querySelectorAll('[data-home-tab-panel]');
|
||||
}
|
||||
|
||||
function getActiveMode() {
|
||||
@@ -767,8 +821,21 @@
|
||||
buttons.forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var mode = btn.getAttribute('data-view-mode') || getDefaultView();
|
||||
applyViewMode(buttons, getPostsContainers(), mode);
|
||||
var activePanel = getActivePanel(stream);
|
||||
if (!activePanel || mode === getActiveMode()) return;
|
||||
|
||||
setViewMode(mode);
|
||||
applyViewMode(buttons, getPostsContainers(), mode);
|
||||
requestHomepagePanel(activePanel, {
|
||||
termId: getPanelTermId(activePanel),
|
||||
page: 1,
|
||||
perPage: getHomepagePerPage(activePanel),
|
||||
sort: getCurrentSort(stream),
|
||||
viewMode: mode,
|
||||
panel: activePanel.getAttribute('data-home-tab-panel') || 'latest',
|
||||
source: 'home',
|
||||
tabOrderby: getPanelTabOrderby(activePanel)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user