The section the Country Posters tab draws (a collapsible region head + its poster cards) is now usable on its
own, for any poster set, by parameters:
- library/components/poster/posterTypes.js: a TYPE REGISTRY. A type is an adapter (items for a scope, the
section's title, the print actions). The library registers 'country' (library data + the shared sheet path,
so a withheld whole-country poster stays withheld); plugins register their own types from their own code
(UPG 100 lists, regions, continents later). No plugin code in the library.
- 'country' scopes: a region key in any spelling. DX Life's /regions slug ('latin-america-and-caribbean'),
the API's value, the wall's slug and the English name all reduce to one canonical key.
- PosterSectionView.vue: one section, drawn by a PosterWall in a new SECTION-ONLY mode (no wall head; off by
default, so every existing wall renders as before), embedded so the page scrolls it.
- <dxm-poster-section type scope collapsible collapsed locale assets-base api-base-url is-dark>: the
attributes map onto the standard element's profile-config (posterSectionConfig.js, pure), so it keeps the
per-instance i18n and store. registerPosterSectionElement() from any bundle; Country Posters ships it first.
- country-posters/poster-section: a page showing two sections (Africa open, Oceania collapsed).
- poster.sectionNone (11 locales): an unknown type or an empty scope says so, never a blank.
check:poster-section (gates:pre) + self-test: the registry, DX Life's 8 scopes covering every country once,
withheld India, the attribute mapping, and PosterSection.vue injecting every name its template uses; 3 poisons.
The known collapse-while-scrolled landing is left exactly as it is.
40 lines
1.9 KiB
JavaScript
40 lines
1.9 KiB
JavaScript
/**
|
|
* posterSectionElement.js — registers <dxm-poster-section>: ONE poster section, any poster type, as an element.
|
|
*
|
|
* <dxm-poster-section type="country" scope="africa" locale="ar"></dxm-poster-section>
|
|
*
|
|
* Attributes: type (default "country"), scope (a region / continent / list key), collapsible (default on;
|
|
* collapsible="false" turns it off), collapsed (start shut), locale, assets-base, api-base-url, is-dark.
|
|
* They are mapped into the standard element's profile-config, so the element keeps defineMapElement's per-instance
|
|
* i18n and store, and the profile (PosterSectionView.vue) reads them like every other profile reads its config.
|
|
* Any bundle can call registerPosterSectionElement(); a second call is a no-op.
|
|
*/
|
|
import { defineMapElement } from './defineMapElement.js'
|
|
|
|
import { ATTRS, TAG, posterSectionConfig } from './posterSectionConfig.js'
|
|
export { posterSectionConfig }
|
|
|
|
export function registerPosterSectionElement(tag = TAG) {
|
|
if (typeof customElements === 'undefined' || customElements.get(tag)) return
|
|
const Base = defineMapElement({ profileModules: { './poster-section.vue': () => import('../components/poster/PosterSectionView.vue') } })
|
|
class PosterSectionElement extends Base {
|
|
connectedCallback() {
|
|
this.syncConfig()
|
|
if (!this.attrWatch) {
|
|
this.attrWatch = new MutationObserver(() => this.syncConfig())
|
|
this.attrWatch.observe(this, { attributes: true, attributeFilter: ATTRS })
|
|
}
|
|
super.connectedCallback()
|
|
}
|
|
disconnectedCallback() {
|
|
if (this.attrWatch) { this.attrWatch.disconnect(); this.attrWatch = null }
|
|
super.disconnectedCallback()
|
|
}
|
|
syncConfig() {
|
|
const next = JSON.stringify(posterSectionConfig(this))
|
|
if (this.getAttribute('profile-config') !== next) this.setAttribute('profile-config', next)
|
|
}
|
|
}
|
|
customElements.define(tag, PosterSectionElement)
|
|
}
|
|
export default registerPosterSectionElement
|