Test Page

Testing leaflet shortcode inputs and error-handling behaviour

This page exercises various arguments and features of the leaflet shortcode extension, including a suite of error cases. For error cases the extension must never crash — it must either render a visible error message or silently skip the bad input and continue rendering.

Note

All tests are run in the HTML output format.

1 YAML-based maps

1.1 Minimal — center only

Default height (400px) is used when height is omitted.

leaflet:
  t-minimal:
    center: [51.505, -0.09]
{{< leaflet t-minimal >}}

1.2 Basic — center, zoom, height

leaflet:
  t-basic:
    center: [51.505, -0.09]
    zoom: 13
    height: "380px"
{{< leaflet t-basic >}}

1.3 Markers — all popup/tooltip combinations

Tests four markers:

Marker popup tooltip
Stockholm
Djurgården
Södermalm
Unnamed point

1.4 Markers from TSV (markers-file + separator)

Loads markers from data/stockholm-markers.tsv using lat/lon, popup, tooltip, and icon columns.

leaflet:
  t-markers-tab:
    center: [59.33, 18.07]
    zoom: 12
    markers-file: "data/stockholm-markers.tsv"
    markers-sep: "\t"

1.5 Markers from CSV

Loads markers from data/stockholm-markers.csv using the generic markers-file option.

leaflet:
  t-markers-csv:
    center: [59.33, 18.07]
    zoom: 12
    markers-file: "data/stockholm-markers.csv"

1.6 Markers from semicolon-separated .txt

leaflet:
  t-markers-semi-txt:
    center: [59.33, 18.07]
    zoom: 12
    markers-file: "data/stockholm-markers-semicolon.txt"
    markers-sep: ";"

1.7 Markers from pipe-separated .txt

leaflet:
  t-markers-pipe-txt:
    center: [59.33, 18.07]
    zoom: 12
    markers-file: "data/stockholm-markers-pipe.txt"
    markers-sep: "|"

1.8 Icon markers — Font Awesome

Tests icon, icon-color, icon-size, and icon-anchor.

---
leaflet:
  t-icons:
    center: [48.86, 2.35]
    zoom: 13
    height: "380px"
    markers:
      - lat: 48.8584
        lon: 2.2945
        popup: "<b>Eiffel Tower</b>"
        icon: "fa-solid fa-house"
        icon-color: "tomato"
        icon-size: 16
      - lat: 48.8606
        lon: 2.3376
        popup: "<b>Louvre Museum</b>"
        icon: "fa-solid fa-building-columns"
        icon-color: "#4a90d9"
        icon-size: 16
        icon-anchor: [12, 24]           # explicit anchor offset
      - lat: 48.853
        lon: 2.3499
        popup: "<b>Notre-Dame</b>"
        icon: "fa-solid fa-church"
        icon-color: "green"
        icon-size: 16
---

{{< leaflet t-icons >}}

1.9 Default markers and Font Awesome icons together

This map exists to catch the packaging bug where default Leaflet markers disappear while Font Awesome icon markers still render. All three markers below must be visible at the same time.

---
leaflet:
  t-default-vs-fonticon:
    center: [51.505, -0.09]
    zoom: 13
    height: "340px"
    markers:
      - lat: 51.505
        lon: -0.09
        popup: "Default Leaflet marker"
        tooltip: "Default marker"
      - lat: 51.51
        lon: -0.082
        popup: "Font Awesome marker"
        tooltip: "Font Awesome icon"
        icon: "fa-solid fa-house"
        icon-color: "tomato"
        icon-size: 20
      - lat: 51.5
        lon: -0.1
        popup: "Second default Leaflet marker"
        tooltip: "Default marker 2"
---
{{< leaflet t-default-vs-fonticon >}}

1.10 FontAwesome markers

These icon-font markers render without extra page setup because the extension loads Font Awesome automatically.

leaflet:
  t-fontawesome:
    center: [41.9028, 12.4964]
    zoom: 13
    markers:
      - lat: 41.9028
        lon: 12.4964
        icon: "fa-solid fa-landmark"
      - lat: 41.89
        lon: 12.4922
        icon: "fa-solid fa-torii-gate"
      - lat: 41.8986
        lon: 12.4768
        icon: "fa-solid fa-tree"

1.11 FontAwesome dense markers

Stress test with 50 markers and 50 different Font Awesome icon classes.

1.12 Custom image icon

The first marker uses a remote PNG via icon: {url: ..., size: [...], anchor: [...]}.

leaflet:
  t-image-icon:
    center: [51.5, -0.09]
    zoom: 13
    height: "340px"
    markers:
      - lat: 51.5
        lon: -0.09
        popup: "Custom image icon"
        icon:
          url: "https://leafletjs.com/examples/custom-icons/leaf-green.png"
          size: [38, 95]
          anchor: [22, 94]
      - lat: 51.505
        lon: -0.07
        popup: "Default blue marker alongside custom icon"

1.13 Custom tile layer — CartoDB dark

Tests the tile sub-object with url, attribution, subdomains, and maxZoom.

leaflet:
  t-tile-dark:
    center: [40.7128, -74.006]
    zoom: 11
    height: "380px"
    tile:
      url: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png"
      attribution: "&copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors &copy; CARTO"
      subdomains: "abcd"
      maxZoom: 20
    markers:
      - lat: 40.7128
        lon: -74.006
        popup: "<b>New York City</b>"
        icon: "fa-solid fa-house"
        icon-color: "#ff6b6b"
        icon-size: 20

1.14 Custom tile layer — CartoDB Voyager

leaflet:
  t-tile-voyager:
    center: [35.68, 139.69]
    zoom: 12
    height: "340px"
    tile:
      url: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png"
      attribution: "&copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors &copy; CARTO"
      subdomains: "abcd"
      maxZoom: 19

1.15 Passthrough Leaflet options

Passes zoomControl, scrollWheelZoom, dragging, doubleClickZoom, keyboard, minZoom, and maxZoom directly to L.map(). Scroll-wheel zoom and double-click zoom are disabled; dragging is on.

leaflet:
  t-passthrough:
    center: [40.7128, -74.006]
    zoom: 14
    height: "340px"
    zoomControl: false
    scrollWheelZoom: false
    dragging: true
    doubleClickZoom: false
    keyboard: false
    minZoom: 10
    maxZoom: 18

1.16 Passthrough Leaflet options — full map option set

Exercises the remaining top-level L.map() options listed in README, including mixed-type options like doubleClickZoom, scrollWheelZoom, and touchZoom with the string value "center".

leaflet:
  t-passthrough-all:
      center: [40.7128, -74.006]
      zoom: 13
      height: "340px"
      zoomControl: true
      attributionControl: true
      closePopupOnClick: true
      minZoom: 3
      maxZoom: 18
      zoomSnap: 0.5
      zoomDelta: 0.5
      trackResize: true
      boxZoom: true
      doubleClickZoom: "center"
      dragging: true
      scrollWheelZoom: "center"
      inertia: true
      inertiaDeceleration: 3200
      inertiaMaxSpeed: 1400
      easeLinearity: 0.2
      worldCopyJump: false
      maxBoundsViscosity: 0.5
      keyboard: true
      keyboardPanDelta: 80
      wheelDebounceTime: 40
      wheelPxPerZoomLevel: 60
      touchZoom: "center"
      bounceAtZoomLimits: true
      tapHold: true
      tapTolerance: 15
      zoomAnimation: true
      zoomAnimationThreshold: 4
      fadeAnimation: true
      markerZoomAnimation: true
      transform3DLimit: 8388608
      preferCanvas: false

1.17 Custom tile layer — all listed tile options

Exercises all listed tile sub-options from README in a single map config.

leaflet:
  t-tile-all-options:
    center: [40.7128, -74.006]
    zoom: 11
    height: "340px"
    tile:
      url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      attribution: "&copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"
      minZoom: 0
      maxZoom: 19
      minNativeZoom: 0
      maxNativeZoom: 19
      subdomains: "abc"
      errorTileUrl: "https://tile.openstreetmap.org/0/0/0.png"
      zoomOffset: 0
      tms: false
      zoomReverse: false
      detectRetina: false
      crossOrigin: "anonymous"
      referrerPolicy: "no-referrer"
      opacity: 0.95
      zIndex: 1
      className: "ql-test-tile"
      pane: "tilePane"
      tileSize: 256
      updateWhenIdle: false
      updateWhenZooming: true
      updateInterval: 200
      keepBuffer: 2
      noWrap: false

2 Inline shortcode maps

2.1 Minimal inline — center + zoom

{{< leaflet center="[48.86, 2.35]" zoom=14 >}}

2.2 Inline with explicit height

{{< leaflet center="[48.86, 2.35]" zoom=14 height="320px" >}}

2.3 Inline with passthrough options

scrollWheelZoom and zoomControl passed inline.

{{< leaflet center="[35.68, 139.69]" zoom=11 height="320px" scrollWheelZoom=false zoomControl=false >}}

2.4 Inline passthrough with string-valued options

Checks that case-sensitive string values are preserved inline (for options that accept string forms in Leaflet).

{{< leaflet center="[35.68, 139.69]" zoom=11 height="320px" scrollWheelZoom="center" touchZoom="center" doubleClickZoom="center" >}}

2.5 Inline custom tile JSON

Checks inline tile JSON object parsing.

{{< leaflet center="[40.7128, -74.006]" zoom=11 height="320px" tile='{"url":"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png","attribution":"&copy; OpenStreetMap"}' >}}

2.6 Inline custom tile JSON (single-item array wrapper)

Checks backward-compatible parsing of tile as a one-element JSON array.

{{< leaflet center="[40.7128, -74.006]" zoom=11 height="320px" tile='[{"url":"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png","attribution":"&copy; OpenStreetMap"}]' >}}

2.7 Inline with JSON markers

Markers are supplied as a JSON string.

{{< leaflet center="[59.33, 18.07]" zoom=12 height="320px"
    markers='[{"lat":59.33,"lon":18.07,"popup":"<b>Stockholm</b>","tooltip":"Stockholm"},{"lat":59.35,"lon":18.10,"popup":"Djurgården"},{"lat":59.31,"lon":18.05,"popup":"Södermalm"}]' >}}

2.8 Inline with TSV markers (markers-file + separator)

{{< leaflet center="[59.33, 18.07]" zoom=12 height="320px" markers-file="data/stockholm-markers.tsv" markers-sep="\t" >}}

2.9 Inline with CSV markers

{{< leaflet center="[59.33, 18.07]" zoom=12 height="320px" markers-file="data/stockholm-markers.csv" >}}

2.10 Inline with semicolon-separated .txt markers

{{< leaflet center="[59.33, 18.07]" zoom=12 height="320px" markers-file="data/stockholm-markers-semicolon.txt" markers-sep=";" >}}

2.11 Multiple inline maps on the same page

Each map must receive a unique HTML id and JS variable name.

{{< leaflet center="[35.68, 139.69]" zoom=10 height="260px" >}}
{{< leaflet center="[-33.87, 151.21]" zoom=11 height="260px" >}}

2.12 Inline Font Awesome icons

This checks inline JSON markers using Font Awesome classes.

{{< leaflet center="[41.9028, 12.4964]" zoom=13 height="320px"
  markers='[{"lat":41.9028,"lon":12.4964,"popup":"<b>Roman Forum</b>","icon":"fa-solid fa-landmark","icon-color":"#b04a2b","icon-size":20},{"lat":41.89,"lon":12.4922,"popup":"<b>Colosseum</b>","icon":"fa-solid fa-torii-gate","icon-color":"#5c6f7b","icon-size":20},{"lat":41.8986,"lon":12.4768,"popup":"<b>Piazza Navona</b>","icon":"fa-solid fa-tree","icon-color":"#2f7d32","icon-size":20}]' >}}

3 Error handling

All cases below must not crash Quarto rendering. The extension either emits a visible error notice or silently skips the offending input.

3.1 No arguments whatsoever

With no center and no usable marker coordinates, the extension must report the error without crashing.

{{< leaflet >}}

Expected: visible error — 'center' is required

⚠ leaflet: 'center' is required

3.2 Named label that does not exist in metadata

{{< leaflet no-such-map >}}

Expected: visible error — map 'no-such-map' not found in metadata

⚠ leaflet: map 'no-such-map' not found in metadata

3.3 Invalid center — no brackets

{{< leaflet center="51.505,-0.09" zoom=13 >}}

Expected: visible error — 'center' is required (no marker coordinates are available to derive it)

⚠ leaflet: 'center' is required

3.4 Invalid center — only one coordinate

{{< leaflet center="[51.505]" zoom=13 >}}

Expected: visible error — 'center' is required (no marker coordinates are available to derive it)

⚠ leaflet: 'center' is required

3.5 Invalid center — non-numeric values

{{< leaflet center="[abc, xyz]" zoom=13 >}}

Expected: visible error — 'center' is required (no marker coordinates are available to derive it)

⚠ leaflet: 'center' is required

3.6 Invalid center — empty brackets

{{< leaflet center="[]" zoom=13 >}}

Expected: visible error — 'center' is required (no marker coordinates are available to derive it)

⚠ leaflet: 'center' is required

3.7 Invalid center — too many coordinates

{{< leaflet center="[51.5, -0.09, 100]" zoom=13 >}}

Expected: visible error — 'center' is required (parser requires exactly 2 values and no marker coordinates are available)

⚠ leaflet: 'center' is required

3.8 Zoom as non-numeric string

zoom is invalid (tonumber returns nil); the shortcode falls back to 13.

{{< leaflet center="[51.505, -0.09]" zoom="very-high" height="300px" >}}

Expected: map renders with zoom level 13

3.9 Inline markers without center

Center is derived from the midpoint of the bounding box of the marker coordinates.

Expected: map renders and auto-centers on the marker centroid

3.10 YAML markers without center or zoom

Both values are derived from defaults: center from the marker centroid, zoom from the shortcode default.

Expected: map renders centered on the three markers at zoom 13

3.11 Marker file without center or zoom

The shortcode derives center from the file coordinates and uses zoom 13.

Expected: map renders with TSV markers, auto-centered at zoom 13

3.12 Invalid JSON for inline markers

Markers are silently dropped; the map still renders.

{{< leaflet center="[51.505, -0.09]" zoom=13 height="300px" markers="not-json-at-all" >}}

Expected: map renders without markers

3.13 Inline markers JSON — wrong root type (not an array)

{{< leaflet center="[51.505, -0.09]" zoom=13 height="300px" markers='{"lat":51.5,"lon":-0.1,"popup":"object not array"}' >}}

Expected: map renders without markers (JSON object instead of array is ignored)

3.14 Inline marker with missing position in JSON array

The marker without position is silently skipped; valid markers are added.

{{< leaflet center="[51.505, -0.09]" zoom=13 height="300px"
    markers='[{"popup":"no position"},{"lat":51.5,"lon":-0.1,"popup":"valid marker"}]' >}}

Expected: map renders with one marker (lat 51.5, lon -0.1)

3.15 YAML map with bad marker entries mixed with valid ones

Uses the t-bad-markers YAML map (defined in frontmatter) which includes:

  • A marker with no position key → skipped
  • A marker with position: "not-a-list" → skipped
  • Two valid markers → rendered

Expected: map renders with 3 visible markers (valid + out-of-range as Leaflet handles it)

3.16 YAML tile given as a boolean, not a sub-table

Uses the t-tile-bool YAML map where tile: true instead of a sub-object.

Expected: map renders using the default OpenStreetMap tile layer

3.17 Unknown / extra kwargs (passthrough)

Unrecognised kwargs are forwarded to L.map() as options. Leaflet ignores unrecognised options, so no error should occur.

{{< leaflet center="[51.505, -0.09]" zoom=13 height="280px" unknownOption="foo" anotherFake=42 >}}

Expected: map renders normally (unknown options are ignored by Leaflet)

3.18 Wrong separator for markers-file

The file exists, but markers-sep is intentionally wrong. Rows should fail to parse into valid marker coordinates, while the map itself still renders without crashing.

{{< leaflet center="[59.33, 18.07]" zoom=12 height="300px" markers-file="data/stockholm-markers-semicolon.txt" markers-sep="," >}}

Expected: map renders, but no markers are added.

3.19 Multiple positional args (not a valid named-label call)

When more than one positional arg is given, the shortcode falls through to kwargs mode. With no center kwarg the extension must report the missing argument because there are still no marker coordinates to derive it.

{{< leaflet t-basic extra-arg >}}

Expected: visible error — 'center' is required

⚠ leaflet: 'center' is required

3.20 Named label call with extra kwargs (kwargs win)

When both a positional label and kwargs are present, the code switches to kwargs mode and the label is ignored. With no center kwarg the shortcode reports the error because there are no marker coordinates in kwargs.

{{< leaflet t-basic zoom=13 >}}

Expected: visible error — 'center' is required (label is ignored; center kwarg and marker coordinates are absent)

⚠ leaflet: 'center' is required