wikipedia-pages-js — Wikipedia Pages (opaque continue-token pagination)

A demo of vanilla-grid against the public MediaWiki Action API that paginates via an opaque continue object whose fields must be echoed back on the next request. Implements a custom DataManager that stores the continue token in its own state and ignores the grid's (skip, pageSize) hint entirely.

What it shows

Resizing the grid

The grid sits in a src/vanilla-resize-box/ (aria-label="Resizable Wikipedia pages grid"). Drag the corner handle to resize it — resizing is pointer-driven, with no keyboard path.

The handle carries role="separator" and takes its accessible name from the host's aria-label — here "Resizable Wikipedia pages grid — resize handle" — but is not focusable, so it adds no tab stop to the page. This app's markup needs nothing beyond the aria-label it already carries.

Endpoint

GET https://en.wikipedia.org/w/api.php
    ?action=query
    &format=json
    &formatversion=2
    &origin=*
    &generator=categorymembers
    &gcmtitle=Category:Web_frameworks
    &gcmlimit=20
    &gcmtype=page
    &gcmsort=sortkey
    &gcmdir=ascending
    &prop=info|pageimages|extracts
    &inprop=url
    &piprop=thumbnail
    &pithumbsize=80
    &exintro=1
    &explaintext=1
    &exlimit=20
    &exchars=300

Note: the intro extract ships with the list query, which is safe only because gcmlimit === exlimit (both PAGE_SIZE, 20). The MediaWiki TextExtracts module caps exlimit; when a page holds more rows than extracts, the API returns continue.excontinue instead of gcmcontinue, which would stall the generator. Keeping the two equal gives every row its extract (the grid's Preview column and the detail panel) with no per-row request.

Subsequent requests append the entire continue object verbatim:

&continue=gcmcontinue||&gcmcontinue=page%7C123%7C456

Sorting

The MediaWiki categorymembers generator only supports two server-side sort modes via the gcmsort parameter:

gcmsort Description
sortkey Default. By per-page category sort key (see caveat below).
timestamp When the page was added to the category (not when it was edited).

Direction is controlled by gcmdir=ascending|descending.

In this demo every column (pageid, title, preview, length, touched, contentmodel, pagelanguage) is marked sortable="false" in index.html: the API exposes no sort key for most of them, client-side sorting would be misleading on a partially loaded infinite-scroll dataset, and sortkey is not a true title sort (see the caveat below). The data manager still maps a title sort to gcmsort=sortkey / gcmdir, so re-enabling sorting on Title is a markup-only change.

⚠️ Caveat — sortkey is NOT strict alphabetical-by-title. The category sort key is a per-page string set manually by editors with [[Category:Web frameworks|<sortkey>]]. When omitted it defaults to the page title, but many pages override it (e.g. Apache Cocoon may be filed under Cocoon, The Sponge Framework under Sponge). The resulting order looks roughly alphabetical but contains surprises; there is no way to get a strict title sort from this generator.

💡 Why formatversion=2 matters. With the legacy formatversion=1 response, query.pages is an object keyed by pageid. Iterating it with Object.values(...) in JavaScript silently re-sorts entries numerically by pageid, destroying the server's sort order. We request formatversion=2 so query.pages comes back as an ordered array that preserves the API's gcmsort ordering.

Etiquette

The Wikimedia Foundation asks API consumers to set a descriptive User-Agent header. Browsers do not allow JS to override User-Agent, so the demo cannot do this — for production scrapers please proxy through a backend that sets one. See https://meta.wikimedia.org/wiki/User-Agent_policy.

Run

Serve the workspace root with any static server, then open /samples/wikipedia-pages-js/index.html.

Files

Notes for adapting to other continue-token APIs

The same pattern works for any API that returns an opaque continuation object that must be echoed back (Azure ARM nextLink, AWS NextToken, …). Only _buildUrl() and the response parser inside _get() need adapting.