feat: #3633914: Let the viewer formatters open the viewer on click and limit the viewers on a page

Closes #3633914

What changed

  • The Street-Level Viewer and Mapillary Leaflet Split Viewer formatters have an "Open the viewer" setting (viewer_load): immediate (default, today's behavior) or on_click.
  • Every viewer starts as a preview: the large thumbnail (else the small one; an expired signed URL is skipped and the cache max age ends with it), an "Open image" button and a "View on Mapillary" link. The viewer replaces the preview when it opens.
  • Drupal.mapillary.createViewer() returns null once 8 viewers are open on the page and puts the preview back if MapillaryJS throws. The new Drupal.mapillary.bindViewer() opens a viewer at once or when the button is pressed, and says why nothing opens on a full page. A removed viewer frees its place.
  • In the split viewer only the viewer waits; the map loads with the page, and a click on the map opens a closed viewer at the nearest image.
  • Without a browser token the formatters render the thumbnail and the link instead of "Mapillary viewer is not configured." and attach neither MapillaryJS nor the viewer script.
  • mapillary/mapillary_js declares MapillaryJS 4.1.2; the README lists it under Requirements. The module's scripts do not change for it.

Upgrade path

  • mapillary_field_post_update_viewer_load() and mapillary_leaflet_post_update_viewer_load() write viewer_load: immediate to the view displays that use the formatters, so they behave as before and match the schema. A display that already has a value is left alone. Layout Builder overrides default to immediate at runtime.
  • No schema change in the database.

Tests

  • Kernel: MapillaryViewerFormatterTest (setting, form, summary, thumbnail choice, expired thumbnail, no-token markup), ViewerLoadPostUpdateTest in both modules, MapillaryLeafletFormatterTest.
  • FunctionalJavascript, with the recording MapillaryJS of mapillary_viewer_test: ViewerBehaviorTest (preview replaced, button opens, ninth viewer stays closed until a place is free), SplitViewerLoadTest (opens with the page, button, map click), SplitViewerBaseLayerTest.
  • Functional: SecurityTokenExposureTest (updated for the no-token markup), the two formatter tests.
  • Run locally: only the tests above, all green. phpcs, phpstan, eslint, stylelint, prettier and cspell were run with the core versions on the changed files. The full run is left to the pipeline.

Notes

  • SplitViewerLoadTest replaces Drupal.mapillary.nearestImage() in the page: the script fetches with credentials: 'omit', which does not carry the test site's cookie. The function has its own test (MapillaryGeoHelperTest).
  • MapillaryJS 4.1.0 with these scripts was not tried.

Merge request reports

Loading
Loading