Drawing toolbar: restore the two-row wrap on phones
The toolbar still did not paint on iPhone in portrait. v17 removed the backdrop-filter from the scrolling strip but kept the horizontal scroll, and that was the wrong half to keep: on iOS a scroll container is the fragile part, with or without a blur. The strip goes back to wrapping onto two rows — the layout that shipped in v8 and worked on these phones for months, before the rail replaced it in v15. That was a mistake of mine: I swapped a device-tested layout for a scrolling one on the strength of desktop testing alone. It now has no overflow, no blur and an opaque background, and pairs `left` with `width` rather than `right`, so there is nothing exotic left for iOS to disagree with. A comment on the block says so, because the scrolling version reads as the tidier solution and someone will be tempted again. Group headings become hairline dividers on the strip rather than disappearing, so the Draw / Edit / Shape / File grouping survives the narrower layout. Building the rail is also wrapped in a fallback now. It is presentation code and must never be able to take the tools down with it: if it throws, our classes are removed and ol-ext's default bar renders instead of nothing at all. The matchMedia listener that would have been the most likely thrower (Safari only gained MediaQueryList.addEventListener in iOS 14) falls back to addListener. Verified: wraps to two rows in a 390px container, single row when wider, no overflow or backdrop-filter in either, and still hides when Draw mode is off. Service Worker v17 -> v18. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d165b57853
commit
7787f77f80
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
dist/assets/index-BM5P5Dc7.js.map
vendored
Normal file
1
dist/assets/index-BM5P5Dc7.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/assets/index-C3r_p8o6.js.map
vendored
1
dist/assets/index-C3r_p8o6.js.map
vendored
File diff suppressed because one or more lines are too long
54
dist/index.html
vendored
54
dist/index.html
vendored
@ -1782,7 +1782,14 @@
|
|||||||
@media (max-width: 576px), (max-height: 560px) {
|
@media (max-width: 576px), (max-height: 560px) {
|
||||||
/* `.ol-left` is repeated here for specificity: ol-ext's own
|
/* `.ol-left` is repeated here for specificity: ol-ext's own
|
||||||
`.ol-control.ol-bar.ol-left` sets top/transform, and without matching
|
`.ol-control.ol-bar.ol-left` sets top/transform, and without matching
|
||||||
it the rail stays vertically centred and stretches to `bottom`. */
|
it the rail stays vertically centred and stretches to `bottom`.
|
||||||
|
|
||||||
|
This layout is deliberately plain. An earlier version scrolled
|
||||||
|
horizontally and blurred its backdrop, and on iOS Safari it did not
|
||||||
|
paint at all — a scroll container that also has backdrop-filter is a
|
||||||
|
known way to lose an element entirely. Wrapping onto two rows needs
|
||||||
|
neither, and it is what shipped before the rail, on the same phones.
|
||||||
|
Nothing here should be made cleverer without testing on a device. */
|
||||||
.ol-control.ol-bar.ol-editbar.ol-editbar-rail.ol-left {
|
.ol-control.ol-bar.ol-editbar.ol-editbar-rail.ol-left {
|
||||||
/* NOTE: display must NOT be !important — ol-ext toggles the bar with an
|
/* NOTE: display must NOT be !important — ol-ext toggles the bar with an
|
||||||
inline display:none/'' (setVisible). An !important here would beat
|
inline display:none/'' (setVisible). An !important here would beat
|
||||||
@ -1790,45 +1797,38 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
grid-template-columns: none;
|
grid-template-columns: none;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: nowrap;
|
justify-content: center;
|
||||||
|
row-gap: 3px;
|
||||||
top: auto;
|
top: auto;
|
||||||
bottom: 12px;
|
bottom: 12px;
|
||||||
left: 8px;
|
left: 8px;
|
||||||
right: 8px;
|
/* width rather than `right`, which is the more conventional pairing
|
||||||
|
with `left` and avoids another layout edge case. */
|
||||||
|
right: auto;
|
||||||
|
width: calc(100% - 16px);
|
||||||
transform: none;
|
transform: none;
|
||||||
/* Horizontal scroll replaces the old two-row wrap. Option bars are
|
overflow: visible;
|
||||||
re-anchored below to open upward, so clipping them is not a concern
|
|
||||||
the way it is on desktop. */
|
|
||||||
overflow-x: auto;
|
|
||||||
overflow-y: hidden;
|
|
||||||
overscroll-behavior-x: contain;
|
|
||||||
scrollbar-width: none;
|
|
||||||
/* No backdrop-filter here. On iOS Safari an element that both blurs its
|
|
||||||
backdrop and scrolls frequently fails to paint at all — which is why
|
|
||||||
this strip was invisible in portrait while the rail, which does not
|
|
||||||
scroll, rendered fine in landscape. An opaque background gives the
|
|
||||||
same legibility without the blur.
|
|
||||||
`-webkit-overflow-scrolling: touch` is deliberately absent too: it is
|
|
||||||
obsolete since iOS 13 and implicated in the same class of bug. */
|
|
||||||
backdrop-filter: none;
|
backdrop-filter: none;
|
||||||
-webkit-backdrop-filter: none;
|
-webkit-backdrop-filter: none;
|
||||||
background: var(--card);
|
background: var(--card);
|
||||||
}
|
}
|
||||||
.ol-control.ol-bar.ol-editbar.ol-editbar-rail.ol-left::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Labels become inline separators between bands rather than headings. */
|
/* Group headings become hairline dividers: the words cost more width than
|
||||||
|
two rows can spare, but the grouping is still worth showing. */
|
||||||
.ol-editbar-rail .ol-rail-label {
|
.ol-editbar-rail .ol-rail-label {
|
||||||
grid-column: auto;
|
grid-column: auto;
|
||||||
padding: 0 6px 0 3px;
|
|
||||||
text-align: left;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex: none;
|
flex: none;
|
||||||
|
width: 1px;
|
||||||
|
height: 24px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 5px;
|
||||||
|
font-size: 0;
|
||||||
|
background: var(--border);
|
||||||
}
|
}
|
||||||
.ol-editbar-rail .ol-rail-label:first-child {
|
.ol-editbar-rail .ol-rail-grip + .ol-rail-label {
|
||||||
padding-left: 0;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ol-editbar-rail > .ol-editbar-actions,
|
.ol-editbar-rail > .ol-editbar-actions,
|
||||||
@ -1887,7 +1887,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script type="module" crossorigin src="/assets/index-C3r_p8o6.js"></script>
|
<script type="module" crossorigin src="/assets/index-BM5P5Dc7.js"></script>
|
||||||
<link rel="modulepreload" crossorigin href="/assets/openlayers-J9qS6Th1.js">
|
<link rel="modulepreload" crossorigin href="/assets/openlayers-J9qS6Th1.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/pako-Xa-UToif.js">
|
<link rel="modulepreload" crossorigin href="/assets/pako-Xa-UToif.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/geotiff-BaoeLn6q.js">
|
<link rel="modulepreload" crossorigin href="/assets/geotiff-BaoeLn6q.js">
|
||||||
|
|||||||
10
dist/sw.js
vendored
10
dist/sw.js
vendored
@ -95,7 +95,15 @@
|
|||||||
// blur. In landscape the phone is 844px wide, so the width-only breakpoint
|
// blur. In landscape the phone is 844px wide, so the width-only breakpoint
|
||||||
// handed it the 396px-tall rail inside a ~270px map; the layout now
|
// handed it the 396px-tall rail inside a ~270px map; the layout now
|
||||||
// switches on height as well as width.
|
// switches on height as well as width.
|
||||||
const CACHE_VERSION = 'v17';
|
// v18: The phone toolbar still did not paint on iPhone. Reverted the strip from
|
||||||
|
// a horizontally scrolling row back to the two-row wrap that shipped
|
||||||
|
// before the rail and was known to work on those phones — removing the
|
||||||
|
// overflow, and with it the whole class of iOS scroll-container paint
|
||||||
|
// bugs, rather than only the backdrop-filter half of it. Group headings
|
||||||
|
// become hairline dividers so the grouping survives the narrower layout.
|
||||||
|
// Building the rail is now also wrapped in a fallback: if it throws, the
|
||||||
|
// default ol-ext bar is shown instead of no bar at all.
|
||||||
|
const CACHE_VERSION = 'v18';
|
||||||
const SHELL_CACHE = `shell-${CACHE_VERSION}`;
|
const SHELL_CACHE = `shell-${CACHE_VERSION}`;
|
||||||
const MODULES_CACHE = `modules-${CACHE_VERSION}`;
|
const MODULES_CACHE = `modules-${CACHE_VERSION}`;
|
||||||
const API_CACHE = `api-${CACHE_VERSION}`;
|
const API_CACHE = `api-${CACHE_VERSION}`;
|
||||||
|
|||||||
52
index.html
52
index.html
@ -1782,7 +1782,14 @@
|
|||||||
@media (max-width: 576px), (max-height: 560px) {
|
@media (max-width: 576px), (max-height: 560px) {
|
||||||
/* `.ol-left` is repeated here for specificity: ol-ext's own
|
/* `.ol-left` is repeated here for specificity: ol-ext's own
|
||||||
`.ol-control.ol-bar.ol-left` sets top/transform, and without matching
|
`.ol-control.ol-bar.ol-left` sets top/transform, and without matching
|
||||||
it the rail stays vertically centred and stretches to `bottom`. */
|
it the rail stays vertically centred and stretches to `bottom`.
|
||||||
|
|
||||||
|
This layout is deliberately plain. An earlier version scrolled
|
||||||
|
horizontally and blurred its backdrop, and on iOS Safari it did not
|
||||||
|
paint at all — a scroll container that also has backdrop-filter is a
|
||||||
|
known way to lose an element entirely. Wrapping onto two rows needs
|
||||||
|
neither, and it is what shipped before the rail, on the same phones.
|
||||||
|
Nothing here should be made cleverer without testing on a device. */
|
||||||
.ol-control.ol-bar.ol-editbar.ol-editbar-rail.ol-left {
|
.ol-control.ol-bar.ol-editbar.ol-editbar-rail.ol-left {
|
||||||
/* NOTE: display must NOT be !important — ol-ext toggles the bar with an
|
/* NOTE: display must NOT be !important — ol-ext toggles the bar with an
|
||||||
inline display:none/'' (setVisible). An !important here would beat
|
inline display:none/'' (setVisible). An !important here would beat
|
||||||
@ -1790,45 +1797,38 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
grid-template-columns: none;
|
grid-template-columns: none;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: nowrap;
|
justify-content: center;
|
||||||
|
row-gap: 3px;
|
||||||
top: auto;
|
top: auto;
|
||||||
bottom: 12px;
|
bottom: 12px;
|
||||||
left: 8px;
|
left: 8px;
|
||||||
right: 8px;
|
/* width rather than `right`, which is the more conventional pairing
|
||||||
|
with `left` and avoids another layout edge case. */
|
||||||
|
right: auto;
|
||||||
|
width: calc(100% - 16px);
|
||||||
transform: none;
|
transform: none;
|
||||||
/* Horizontal scroll replaces the old two-row wrap. Option bars are
|
overflow: visible;
|
||||||
re-anchored below to open upward, so clipping them is not a concern
|
|
||||||
the way it is on desktop. */
|
|
||||||
overflow-x: auto;
|
|
||||||
overflow-y: hidden;
|
|
||||||
overscroll-behavior-x: contain;
|
|
||||||
scrollbar-width: none;
|
|
||||||
/* No backdrop-filter here. On iOS Safari an element that both blurs its
|
|
||||||
backdrop and scrolls frequently fails to paint at all — which is why
|
|
||||||
this strip was invisible in portrait while the rail, which does not
|
|
||||||
scroll, rendered fine in landscape. An opaque background gives the
|
|
||||||
same legibility without the blur.
|
|
||||||
`-webkit-overflow-scrolling: touch` is deliberately absent too: it is
|
|
||||||
obsolete since iOS 13 and implicated in the same class of bug. */
|
|
||||||
backdrop-filter: none;
|
backdrop-filter: none;
|
||||||
-webkit-backdrop-filter: none;
|
-webkit-backdrop-filter: none;
|
||||||
background: var(--card);
|
background: var(--card);
|
||||||
}
|
}
|
||||||
.ol-control.ol-bar.ol-editbar.ol-editbar-rail.ol-left::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Labels become inline separators between bands rather than headings. */
|
/* Group headings become hairline dividers: the words cost more width than
|
||||||
|
two rows can spare, but the grouping is still worth showing. */
|
||||||
.ol-editbar-rail .ol-rail-label {
|
.ol-editbar-rail .ol-rail-label {
|
||||||
grid-column: auto;
|
grid-column: auto;
|
||||||
padding: 0 6px 0 3px;
|
|
||||||
text-align: left;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex: none;
|
flex: none;
|
||||||
|
width: 1px;
|
||||||
|
height: 24px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 5px;
|
||||||
|
font-size: 0;
|
||||||
|
background: var(--border);
|
||||||
}
|
}
|
||||||
.ol-editbar-rail .ol-rail-label:first-child {
|
.ol-editbar-rail .ol-rail-grip + .ol-rail-label {
|
||||||
padding-left: 0;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ol-editbar-rail > .ol-editbar-actions,
|
.ol-editbar-rail > .ol-editbar-actions,
|
||||||
|
|||||||
10
public/sw.js
10
public/sw.js
@ -95,7 +95,15 @@
|
|||||||
// blur. In landscape the phone is 844px wide, so the width-only breakpoint
|
// blur. In landscape the phone is 844px wide, so the width-only breakpoint
|
||||||
// handed it the 396px-tall rail inside a ~270px map; the layout now
|
// handed it the 396px-tall rail inside a ~270px map; the layout now
|
||||||
// switches on height as well as width.
|
// switches on height as well as width.
|
||||||
const CACHE_VERSION = 'v17';
|
// v18: The phone toolbar still did not paint on iPhone. Reverted the strip from
|
||||||
|
// a horizontally scrolling row back to the two-row wrap that shipped
|
||||||
|
// before the rail and was known to work on those phones — removing the
|
||||||
|
// overflow, and with it the whole class of iOS scroll-container paint
|
||||||
|
// bugs, rather than only the backdrop-filter half of it. Group headings
|
||||||
|
// become hairline dividers so the grouping survives the narrower layout.
|
||||||
|
// Building the rail is now also wrapped in a fallback: if it throws, the
|
||||||
|
// default ol-ext bar is shown instead of no bar at all.
|
||||||
|
const CACHE_VERSION = 'v18';
|
||||||
const SHELL_CACHE = `shell-${CACHE_VERSION}`;
|
const SHELL_CACHE = `shell-${CACHE_VERSION}`;
|
||||||
const MODULES_CACHE = `modules-${CACHE_VERSION}`;
|
const MODULES_CACHE = `modules-${CACHE_VERSION}`;
|
||||||
const API_CACHE = `api-${CACHE_VERSION}`;
|
const API_CACHE = `api-${CACHE_VERSION}`;
|
||||||
|
|||||||
@ -1075,7 +1075,20 @@ export class MapView {
|
|||||||
_buildToolbarRail() {
|
_buildToolbarRail() {
|
||||||
const bar = this.editBar?.element;
|
const bar = this.editBar?.element;
|
||||||
if (!bar) return;
|
if (!bar) return;
|
||||||
|
try {
|
||||||
|
this._applyToolbarRail(bar);
|
||||||
|
} catch (err) {
|
||||||
|
// This is presentation only. If it fails the toolbar must still work, so
|
||||||
|
// strip our classes and let ol-ext render its own default bar rather than
|
||||||
|
// leaving a half-styled one — or, worse, aborting initEditBar() and
|
||||||
|
// taking every tool with it.
|
||||||
|
console.warn('[MapView] Could not build the toolbar rail; falling back to the default bar:', err);
|
||||||
|
bar.classList.remove('ol-left', 'ol-editbar-rail');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @private Does the work for _buildToolbarRail(). */
|
||||||
|
_applyToolbarRail(bar) {
|
||||||
// `ol-left` is ol-ext's own left-dock class; `ol-editbar-rail` scopes our CSS.
|
// `ol-left` is ol-ext's own left-dock class; `ol-editbar-rail` scopes our CSS.
|
||||||
bar.classList.add('ol-left', 'ol-editbar-rail');
|
bar.classList.add('ol-left', 'ol-editbar-rail');
|
||||||
|
|
||||||
@ -1221,8 +1234,14 @@ export class MapView {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Crossing the phone breakpoint swaps the layout, so drop or re-apply the
|
// Crossing the phone breakpoint swaps the layout, so drop or re-apply the
|
||||||
// inline position to match.
|
// inline position to match. Safari only gained MediaQueryList.addEventListener
|
||||||
phone.addEventListener('change', restore);
|
// in iOS 14; fall back rather than throw, because an exception here would
|
||||||
|
// abort initEditBar() and take the whole toolbar with it.
|
||||||
|
if (typeof phone.addEventListener === 'function') {
|
||||||
|
phone.addEventListener('change', restore);
|
||||||
|
} else if (typeof phone.addListener === 'function') {
|
||||||
|
phone.addListener(restore);
|
||||||
|
}
|
||||||
restore();
|
restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user