Skip to content

Support several GeoJSON sources in one Leaflet map - #930

Merged
JeroenDeDauw merged 8 commits into
masterfrom
feature/multiple-geojson-sources
Jul 26, 2026
Merged

Support several GeoJSON sources in one Leaflet map#930
JeroenDeDauw merged 8 commits into
masterfrom
feature/multiple-geojson-sources

Conversation

@JeroenDeDauw

@JeroenDeDauw JeroenDeDauw commented Jul 26, 2026

Copy link
Copy Markdown
Member

Fixes #831

geojson becomes a list parameter, so {{#display_map:geojson=A;B}} and the Leaflet
result format show several GeoJson pages or URLs on one map. Each source is fetched
separately; sources that fail are dropped without affecting the rest.

The delimiter is ; rather than ParamProcessor's default ,, since commas are common
inside GeoJson page titles and URLs, and ; is what the other Maps list parameters use.
An existing value containing a semicolon now splits into several sources, which the
release notes call out.

The visual editor replaces the whole page it was opened on, so GeoJsonSource and
GeoJsonRevisionId are non-null only when exactly one non-empty value was given and it
resolved to a page in the GeoJson namespace. The count comes from the values given rather
than from which fetches succeeded, so a source becoming reachable or unreachable can never
turn the editor on for a map that shows several. The namespace condition also fixes a
pre-existing bug: the fetcher resolves any page whose content is JSON, so
geojson=MediaWiki:Maps used to show an edit button that saved to GeoJson:Maps.

Two further failure paths are fixed here: map data still in the parser cache after an
upgrade holds a single GeoJSON object, which the editor would have opened empty over a page
that still had features; and a source whose content is a bare JSON scalar made the fetcher
throw, taking the whole page render down.

Considered and omitted: each source as a separately toggleable overlay in the layer control
(a distinct feature); de-duplicating identical sources; Google Maps, which has no geojson
parameter. Left open: a cap on the number of sources. Wikitext could already trigger as many
fetches with one map per source, but Special:Ask takes result-format parameters straight
from the request and is not parser-cached, so one anonymous request can now trigger N
server-side fetches instead of one.

AI-authored — Claude Code, Opus 5 (max); detailed spec from @JeroenDeDauw, no redirections; diff not yet human-reviewed; every new test seen failing first, mutation-tested, reviewed by four independent AI passes whose blocking findings are fixed here, full PHPUnit and QUnit suites plus PHPStan and phpcs run locally, rendered map and editor gating checked in a browser; CI green.

JeroenDeDauw and others added 8 commits July 26, 2026 21:09
Fixes #831

`geojson` becomes a list parameter, so `{{#display_map:geojson=A;B}}` and the Leaflet
result format show several GeoJson pages or URLs on one map. Each source is fetched
separately; sources that fail are dropped without affecting the rest. The decoded values
go to `L.geoJSON()`, which takes a list natively.

The delimiter is `;` rather than ParamProcessor's default `,`, since commas are common
inside GeoJson page titles and URLs, and `;` is what the other Maps list parameters use.

The visual editor saves the whole map layer back to `GeoJson:<GeoJsonSource>`, which with
several sources would overwrite one page with the content of all of them. So
`GeoJsonSource` and `GeoJsonRevisionId` are set only when the parameter got exactly one
value that resolved to a GeoJson page, counted from the values given rather than from
which fetches succeeded, so an unrelated page being created or deleted never makes the
editor appear or disappear.

Considered and omitted: each source as a separately toggleable overlay in the layer
control (a distinct feature); a cap on the number of sources (a page can already trigger
as many fetches with one map per source); Google Maps, which has no `geojson` parameter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Mutation testing found two spots where production logic could be removed without any
test noticing: the resource module gate that only loads the GeoJSON editor for an
editable source, and the dropping of blank source names, which is what keeps
`geojson=A;` editable.

Also extracts the repeated two-page setup in LeafletTest and replaces the GeoJSON layer
counting helper in FeatureBuilderTest with one that can assert the layer is absent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Map data lives in the parser cache, which an extension upgrade does not invalidate, so the
new code sees `geojson` as a single GeoJSON object for up to $wgParserCacheExpireTime. The
length check then skipped the layer, and the editor was seeded with `geojson[0]` of an
object, so it opened empty over a page that still had features. Saving from there replaced
them with only what the user had just drawn.

Both readers now go through one normalization at the entry point, which also makes the
rendering path tolerate map data without a geojson key at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
GeoJsonFetcher resolves any page whose content model is JSON, including `MediaWiki:Maps`
and `User:*/*.json`. The editor builds its save target as `GeoJson:` plus the bare page
name, so such a source offered an edit button pointing at an unrelated page.

Also corrects the rationale in the docblock, which described the save as writing the
combined content of all sources when it writes just one of them, and pins the leading
delimiter case that the reindexing in the constructor exists for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A source containing a bare JSON number, string or boolean made normalizeJson() return a
non-array from a method declared `: array`, so the TypeError took down the whole page
render. With several sources per map, one such source would stop all the others from
rendering.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Say the geojson parameter takes a semicolon-separated list rather than
"several" values, and frame the splitting caveat as what it costs an
existing wiki. Drop "file" from the parameter description, where it
invites reading the accepted URLs as file:// ones.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@JeroenDeDauw
JeroenDeDauw marked this pull request as ready for review July 26, 2026 20:25
@JeroenDeDauw
JeroenDeDauw merged commit d799822 into master Jul 26, 2026
8 checks passed
@JeroenDeDauw
JeroenDeDauw deleted the feature/multiple-geojson-sources branch July 26, 2026 20:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for multiple GeoJSON files in the same map?

1 participant