Revision history for HTML-OSM

0.13	Wed Nov  4 10:02:06 AM EST 2026
	[ Enhancements ]
	- new(scale => 1) adds Leaflet's scale bar, in kilometres and miles.  It
	  is redrawn as the reader moves and zooms
	- new(legend => [ { label, colour, radius, group }, ... ]) draws a key in
	  a corner of the map (legend_position, default topright), headed by
	  legend_title.  A radius gives a swatch that size, for a key to the
	  sizes of circle markers
	- add_marker() and add_circle_marker() take group.  A key entry with a
	  group is listed only while a marker of that group is in view, so the
	  key changes as the reader pans and zooms; a marker inside a cluster
	  counts.  When nothing is listed the key says legend_empty ("Nothing in
	  this view")
	- new() croaks on a key entry it cannot draw and on a position that is
	  not a corner; onload_render() leaves out such an entry from a config
	  file or a clone, with a warning.  Every text in the key is written as
	  text, never as HTML
	- new(fit => 1) opens the map on every pin and circle marker, zooming in
	  no further than zoom, and "Reset Map" returns there.  Without it the
	  map still opens at zoom around the markers' midpoint, which can leave
	  them all out of view.  A centre set with center() wins

	[ Tests ]
	- Add t/legend.t (scale, legend, legend_title, legend_position,
	  legend_empty, group and fit)
	- t/30-basics.t no longer asks Nominatim about "xyzzy" to test an unknown
	  centre location; it uses a geocoder stub that finds nothing.  The test
	  failed whenever Nominatim found a place of that name (RT#179908).  An
	  address the geocoder cannot find is now tested through add_marker()
	  too.  Only the CDN checks need the internet, so the rest of the file
	  runs without it and Test::RequiresInternet is no longer needed
	- t/conf/new.yml covers legend_position
	- Require Test::Mockingbird 0.03, the first version with the
	  mock 'Pkg::method' => sub { ... } form the tests use.  With 0.02 eight
	  test files failed to compile
	  Fixes https://www.cpantesters.org/cpan/report/876c3bf2-cf9d-11f1-a02c-9138a504d503
	- .github/workflows/actionlint.yml lints every workflow on push and pull
	  request: actionlint reads each expression with the contexts available where
	  it stands, which is how Database-BI's browser.yml was refused whole -
	  "Unrecognized named-value: 'runner'" for ${{ runner.temp }} in a job-level
	  env, with none of its four jobs run - and shellcheck checks the shell inside
	  every run: block.  Both are downloaded from a pinned release with a
	  verified checksum, and the workflows are found rather than listed, so one
	  added later is covered without being added here as well.  The file is the
	  one the distributions that share these workflows carry unchanged - the
	  contract job's four callers, the siblings it checks out and the eight the
	  location-predicate fuzz assembles - so the copies here are held to the same
	  rules.
	- The findings it reported in .github/workflows/perl-ci.yml are fixed rather
	  than silenced: the documented `eval "$(perl -Mlocal::lib)"` idiom is quoted
	  (SC2046), and `find lib -name '*.pm' | xargs` is -print0 and -0 now
	  (SC2038), so a module path holding a space is no longer split into two.
	- The other copies in this repository are fixed too: dashboard.yml and
	  mutate.yml quote their writes to $GITHUB_ENV and $GITHUB_PATH (SC2086) and
	  give `find xt ... | xargs git add` -print0 and -0 (SC2038).  mutate.yml's
	  mutator command and its flags are arrays rather than strings split by the
	  shell - an empty string that relied on splitting to vanish is an empty
	  array - and `command -v` replaces `which`, so the branch taken is about
	  whether the program exists rather than what a wrapper printed.

0.12	Fri Oct 23 09:19:01 PM EDT 2026
	[ Enhancements ]
	- new(search => 0) leaves out the Nominatim search box, the "Clear search
	  markers" button and their script, so nothing typed on the page leaves
	  the reader's machine.  The "Reset Map" button stays.  The default is
	  still to include the search box
	- new(max_zoom => N) sets maxZoom (0-28) on the tile layer, for tile
	  servers that have no tiles beyond a given zoom level
	- New add_circle_marker() draws a filled circle with a radius in pixels
	  and a hex colour, for bubble maps.  It takes the same points as
	  add_marker(), joins the cluster group when cluster => 1 is set, and
	  counts towards the map's bounds, so a map of circles alone needs no
	  center() call
	- onload_render() checks max_zoom and the circle markers again, as it does
	  zoom, width and height

	[ Tests ]
	- Add t/options.t (search, max_zoom) and t/circle_marker.t

0.11	Mon Oct 19 09:48:31 PM EDT 2026
	[ Bug Fixes ]
	- Heatmap radius and blur are now forced to positive numbers, so they can
	  no longer inject JavaScript
	- onload_render() checks zoom, width and height again (values from a
	  config file or a clone skip new()'s checks) and falls back to the
	  defaults with a warning
	- CDN URLs are HTML-escaped in the <head> fragment
	- A lone carriage return in a label no longer breaks the JavaScript
	- add_marker('') and center('') return 0 instead of croaking from a
	  private helper; a coordinate with no lat/lon and no address is skipped
	- A user agent passed in by the caller is no longer reconfigured
	- Some perls (seen with 5.38.0 on macOS) print and read numbers with the
	  locale's decimal point, so under de_DE 51.5074 printed as "51,5074" and
	  "51.5074" was read as 51.  Coordinates were rejected, and the computed
	  map centre lost its fractions.  Coordinates are now always written with
	  a '.', converted to numbers without the locale, and range-checked
	  correctly ("90.5" was read as 90 and accepted).  JSON layers are
	  encoded under the C numeric locale, and heatmap radius/blur accept
	  decimals such as "12.5"
	  Fixes https://matrix.perl-magpie.org/results/97965e64-9dc9-11f1-963c-fccfcb508d96

	[ Enhancements ]
	- new(tile_url => ...) replaces the OpenStreetMap tile layer, so maps can
	  use an internal tile server or run on an air-gapped network
	- new(tile_attribution => ...) replaces the map credit; the default now
	  links to the OpenStreetMap copyright page
	- new(email => ...) adds a contact address to Nominatim requests, as the
	  Nominatim usage policy asks

	[ Documentation ]
	- Add a DESCRIPTION section
	- MESSAGES tables now match the exact croak text and list the warnings
	- Document that only one map can be rendered per page

	[ Build ]
	- Declare IPC::System::Simple as a runtime prerequisite: autodie qw(:all)
	  needs it when the module loads
	- Set MIN_PERL_VERSION to 5.010
	- Remove ExtUtils::MakeMaker from PREREQ_PM (it stays in CONFIGURE_REQUIRES)
	- Declare HTTP::Response for tests; drop unused Test::JSON,
	  Test::HTML::Lint and Test::Warnings

	[ Tests ]
	- Cover the default tile URL, a configured tile URL and JS-string escaping
	- Cover tile_attribution, email, the render-time checks and the new
	  escaping helpers
	- Simulate comma-decimal number printing so the locale fix is tested on
	  every platform, and check the rendered output under real locales

0.10	Sun Jul 12 21:23:33 EDT 2026
	[ Bug Fixes ]
	- Don't try to call a method on an uninitialized variable
	- Use consistent default sizes
	- Bump minimum versions
	- Set maximum zoom to 19
	- Fix function-style HTML::OSM::new() with arguments blessing into wrong package

	[ Enhancements ]
	- Re-enable search box and reset button in rendered map
	- Add "Clear search markers" button to remove dynamically-added markers
	- add_geojson(): render GeoJSON layers via Leaflet-native L.geoJSON()
	- add_heatmap(): render heatmap layers via Leaflet.heat plugin
	- add_gpx(): render GPX tracks from a URL via leaflet-gpx plugin
	- add_choropleth(): data-driven colour-fill layers; colours pre-computed in Perl
	- new(cluster=>1): group markers with Leaflet.markercluster plugin
	- onload_render() no longer requires point markers when GeoJSON/heatmap/GPX/choropleth data is present
	- Use Params::Validate::Strict on new()
	- Added the test dashboard at https://nigelhorne.github.io/HTML-OSM/coverage/

	[ Tests ]
	- Started fuzz testing
	- Extend new() fuzz schema with zoom, height, width and min_interval inputs

0.09	Thu Jul 31 11:15:55 EDT 2025
	Remove unused module: File::Slurp
	Use Params::Get, Object::Configure
	Don't test URLs on smokers

0.08	Wed Apr  2 07:51:24 EDT 2025
	Added css_url and js_url arguments to new()
	Default Leaflet bumped from 1.7.1 to 1.9.4
	Added config_file argument to new()

0.07	Fri Feb 28 15:07:03 EST 2025
	Center() was being ignored
	Changed default zoom to 12

0.06	Wed Feb 19 08:20:29 EST 2025
	Remove unwanted <head> and <title> information

0.05	Mon Feb 17 20:24:18 EST 2025
	More compatiblity with Geo::Coder::* modules
	Allow coordinates to start with a decimal point, e.g. "-.516667"
	Changed the default zoom to 17

0.04	Mon Feb 17 14:32:21 EST 2025
	Allow center() to be given a location string

0.03	Sun Feb 16 21:36:35 EST 2025
	Change the default size to be the same as HTML::GoogleMaps::V3
	Improved handling when an ARRAY is returned by Nominatim
	Remove the search and reset buttons
	Use %20 rather than ' ' in the URL

0.02	Sun Feb 16 14:44:32 EST 2025
	Added rate-limiting and caching support

0.01	Sun Feb 16 12:46:54 EST 2025
        First draft
