fix(weather): preserve filter drag previews across panel refreshes

This commit is contained in:
Mazeyar Moeini Feizabadi committed 2026-10-15 20:52:22 +02:00
1 parent 86b7dc8d3c
commit 8959b5b71a
5 files changed
+37 -4

No files matched your search

+3 -1
View File
@@ -151,7 +151,9 @@
cloud-filter slider: 0% is Full, 100% is the existing brightness key, and cloud-filter slider: 0% is Full, 100% is the existing brightness key, and
intermediate values blend the keyed alpha. The slider commits on release to intermediate values blend the keyed alpha. The slider commits on release to
avoid restaging imagery for every drag event. Filter percentages round-trip in avoid restaging imagery for every drag event. Filter percentages round-trip in
share links; legacy mode codes retain their old endpoint meanings. share links; legacy mode codes retain their old endpoint meanings. Background
panel refreshes preserve the pending drag value until release. Contributed by
[NotProniss](https://github.com/NotProniss) (#1084).
- Flights and Military Flights highlight emergency transponder broadcasts in - Flights and Military Flights highlight emergency transponder broadcasts in
fleet billboards, 3D models and Cockpit contacts. Colors update when a status fleet billboards, 3D models and Cockpit contacts. Colors update when a status
+3 -1
View File
@@ -259,7 +259,9 @@ preserved in Full image mode; both modes use the chosen layer opacity. This
is a display filter, not a cloud mask. The cloud-filter slider is a continuous is a display filter, not a cloud mask. The cloud-filter slider is a continuous
0–100% strength: 0% is Full, 100% is the existing Clouds only key, and 0–100% strength: 0% is Full, 100% is the existing Clouds only key, and
intermediate values blend their alpha. The value commits on slider release to intermediate values blend their alpha. The value commits on slider release to
avoid restaging for every pointer event. Satellite share links carry the filter avoid restaging for every pointer event. Status refreshes retain the uncommitted
drag preview; changed model values or disabled controls supersede it.
Satellite share links carry the filter
strength; legacy `f`/`a` values keep their Clouds only / Full meanings. Soft and strength; legacy `f`/`a` values keep their Clouds only / Full meanings. Soft and
Vivid remain layer-opacity presets (40%/70%); history remains transient and links Vivid remain layer-opacity presets (40%/70%); history remains transient and links
open latest. open latest.
+14 -1
View File
@@ -110,6 +110,7 @@ export function createRailCardBlocks({ container, cardId, onParams }) {
const value = Number(block.rangeInput.value); const value = Number(block.rangeInput.value);
const params = rangeParams(); const params = rangeParams();
if (!params) return; if (!params) return;
if (range.commitOnChange) block.rangeDraft = { range, value };
set( set(
block.rangeValue, block.rangeValue,
'textContent', 'textContent',
@@ -125,6 +126,7 @@ export function createRailCardBlocks({ container, cardId, onParams }) {
const onChange = () => { const onChange = () => {
if (!block.props.range?.commitOnChange) return; if (!block.props.range?.commitOnChange) return;
const params = rangeParams(); const params = rangeParams();
block.rangeDraft = null;
if (params) dispatch(params); if (params) dispatch(params);
}; };
block.rangeInput.addEventListener('input', onInput); block.rangeInput.addEventListener('input', onInput);
@@ -196,11 +198,22 @@ export function createRailCardBlocks({ container, cardId, onParams }) {
syncChipGroup(block.chips, props.chips); syncChipGroup(block.chips, props.chips);
const range = props.range; const range = props.range;
set(block.rangeRow, 'hidden', !range); set(block.rangeRow, 'hidden', !range);
const draft = block.rangeDraft;
if (
draft &&
(!range ||
range.disabled ||
!range.commitOnChange ||
['id', 'param', 'min', 'max', 'step', 'value'].some(
(key) => range[key] !== draft.range[key],
))
)
block.rangeDraft = null;
if (range) { if (range) {
const min = Number(range.min); const min = Number(range.min);
const max = Number(range.max); const max = Number(range.max);
const step = Number(range.step); const step = Number(range.step);
const candidate = Number(range.value); const candidate = Number(block.rangeDraft?.value ?? range.value);
const value = Math.min( const value = Math.min(
max, max,
Math.max(min, Number.isFinite(candidate) ? candidate : min), Math.max(min, Number.isFinite(candidate) ? candidate : min),
+15
View File
@@ -183,11 +183,26 @@ test('setting ranges stay below presets and commit expensive filters on release'
.textContent, .textContent,
'53%', '53%',
); );
view.update([model(100)]);
assert.equal(slider.value, '53', 'a status refresh retains the pending drag');
assert.equal(
slider.getAttribute('aria-valuetext'),
'53%',
'the accessible preview also survives a refresh',
);
slider.dispatchEvent(new Event('change')); slider.dispatchEvent(new Event('change'));
assert.deepEqual(calls.at(-1), ['a', { infrared: 53 }]); assert.deepEqual(calls.at(-1), ['a', { infrared: 53 }]);
view.update([model(53)]); view.update([model(53)]);
assert.equal(slider.value, '53'); assert.equal(slider.value, '53');
assert.equal(f.document.activeElement, slider); assert.equal(f.document.activeElement, slider);
slider.value = '41';
slider.dispatchEvent(new Event('input'));
view.update([model(70)]);
assert.equal(
slider.value,
'70',
'an authoritative value supersedes the draft',
);
view.destroy(); view.destroy();
slider.value = '41'; slider.value = '41';
slider.dispatchEvent(new Event('change')); slider.dispatchEvent(new Event('change'));
+2 -1
View File
@@ -351,7 +351,8 @@ body.recording-mode .gev-wind-inspection-marker {
outline-offset: 3px; outline-offset: 3px;
} }
.rail-card-setting-range-value { .rail-card-setting-range-value {
min-width: 3ch; flex: 0 0 4ch;
white-space: nowrap;
color: var(--text-primary); color: var(--text-primary);
font: 9px var(--font-mono); font: 9px var(--font-mono);
text-align: right; text-align: right;