fix(widgets): restore article list rendering and reference styles

This commit is contained in:
kate522 committed 2026-10-30 12:47:07 +08:00
1 parent 4ea00f1322
commit fc04bf65e6
18 files changed
+345 -97

No files matched your search

+102 -5
View File
@@ -332,9 +332,25 @@ function addJumpControl(document, pager, { max = 20, value = '4' } = {}) {
return { input, button };
}
function createRuntime({ fetch, pages } = {}) {
function postsMarkup(document, unveiled = false) {
const root = document.createElement('div');
root.className = 'widget-main-post style-list';
const pager = document.createElement('div');
pager.className = 'widget-ajaxpager ' + (unveiled ? 'lazyloaded' : 'lazyload');
pager.setAttribute('data-widget-items', '');
pager.setAttribute('data-widget-lazy', '');
pager.setAttribute('data-widget', 'posts');
pager.setAttribute('data-instance', 'aksrt_widget_posts-2');
pager.setAttribute('data-page', '1');
pager.setAttribute('aria-busy', 'true');
pager.innerHTML = '<div class="post_ajax_loader is-loading"><div class="posts-item placeholder">Loading</div></div>';
root.appendChild(pager);
return { root };
}
function createRuntime({ fetch, pages, posts = false, unveiled = false, restUrl = '/wp-json/aksrt/v1/widgets/', observe = false } = {}) {
const document = new MiniDocument();
const { root: widget, nav, tabOne, tabTwo } = tabMarkup(document);
const { root: widget, nav, tabOne, tabTwo } = posts ? postsMarkup(document, unveiled) : tabMarkup(document);
document.body.appendChild(widget);
const autoFun = [];
function jQuery() {
@@ -344,7 +360,7 @@ function createRuntime({ fetch, pages } = {}) {
};
}
const requests = [];
const config = { restUrl: '/wp-json/aksrt/v1', i18n: { error: 'error', retry: 'retry' } };
const config = { restUrl, i18n: { error: 'error', retry: 'retry' } };
const fetchStub = (url) => {
requests.push(url);
if (fetch) return fetch(url);
@@ -357,11 +373,18 @@ function createRuntime({ fetch, pages } = {}) {
};
return Promise.resolve({ ok: true, json: () => Promise.resolve(response) });
};
let notifyMutation;
const Observer = observe ? class {
constructor(callback) { notifyMutation = callback; }
observe() {}
} : undefined;
const window = {
aksrtWidgets: config,
location: { href: 'https://example.test/' },
matchMedia: () => ({ matches: false }),
jQuery,
};
if (observe) window.MutationObserver = Observer;
vm.runInNewContext(fs.readFileSync(path.join(root, 'assets/widgets/frontend.js'), 'utf8'), {
window,
document,
@@ -373,9 +396,10 @@ function createRuntime({ fetch, pages } = {}) {
Object,
Math,
encodeURIComponent,
MutationObserver: undefined,
URL,
MutationObserver: Observer,
});
return { document, widget, nav, tabOne, tabTwo, requests, autoFun };
return { document, widget, nav, tabOne, tabTwo, requests, autoFun, notifyMutation };
}
const tick = () => new Promise((resolve) => setImmediate(resolve));
@@ -677,3 +701,76 @@ test('jump input clamps pages to max and rejects invalid or current pages withou
assert.equal(runtime.requests.length, 0, 'submitting the already selected page does not request again');
assert.equal(runtime.document.activeElement, input, 'invalid and current page values return focus to the input');
});
test('article widget waits for its own lazy reveal and fetches the first page once', async () => {
const transport = pendingFetch();
const runtime = createRuntime({ posts: true, fetch: transport.fetch });
const pager = runtime.widget.querySelector('[data-widget-items]');
assert.equal(runtime.requests.length, 0, 'offscreen widgets keep their placeholder without fetching');
assert.ok(pager.querySelector('.post_ajax_loader.is-loading'));
pager.querySelector('.placeholder').dispatch('lazybeforeunveil');
assert.equal(runtime.requests.length, 0, 'a descendant image reveal does not load the pager');
pager.dispatch('lazybeforeunveil');
pager.dispatch('lazybeforeunveil');
assert.deepEqual(pageRequests(runtime.requests), [1]);
const url = new URL(runtime.requests[0]);
assert.equal(url.pathname, '/wp-json/aksrt/v1/widgets/posts/items');
assert.equal(url.searchParams.get('instance'), 'aksrt_widget_posts-2');
transport.pending[0].resolve({ html: '<posts class="posts-item list ajax-item" data-post-id="first">First article</posts>', page: 1, paginate_html: '' });
await tick();
assert.ok(pager.querySelector('[data-post-id="first"]'));
assert.equal(pager.dataset.loaded, '1');
assert.equal(pager.getAttribute('aria-busy'), 'false');
assert.equal(pager.querySelector('.post_ajax_loader').classList.contains('is-loading'), false);
pager.dispatch('lazybeforeunveil');
assert.equal(runtime.requests.length, 1, 'a completed first page is never fetched again by lazySizes');
});
test('article widget loads when lazySizes unveiled it before the widget client initialized', async () => {
const runtime = createRuntime({ posts: true, unveiled: true });
assert.deepEqual(pageRequests(runtime.requests), [1]);
await tick();
const pager = runtime.widget.querySelector('[data-widget-items]');
assert.equal(pager.dataset.loaded, '1');
assert.ok(pager.querySelector('[data-post-id]'));
});
test('article widget failure exposes a retry that replaces the initial skeleton', async () => {
const transport = pendingFetch();
const runtime = createRuntime({ posts: true, fetch: transport.fetch });
const pager = runtime.widget.querySelector('[data-widget-items]');
pager.dispatch('lazybeforeunveil');
transport.pending[0].reject(new Error('offline'));
await tick();
assert.equal(pager.getAttribute('aria-busy'), 'false');
assert.equal(pager.querySelector('.post_ajax_loader').classList.contains('is-loading'), false);
pager.querySelector('[data-widget-retry]').click();
assert.deepEqual(pageRequests(runtime.requests), [1, 1]);
transport.pending[1].resolve({ html: '<posts class="posts-item card ajax-item" data-post-id="retried">Retried</posts>', page: 1, paginate_html: '' });
await tick();
assert.ok(pager.querySelector('[data-post-id="retried"]'));
assert.equal(pager.querySelector('[data-widget-retry]'), null);
});
test('article REST addresses preserve the route for plain WordPress permalinks', async () => {
const runtime = createRuntime({ posts: true, unveiled: true, restUrl: 'https://example.test/blog/?rest_route=/aksrt/v1/widgets/' });
const url = new URL(runtime.requests[0]);
assert.equal(url.pathname, '/blog/');
assert.equal(url.searchParams.get('rest_route'), '/aksrt/v1/widgets/posts/items');
assert.equal(url.searchParams.get('instance'), 'aksrt_widget_posts-2');
assert.equal(url.searchParams.get('page'), '1');
await tick();
assert.equal(runtime.widget.querySelector('[data-widget-items]').dataset.loaded, '1');
});
test('a pager inserted as the mutation root still receives its lazy listener', async () => {
const runtime = createRuntime({ observe: true });
const pager = postsMarkup(runtime.document).root.querySelector('[data-widget-items]');
pager.nodeType = 1;
runtime.document.body.appendChild(pager);
runtime.notifyMutation([{ addedNodes: [pager] }]);
pager.dispatch('lazybeforeunveil');
await tick();
assert.deepEqual(pageRequests(runtime.requests), [1]);
assert.equal(pager.dataset.loaded, '1');
});