bh 6.9.1 → 6.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29a85e5fc78e270eb30a28d5b6ac8e815b7f8ab8dc14a961080b4e11f5b7a6ce
4
- data.tar.gz: 92fe0b26cf3e684106552ce907b92a47b5b030cc33e5ddaf83d4f81e139b9704
3
+ metadata.gz: 323e18fad01eb3fdc146019166fdec96ecc7455a12b2ce170525ee07d5083c47
4
+ data.tar.gz: c6050641e6910669ef9b645b55cae1141f94370e9a3167ddd93937c4f28274eb
5
5
  SHA512:
6
- metadata.gz: 8c7f04aba5850ee986b0eec80c713049629b17eff4bdd922e7e981eaa0aeedb1f0d2776d0b263b2db61a26a1f6336667c4eb0b8b11b8ef633e5acaab19cd9298
7
- data.tar.gz: a65ea0eff219a4d095f6ee0b4215656c34ab17cde0b8ce0ea0a883f590014bd6d47c33756c99c83839cf28d2f84b065a2dd7d7bd459577bd5e429574f51160f1
6
+ metadata.gz: 901c770b2d53376cd82a3ccf7f0e09c3499f26415d3f10dc896488b483b344cfd6cef5d3eed869174337945338c3b79fc6c38e36f5ce02273d5ba6caad06a35a
7
+ data.tar.gz: 15f84dd6790385a89d6d8ca6b9fcceab7168ce0c8dcae1a63cc24e749c282a782d18f118f86a0e1fc85ee4ca94c2ec8d4d4634110abba83b839eca32f7da14bc
data/CHANGELOG.md CHANGED
@@ -8,6 +8,24 @@ For more information about changelogs, check
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## 6.10.0 - 2026-09-26
12
+
13
+ * [FEATURE] A pin or an area on a map leads where its row does
14
+
15
+ The map controller takes a point as `[lat, lng, href, title]` and a place as
16
+ `[id, href, title]`. A pin with an `href` is clickable, shows its `title` on hover, and a
17
+ click follows it through Turbo; an area filled on a boundary layer is followed the same
18
+ way. A bare `[lat, lng]` or a bare place ID still draws a pin that leads nowhere.
19
+
20
+ ## 6.9.2 - 2026-09-20
21
+
22
+ * [FIX] A small select's combobox is small too
23
+
24
+ The button that stands in for a `<select>` took the compact size from `form-select-sm`
25
+ alone, so a select wearing `form-control-sm` — which is what a filter beside a search
26
+ box wears — was replaced by a full-height one. It stood two pixels taller than the trail
27
+ beside it, which is what set the height of every row it sat in.
28
+
11
29
  ## 6.9.1 - 2026-09-20
12
30
 
13
31
  * [FIX] A combobox's search box carries an id
@@ -5,7 +5,7 @@
5
5
  // The toggle takes the select's size and its error, and is labelled the way the select was.
6
6
  export function menuFor(select, controller) {
7
7
  const toggle = element('button', 'form-control combobox-toggle', { type: 'button' })
8
- if (select.classList.contains('form-select-sm')) { toggle.classList.add('form-control-sm') }
8
+ if (['form-select-sm', 'form-control-sm'].some(size => select.classList.contains(size))) { toggle.classList.add('form-control-sm') }
9
9
  if (select.classList.contains('is-invalid')) { toggle.classList.add('is-invalid') }
10
10
  toggle.dataset.bsToggle = 'combobox'
11
11
  toggle.dataset.bsSearch = 'true'
@@ -6,6 +6,11 @@ import { load } from './map/loader.js'
6
6
  // none, a pin at the place; a row keeping coordinates is a pin there and then, with
7
7
  // nothing to look up. The key and the map are the host's, read from its credentials; the
8
8
  // rows are the page's, and the map is fitted round whatever it drew.
9
+ //
10
+ // A row may carry where it leads and what it is called: a point as `[lat, lng, href, title]`,
11
+ // a place as `[id, href, title]`, where a bare place ID or a bare `[lat, lng]` leads nowhere.
12
+ // A pin or an area with somewhere to lead is clicked through to it, the way the row's own
13
+ // link in the table is.
9
14
  export default class extends Controller {
10
15
  static values = { key: String, id: String, boundary: String, places: Array, points: Array }
11
16
 
@@ -30,7 +35,8 @@ export default class extends Controller {
30
35
  async place(map, bounds) {
31
36
  if (this.placesValue.length === 0) return
32
37
  const { Place } = await google.maps.importLibrary('places')
33
- const places = this.placesValue.map(id => new Place({ id }))
38
+ const rows = this.placesValue.map(row => [].concat(row))
39
+ const places = rows.map(([id, href, title]) => ({ place: new Place({ id }), href, title }))
34
40
 
35
41
  if (this.hasBoundaryValue) return this.fill(map, bounds, places)
36
42
  return this.pin(map, bounds, places)
@@ -38,13 +44,19 @@ export default class extends Controller {
38
44
 
39
45
  // The layer styles every boundary Google knows at that level, and a function saying
40
46
  // which of them are ours is what fills them in. The bounds are the places' viewports.
47
+ // An area with somewhere to lead is followed there when clicked.
41
48
  async fill(map, bounds, places) {
42
- const ours = new Set(this.placesValue)
43
- map.getFeatureLayer(this.boundaryValue).style = ({ feature }) => {
44
- if (ours.has(feature.placeId)) return FILLED
49
+ const hrefs = new Map(places.map(({ place, href }) => [place.id, href]))
50
+ const layer = map.getFeatureLayer(this.boundaryValue)
51
+ layer.style = ({ feature }) => {
52
+ if (hrefs.has(feature.placeId)) return FILLED
45
53
  }
54
+ layer.addListener('click', ({ features }) => {
55
+ const href = features.map(feature => hrefs.get(feature.placeId)).find(Boolean)
56
+ if (href) visit(href)
57
+ })
46
58
 
47
- await Promise.all(places.map(place =>
59
+ await Promise.all(places.map(({ place }) =>
48
60
  fetched(place, 'viewport').then(() => { if (place.viewport) bounds.union(place.viewport) })
49
61
  ))
50
62
  }
@@ -52,8 +64,8 @@ export default class extends Controller {
52
64
  async pin(map, bounds, places) {
53
65
  const drop = await this.dropper(map, bounds)
54
66
 
55
- await Promise.all(places.map(place =>
56
- fetched(place, 'location').then(() => { if (place.location) drop(place.location) })
67
+ await Promise.all(places.map(({ place, href, title }) =>
68
+ fetched(place, 'location').then(() => { if (place.location) drop(place.location, href, title) })
57
69
  ))
58
70
  }
59
71
 
@@ -62,20 +74,29 @@ export default class extends Controller {
62
74
  if (this.pointsValue.length === 0) return
63
75
  const drop = await this.dropper(map, bounds)
64
76
 
65
- for (const [lat, lng] of this.pointsValue) drop({ lat, lng })
77
+ for (const [lat, lng, href, title] of this.pointsValue) drop({ lat, lng }, href, title)
66
78
  }
67
79
 
68
- // One marker at a position, and the bounds widened to hold it.
80
+ // One marker at a position, and the bounds widened to hold it. A marker with somewhere to
81
+ // lead is clickable, names what it leads to on hover, and is followed there when clicked.
69
82
  async dropper(map, bounds) {
70
83
  const { AdvancedMarkerElement } = await google.maps.importLibrary('marker')
71
84
 
72
- return (position) => {
73
- new AdvancedMarkerElement({ map, position })
85
+ return (position, href, title) => {
86
+ const marker = new AdvancedMarkerElement({ map, position, title, gmpClickable: Boolean(href) })
87
+ if (href) marker.addEventListener('gmp-click', () => visit(href))
74
88
  bounds.extend(position)
75
89
  }
76
90
  }
77
91
  }
78
92
 
93
+ // Through Turbo where the page has it, so the table's frame and scroll behave as a click on
94
+ // the row's own link would; a plain navigation otherwise.
95
+ function visit(href) {
96
+ if (window.Turbo) window.Turbo.visit(href)
97
+ else window.location.assign(href)
98
+ }
99
+
79
100
  // A place that cannot be fetched — an ID Google no longer knows — is left off the map
80
101
  // rather than taking the rest of the page's rows with it.
81
102
  function fetched(place, field) {
data/lib/bh/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Bh
2
2
  # Version of the gem, read by the gemspec and by hosts checking compatibility.
3
- VERSION = '6.9.1'
3
+ VERSION = '6.10.0'
4
4
  end