series.json: a new `indiaState` series, modelled on `country`, so a state poster names itself honestly
("India State Maps", "What is a State Prayer Map?", one sheet for each state and union territory of India,
"which state God has put on their heart"). The country series' text would have called Gujarāt one of the
~170 Country Maps. Approved as the default wording; shown as editable.
check:series-isolation, two blind spots found by adding a third series:
- Shared wording was dropped from only the EARLIER series (sets were mutated while still being compared),
so the later one kept it as a fingerprint and the earlier failed for carrying it. The shared set is now
found on the original sets. Self-test: three series in any order; the old loop fails it.
- The contamination scan never read a series' `poster` block, where a country poster once printed the
UPG-100 side box. It does now. The phrases that NAME country and indiaState are hand-listed, so a
verbatim copy of one's framing into the other is caught even though symmetric dropping treats it as shared.
Self-test 9/9, including both directions of a country/state copy.
countrySheet.js: the seriesFor comment no longer says "map 1 of 0" was printed; it was latent (the map-only
packet page prints no series line, and the India poster is gated), as a rendered check showed.
98 lines
6 KiB
JavaScript
98 lines
6 KiB
JavaScript
/**
|
|
* countrySheet.js — a country's map sheet, GENERATED in the browser at the click.
|
|
*
|
|
* SHARED (@map/packet/countrySheet.js). Its callers are the regions dashboard's regions-list and the
|
|
* Country Posters wall (country-poster-wall.vue), which used to define its own inline copy.
|
|
*
|
|
* ⚠ THE MOVE HERE WAS NEVER FINISHED, and it cost a real defect. This module's comment used to claim
|
|
* two consumers -- the country-poster wall and <doxa-country-map> -- and a CENSUS of the tree found
|
|
* it had NONE: nothing imported it at all. regions-list kept importing a byte-identical plugin-local
|
|
* copy (src/country-sheet-print.js), and country-poster-wall.vue defines its own inline countrySheet
|
|
* that calls generateCountrySheet directly. So this file was an ORPHAN wearing a comment that said
|
|
* otherwise.
|
|
* That mattered the moment the country poster's hue became data-driven: the region key was added
|
|
* HERE, where nothing read it, while the copy regions-list actually imported went on building
|
|
* `country` without a region -- so countryRegionColor(undefined) returned the old flat teal and
|
|
* warned. The same country then printed HUED from Country Posters and TEAL from the Regions tab,
|
|
* which is exactly the "two different posters for one country" the hue change exists to refuse.
|
|
* The copy is deleted, and regions-list and the wall both import this (check:country-sheet-one-path
|
|
* refuses a caller that draws a country sheet any other way). Do not re-copy it: a duplicate of this file is
|
|
* indistinguishable from it until one of them is edited, and then it is a silent divergence.
|
|
*
|
|
* The print standard is generate, store only previews: no country sheet is shipped, and none should
|
|
* be. MEASURED before this existed: data/posters holds 28 .html sheets and all 28 are ZONES, while
|
|
* emit-countries.mjs writes only country-posters.json, whose `sheet` field is a PAPER SIZE ('3x3')
|
|
* rather than a filename. So a packet's page-1 lift for a country asked for posters/country-<iso3>.html
|
|
* and got a 404 for all 175 of them. This draws it instead.
|
|
*
|
|
* Same shape as my-upg-100-list's zone sheet (data/zone-sheet-print.js), deliberately, so the two
|
|
* surfaces cannot draw the "same" sheet two ways:
|
|
*
|
|
* const sheet = makeCountrySheet({ records, assetsBase: () => base })
|
|
* usePosterPrints({ …, sheet }) // (item, format) -> html
|
|
* <PosterWall :sheet="sheet" />
|
|
*
|
|
* The country case is simpler than the zone case: generateCountrySheet resolves the zone and its
|
|
* geometry from the country entry itself, so there is no assignment step to keep in sync.
|
|
*/
|
|
|
|
/**
|
|
* @param {object} o
|
|
* records (selector) => Promise<rows[]> the shared provider; this asks it for ONE country
|
|
* assetsBase () => string where boundaries/ is served from
|
|
* @returns {(item, format) => Promise<string>} the sheet's HTML, or '' when it cannot be drawn
|
|
*/
|
|
/**
|
|
* The sheet's SERIES facts, computed exactly as the Country Posters wall computes them
|
|
* (country-poster-wall.vue): the tier is every country printed at the same sheet size, the total is
|
|
* that tier's length, and the index is the country's position in it by id. So a country's printed
|
|
* "map N of M" and "one of a ~M-map set" agree with the wall's print and with its own thumbnail.
|
|
*
|
|
* ★ WHY THIS EXISTS: without a series, generateCountrySheet falls back to totalLists 0, and every
|
|
* Regions-tab print read "map 1 of 0" and "one of a 0-map set called the Country Maps" -- nonsense
|
|
* on a printed poster, on the demo's showcase flow (Regions -> a country -> Poster Map). This was
|
|
* not introduced by the one-definition change: the plugin-local copy regions-list used before it
|
|
* passed no series either. The wall was never affected because it computes its own.
|
|
*
|
|
* Returns undefined when the item is not in the list (a host's country with no poster), so that row
|
|
* keeps the renderer's own default rather than a fabricated position.
|
|
*
|
|
* A null sheet is a tier too: India (sheet null, too many groups for any paper size) is its own
|
|
* 1-of-1 series. Skipping it gave India's sheet "map 1 of 0" on the Regions path and "map 1 of 1" on the
|
|
* wall's old copy. Neither was visible then (the map-only packet page prints no series line, and India's
|
|
* poster is gated), but any India sheet with a header would have shown it.
|
|
* Every null-sheet country shares that ONE oversized series: a second would make India "map 1 of 2".
|
|
* check:country-sheet-one-path fails when that happens, so it is decided, not drifted into.
|
|
*/
|
|
export function seriesFor(countries, item) {
|
|
if (!item || !Array.isArray(countries)) return undefined
|
|
const tier = countries.filter((x) => (x.sheet ?? null) === (item.sheet ?? null))
|
|
const index = tier.findIndex((x) => x.id === item.id) + 1
|
|
if (!index) return undefined
|
|
return { totalGroups: tier.reduce((a, x) => a + (x.count || 0), 0), totalLists: tier.length, index }
|
|
}
|
|
|
|
export function makeCountrySheet({ records, assetsBase, countries = null }) {
|
|
return async function countrySheet(item, format) {
|
|
const iso3 = item && item.iso3
|
|
if (!iso3) return '' // a selection or a row without a country: no sheet
|
|
// Lazy, like the zone sheet: the generator and the boundary loader are only pulled when a
|
|
// reader actually prints, so they stay out of every wall's initial download.
|
|
const { generateCountrySheet } = await import('@map/packet/posterSheets.js')
|
|
const [{ ISO3_NAME }, rows] = await Promise.all([
|
|
import('@map/data/iso3-name.js'),
|
|
records({ type: 'country', values: [iso3] }),
|
|
])
|
|
if (!rows || !rows.length) return '' // nothing to pin: fall through rather than draw an empty country
|
|
return generateCountrySheet({
|
|
// region travels: countryZone colours the sheet from it, and a country arriving without one
|
|
// silently falls back to the old flat teal for that poster alone.
|
|
country: { id: item.id, iso3, label: item.label, count: item.count, region: item.region },
|
|
records: rows,
|
|
assetsBase: assetsBase(),
|
|
ISO3_NAME,
|
|
format,
|
|
series: seriesFor(countries, item),
|
|
})
|
|
}
|
|
}
|