@fmidev/smartmet-alert-client 4.4.19 → 4.7.0-alpha.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.
- package/.eslintignore +2 -14
- package/.github/workflows/test.yaml +26 -0
- package/.nvmrc +1 -0
- package/dist/index.html +5 -0
- package/dist/index.js +105 -135
- package/dist/index.mjs +112 -135
- package/dist/locale-en-DCEKDw5G.js +8 -0
- package/dist/locale-fi-DPiOM1rB.js +8 -0
- package/dist/locale-sv-B0FlbgEF.js +8 -0
- package/dist/vendor-Cfkkvdz7.js +21 -0
- package/dist/vue/index.mjs +15245 -0
- package/dist/vue/style.css +1 -0
- package/dist/xml-parser-BiNO9kc-.js +13 -0
- package/package.json +60 -24
- package/src/AlertClientVue.vue +170 -0
- package/src/App.vue +55 -205
- package/src/assets/img/ui/arrow-down.svg +4 -11
- package/src/assets/img/ui/arrow-up.svg +4 -11
- package/src/assets/img/ui/clear.svg +7 -21
- package/src/assets/img/ui/close.svg +4 -15
- package/src/assets/img/ui/toggle-selected.svg +5 -6
- package/src/assets/img/ui/toggle-unselected.svg +5 -6
- package/src/assets/img/warning/cold-weather.svg +3 -6
- package/src/assets/img/warning/flood-level-3.svg +4 -7
- package/src/assets/img/warning/forest-fire-weather.svg +2 -6
- package/src/assets/img/warning/grass-fire-weather.svg +2 -6
- package/src/assets/img/warning/hot-weather.svg +3 -6
- package/src/assets/img/warning/pedestrian-safety.svg +3 -7
- package/src/assets/img/warning/rain.svg +2 -7
- package/src/assets/img/warning/sea-icing.svg +2 -6
- package/src/assets/img/warning/sea-thunder-storm.svg +2 -5
- package/src/assets/img/warning/sea-water-height-high-water.svg +3 -8
- package/src/assets/img/warning/sea-water-height-shallow-water.svg +3 -7
- package/src/assets/img/warning/sea-wave-height.svg +4 -7
- package/src/assets/img/warning/sea-wind-legend.svg +2 -5
- package/src/assets/img/warning/sea-wind.svg +2 -5
- package/src/assets/img/warning/several.svg +2 -5
- package/src/assets/img/warning/thunder-storm.svg +2 -5
- package/src/assets/img/warning/traffic-weather.svg +2 -6
- package/src/assets/img/warning/uv-note.svg +2 -6
- package/src/assets/img/warning/wind.svg +2 -5
- package/src/components/AlertClient.vue +41 -19
- package/src/components/CollapsiblePanel.vue +284 -0
- package/src/components/DayLarge.vue +12 -7
- package/src/components/DaySmall.vue +16 -6
- package/src/components/Days.vue +76 -51
- package/src/components/DescriptionWarning.vue +15 -8
- package/src/components/GrayScaleToggle.vue +11 -6
- package/src/components/Legend.vue +36 -248
- package/src/components/MapLarge.vue +41 -42
- package/src/components/MapSmall.vue +44 -28
- package/src/components/PopupRow.vue +6 -3
- package/src/components/Region.vue +30 -15
- package/src/components/RegionWarning.vue +6 -5
- package/src/components/Regions.vue +50 -19
- package/src/components/Warning.vue +18 -10
- package/src/components/Warnings.vue +36 -21
- package/src/main.js +1 -0
- package/src/mixins/alertClientCore.js +210 -0
- package/src/mixins/config.js +262 -256
- package/src/mixins/utils.js +40 -26
- package/src/plugins/index.js +1 -1
- package/src/scss/_utilities.scss +193 -0
- package/src/scss/constants.scss +2 -1
- package/src/scss/warningImages.scss +8 -3
- package/src/vue.js +41 -0
- package/svgo.config.js +45 -0
- package/tests/README.md +430 -0
- package/tests/fixtures/mockWarningData.js +135 -0
- package/tests/integration/warning-flow.spec.js +452 -0
- package/tests/setup.js +41 -0
- package/tests/unit/components/AlertClient.spec.js +734 -0
- package/tests/unit/components/DayLarge.spec.js +281 -0
- package/tests/unit/components/DaySmall.spec.js +278 -0
- package/tests/unit/components/Days.spec.js +565 -0
- package/tests/unit/components/DescriptionWarning.spec.js +432 -0
- package/tests/unit/components/GrayScaleToggle.spec.js +311 -0
- package/tests/unit/components/Legend.spec.js +223 -0
- package/tests/unit/components/MapLarge.spec.js +276 -0
- package/tests/unit/components/MapSmall.spec.js +226 -0
- package/tests/unit/components/PopupRow.spec.js +261 -0
- package/tests/unit/components/Region.spec.js +430 -0
- package/tests/unit/components/RegionWarning.snapshot.spec.js +73 -0
- package/tests/unit/components/RegionWarning.spec.js +408 -0
- package/tests/unit/components/Regions.spec.js +335 -0
- package/tests/unit/components/Warning.snapshot.spec.js +107 -0
- package/tests/unit/components/Warning.spec.js +472 -0
- package/tests/unit/components/Warnings.spec.js +329 -0
- package/tests/unit/components/__snapshots__/RegionWarning.snapshot.spec.js.snap +21 -0
- package/tests/unit/components/__snapshots__/Warning.snapshot.spec.js.snap +199 -0
- package/tests/unit/mixins/config.spec.js +269 -0
- package/tests/unit/mixins/i18n.spec.js +115 -0
- package/tests/unit/mixins/keycodes.spec.js +37 -0
- package/tests/unit/mixins/utils.spec.js +624 -0
- package/vite.config.js +96 -26
- package/vitest.config.js +40 -0
- package/dist/index.mjs.map +0 -1
- package/dist/index.relative.html +0 -19
- package/dist/index.start.html +0 -20
- package/playwright.config.ts +0 -18
- package/public/index.relative.html +0 -19
- package/public/index.start.html +0 -20
- package/src/mixins/panzoom.js +0 -900
- package/test/snapshot.test.ts +0 -126
- package/vitest.config.ts +0 -6
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<h3>
|
|
3
3
|
<button
|
|
4
|
+
:id="`accordion-${code}`"
|
|
4
5
|
type="button"
|
|
5
6
|
:aria-expanded="open"
|
|
6
7
|
:class="['accordion-trigger', 'focus-ring', open ? '' : 'collapsed']"
|
|
7
8
|
:aria-controls="`accordion-section-${code}`"
|
|
8
|
-
:id="`accordion-${code}`"
|
|
9
9
|
:aria-label="ariaButton"
|
|
10
10
|
@click="onRegionToggle">
|
|
11
11
|
<div class="region-header">
|
|
@@ -21,9 +21,7 @@
|
|
|
21
21
|
</RegionWarning>
|
|
22
22
|
</div>
|
|
23
23
|
</div>
|
|
24
|
-
<div
|
|
25
|
-
block
|
|
26
|
-
:class="['current-warning-toggle', open ? '' : 'collapsed']" />
|
|
24
|
+
<div block :class="['current-warning-toggle', open ? '' : 'collapsed']" />
|
|
27
25
|
</button>
|
|
28
26
|
</h3>
|
|
29
27
|
<div
|
|
@@ -32,17 +30,15 @@
|
|
|
32
30
|
:aria-labelledby="`accordion-${code}`"
|
|
33
31
|
:aria-expanded="open"
|
|
34
32
|
class="accordion-panel"
|
|
35
|
-
:hidden="open ? null : ''"
|
|
36
|
-
>
|
|
33
|
+
:hidden="open ? null : ''">
|
|
37
34
|
<div class="current-description">
|
|
38
35
|
<div class="current-description-table">
|
|
39
36
|
<DescriptionWarning
|
|
40
37
|
v-for="warning in reducedWarnings"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
/>
|
|
38
|
+
:key="warning.identification"
|
|
39
|
+
:input="warning"
|
|
40
|
+
:theme="theme"
|
|
41
|
+
:language="language" />
|
|
46
42
|
</div>
|
|
47
43
|
</div>
|
|
48
44
|
</div>
|
|
@@ -192,6 +188,7 @@ export default {
|
|
|
192
188
|
|
|
193
189
|
button {
|
|
194
190
|
border: none;
|
|
191
|
+
cursor: pointer;
|
|
195
192
|
&:focus:not(:focus-visible) {
|
|
196
193
|
box-shadow: none;
|
|
197
194
|
}
|
|
@@ -366,7 +363,10 @@ h3 {
|
|
|
366
363
|
border-radius: 0;
|
|
367
364
|
}
|
|
368
365
|
|
|
369
|
-
.accordion
|
|
366
|
+
.accordion
|
|
367
|
+
> div:first-child:last-child
|
|
368
|
+
.accordion-trigger.collapsed
|
|
369
|
+
> .region-header {
|
|
370
370
|
border-radius: 0;
|
|
371
371
|
}
|
|
372
372
|
|
|
@@ -398,15 +398,30 @@ h3 {
|
|
|
398
398
|
border-radius: 0;
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
-
.accordion
|
|
401
|
+
.accordion
|
|
402
|
+
> div:last-child
|
|
403
|
+
> div
|
|
404
|
+
> h3
|
|
405
|
+
> button
|
|
406
|
+
> div.current-warning-toggle.collapsed {
|
|
402
407
|
border-radius: 0;
|
|
403
408
|
}
|
|
404
409
|
|
|
405
|
-
.accordion
|
|
410
|
+
.accordion
|
|
411
|
+
> div:first-child:last-child
|
|
412
|
+
> div
|
|
413
|
+
> h3
|
|
414
|
+
> button
|
|
415
|
+
> div.current-warning-toggle {
|
|
406
416
|
border-radius: 0;
|
|
407
417
|
}
|
|
408
418
|
|
|
409
|
-
.accordion
|
|
419
|
+
.accordion
|
|
420
|
+
> div:first-child:last-child
|
|
421
|
+
> div
|
|
422
|
+
> h3
|
|
423
|
+
> button
|
|
424
|
+
> div.current-warning-toggle.collapsed {
|
|
410
425
|
border-radius: 0;
|
|
411
426
|
}
|
|
412
427
|
|
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
'symbol-text',
|
|
19
19
|
`transform-rotate-${invertedRotation}`,
|
|
20
20
|
]"
|
|
21
|
-
|
|
22
|
-
>
|
|
21
|
+
>{{ input.text }}</span>
|
|
23
22
|
</div>
|
|
24
23
|
</template>
|
|
25
24
|
|
|
@@ -45,14 +44,16 @@ export default {
|
|
|
45
44
|
return this.t(`warningLevel${this.input.severity}`)
|
|
46
45
|
},
|
|
47
46
|
warningTypeText() {
|
|
48
|
-
return this.t(this.input.type).toLowerCase()
|
|
47
|
+
return this.t(this.input.type).toLowerCase()
|
|
49
48
|
},
|
|
50
49
|
warningDetails() {
|
|
51
50
|
if (this.input.text == null || this.input.direction == null) {
|
|
52
51
|
return ''
|
|
53
52
|
}
|
|
54
|
-
return ` (${this.input.text} m/s ${this.t(
|
|
55
|
-
|
|
53
|
+
return ` (${this.input.text} m/s ${this.t('fromDirection')} ${
|
|
54
|
+
this.input.direction + 180
|
|
55
|
+
}°)`
|
|
56
|
+
},
|
|
56
57
|
},
|
|
57
58
|
}
|
|
58
59
|
</script>
|
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
<div
|
|
3
|
+
id="region-warnings"
|
|
4
|
+
class="row"
|
|
5
|
+
>
|
|
6
|
+
<div
|
|
7
|
+
v-if="anyLandWarnings"
|
|
8
|
+
class="region-type-container"
|
|
9
|
+
>
|
|
10
|
+
<h3
|
|
11
|
+
id="header-land"
|
|
12
|
+
class="header-region"
|
|
13
|
+
>
|
|
14
|
+
{{ landText }}
|
|
15
|
+
</h3>
|
|
5
16
|
<a
|
|
6
17
|
id="fmi-warnings-region-content"
|
|
7
18
|
:href="fromLandToNextContentHref"
|
|
8
19
|
tabindex="0"
|
|
9
20
|
class="fmi-warnings-to-next-content visually-hidden-focusable focus-ring"
|
|
10
21
|
@click="fromLandToNextContentClicked"
|
|
11
|
-
|
|
22
|
+
>{{ fromLandToNextContentText }}</a>
|
|
23
|
+
<div
|
|
24
|
+
id="accordion-group-land"
|
|
25
|
+
class="accordion"
|
|
12
26
|
>
|
|
13
|
-
|
|
14
|
-
|
|
27
|
+
<div
|
|
28
|
+
v-for="region in regions.land"
|
|
29
|
+
:key="region.key"
|
|
30
|
+
>
|
|
15
31
|
<Region
|
|
16
32
|
v-if="region.warnings.length"
|
|
17
33
|
type="land"
|
|
@@ -20,23 +36,37 @@
|
|
|
20
36
|
:input="region.warnings"
|
|
21
37
|
:warnings="warnings"
|
|
22
38
|
:theme="theme"
|
|
23
|
-
:language="language"
|
|
39
|
+
:language="language"
|
|
40
|
+
/>
|
|
24
41
|
</div>
|
|
25
42
|
</div>
|
|
26
43
|
</div>
|
|
27
44
|
|
|
28
|
-
<div
|
|
29
|
-
|
|
45
|
+
<div
|
|
46
|
+
v-if="anySeaWarnings"
|
|
47
|
+
class="region-type-container"
|
|
48
|
+
>
|
|
49
|
+
<h3
|
|
50
|
+
id="header-sea"
|
|
51
|
+
class="header-region"
|
|
52
|
+
>
|
|
53
|
+
{{ seaText }}
|
|
54
|
+
</h3>
|
|
30
55
|
<a
|
|
31
56
|
:id="fromSeaToNextContentId"
|
|
32
57
|
href="#fmi-warnings-end-of-regions"
|
|
33
58
|
tabindex="0"
|
|
34
59
|
class="fmi-warnings-to-next-content visually-hidden-focusable focus-ring"
|
|
35
60
|
@click="fromSeaToNextContentClicked"
|
|
36
|
-
|
|
61
|
+
>{{ fromSeaToNextContentText }}</a>
|
|
62
|
+
<div
|
|
63
|
+
id="accordion-group-sea"
|
|
64
|
+
class="accordion"
|
|
37
65
|
>
|
|
38
|
-
|
|
39
|
-
|
|
66
|
+
<div
|
|
67
|
+
v-for="region in regions.sea"
|
|
68
|
+
:key="region.key"
|
|
69
|
+
>
|
|
40
70
|
<Region
|
|
41
71
|
v-if="region.warnings.length"
|
|
42
72
|
type="sea"
|
|
@@ -45,7 +75,8 @@
|
|
|
45
75
|
:input="region.warnings"
|
|
46
76
|
:warnings="warnings"
|
|
47
77
|
:theme="theme"
|
|
48
|
-
:language="language"
|
|
78
|
+
:language="language"
|
|
79
|
+
/>
|
|
49
80
|
</div>
|
|
50
81
|
</div>
|
|
51
82
|
</div>
|
|
@@ -83,14 +114,14 @@ export default {
|
|
|
83
114
|
return this.t('regionSea')
|
|
84
115
|
},
|
|
85
116
|
fromLandToNextContentText() {
|
|
86
|
-
return `${this.t('warningsInAreasStart')} ${
|
|
87
|
-
|
|
88
|
-
}. ${this.t('toNextContent')}`
|
|
117
|
+
return `${this.t('warningsInAreasStart')} ${this.t(
|
|
118
|
+
`in${this.regions.land.length}Areas`
|
|
119
|
+
)}. ${this.t('toNextContent')}`
|
|
89
120
|
},
|
|
90
121
|
fromSeaToNextContentText() {
|
|
91
|
-
return `${this.t('warningsInAreasStart')} ${
|
|
92
|
-
|
|
93
|
-
}. ${this.t('toNextContent')}`
|
|
122
|
+
return `${this.t('warningsInAreasStart')} ${this.t(
|
|
123
|
+
`in${this.regions.sea.length}Areas`
|
|
124
|
+
)}. ${this.t('toNextContent')}`
|
|
94
125
|
},
|
|
95
126
|
fromLandToNextContentHref() {
|
|
96
127
|
return this.anySeaWarnings
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="symbol-list-table"
|
|
4
|
+
:class="theme"
|
|
5
|
+
>
|
|
3
6
|
<div class="symbol-list-cell symbol-list-cell-image">
|
|
4
7
|
<div
|
|
5
8
|
:class="`level-${severity} ${typeClass} symbol-list-image-column symbol-list-image warning-image`"
|
|
6
|
-
:aria-label="`${warningLevelText} ${title.toLowerCase()}`"
|
|
7
|
-
|
|
9
|
+
:aria-label="`${warningLevelText} ${title.toLowerCase()}`"
|
|
10
|
+
></div>
|
|
8
11
|
</div>
|
|
9
12
|
<div class="symbol-list-cell symbol-list-cell-text">
|
|
10
13
|
<div class="symbol-list-text-select">
|
|
11
14
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
|
12
|
-
<div
|
|
15
|
+
<div
|
|
16
|
+
class="item-text symbol-list-text"
|
|
17
|
+
v-html="title"
|
|
18
|
+
></div>
|
|
13
19
|
<div class="symbol-list-select-container d-none d-md-table-cell">
|
|
14
20
|
<div
|
|
15
21
|
:id="id"
|
|
@@ -27,11 +33,12 @@
|
|
|
27
33
|
@mousedown="preventEvents"
|
|
28
34
|
@click="toggle"
|
|
29
35
|
@keydown.enter="toggle"
|
|
30
|
-
@keydown.space="toggle"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
</
|
|
36
|
+
@keydown.space="toggle"
|
|
37
|
+
>
|
|
38
|
+
<span>
|
|
39
|
+
{{ toggleText }}
|
|
40
|
+
</span>
|
|
41
|
+
</div>
|
|
35
42
|
</div>
|
|
36
43
|
</div>
|
|
37
44
|
<hr />
|
|
@@ -204,6 +211,7 @@ div.symbol-list-text {
|
|
|
204
211
|
justify-content: center;
|
|
205
212
|
width: 100%;
|
|
206
213
|
height: $symbol-list-select-height;
|
|
214
|
+
cursor: pointer;
|
|
207
215
|
margin: 0;
|
|
208
216
|
background-repeat: no-repeat;
|
|
209
217
|
background-position: center;
|
|
@@ -222,7 +230,7 @@ div.symbol-list-text {
|
|
|
222
230
|
}
|
|
223
231
|
}
|
|
224
232
|
span {
|
|
225
|
-
font-family:
|
|
233
|
+
font-family: 'Noto Sans', sans-serif;
|
|
226
234
|
font-size: $font-size;
|
|
227
235
|
forced-color-adjust: none;
|
|
228
236
|
}
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
id="fmi-warnings-view"
|
|
4
|
+
:class="theme"
|
|
5
|
+
>
|
|
3
6
|
<div
|
|
4
7
|
v-if="input.length > 0"
|
|
5
|
-
:class="['row', 'symbol-list-main-row', 'show-text-row']"
|
|
8
|
+
:class="['row', 'symbol-list-main-row', 'show-text-row']"
|
|
9
|
+
>
|
|
6
10
|
<button
|
|
7
11
|
tabindex="0"
|
|
8
12
|
type="button"
|
|
9
13
|
class="bold-text show-text d-none focus-ring"
|
|
10
14
|
:class="{ 'd-sm-block': hiddenWarnings }"
|
|
11
|
-
@click="showAll"
|
|
15
|
+
@click="showAll"
|
|
16
|
+
>
|
|
12
17
|
{{ showWarningsText }}
|
|
13
18
|
</button>
|
|
14
19
|
</div>
|
|
15
|
-
<div
|
|
20
|
+
<div
|
|
21
|
+
v-if="input.length > 0"
|
|
22
|
+
class="row symbol-list-main-row"
|
|
23
|
+
>
|
|
16
24
|
<hr class="symbol-block-separator" />
|
|
17
25
|
</div>
|
|
18
26
|
<div id="fmi-warnings-list">
|
|
@@ -23,25 +31,28 @@
|
|
|
23
31
|
:hideable="warnings.length > 1"
|
|
24
32
|
:theme="theme"
|
|
25
33
|
:language="language"
|
|
26
|
-
@
|
|
34
|
+
@warning-toggled="onWarningToggled"
|
|
35
|
+
/>
|
|
27
36
|
</div>
|
|
28
37
|
<div class="row symbol-list-main-row">
|
|
29
38
|
<hr
|
|
30
39
|
class="symbol-block-separator legend-separator"
|
|
31
|
-
:class="noWarnings ? 'no-warnings' : ''"
|
|
40
|
+
:class="noWarnings ? 'no-warnings' : ''"
|
|
41
|
+
/>
|
|
32
42
|
</div>
|
|
33
43
|
<div class="row symbol-list-main-row">
|
|
34
44
|
<div class="symbol-list-table">
|
|
35
45
|
<div class="symbol-list-cell symbol-list-cell-image">
|
|
36
46
|
<div
|
|
37
47
|
class="gray several symbol-list-image-column symbol-list-image warning-image"
|
|
38
|
-
aria-labelledby="symbol-list-several-warnings-text"
|
|
39
|
-
|
|
48
|
+
aria-labelledby="symbol-list-several-warnings-text"
|
|
49
|
+
></div>
|
|
40
50
|
</div>
|
|
41
51
|
<div class="symbol-list-cell symbol-list-cell-text">
|
|
42
52
|
<div
|
|
43
53
|
id="symbol-list-several-warnings-text"
|
|
44
|
-
class="item-text symbol-list-text"
|
|
54
|
+
class="item-text symbol-list-text"
|
|
55
|
+
>
|
|
45
56
|
{{ severalWarningsText }}
|
|
46
57
|
</div>
|
|
47
58
|
</div>
|
|
@@ -52,13 +63,14 @@
|
|
|
52
63
|
<div class="symbol-list-cell symbol-list-cell-image">
|
|
53
64
|
<div
|
|
54
65
|
class="level-1 symbol-list-image-column symbol-list-image warning-image"
|
|
55
|
-
aria-labelledby="symbol-list-warning-level-1-text"
|
|
56
|
-
|
|
66
|
+
aria-labelledby="symbol-list-warning-level-1-text"
|
|
67
|
+
></div>
|
|
57
68
|
</div>
|
|
58
69
|
<div class="symbol-list-cell symbol-list-cell-text">
|
|
59
70
|
<div
|
|
60
71
|
id="symbol-list-warning-level-1-text"
|
|
61
|
-
class="item-text symbol-list-text"
|
|
72
|
+
class="item-text symbol-list-text"
|
|
73
|
+
>
|
|
62
74
|
{{ warningLevel1Text }}
|
|
63
75
|
</div>
|
|
64
76
|
</div>
|
|
@@ -69,13 +81,14 @@
|
|
|
69
81
|
<div class="symbol-list-cell symbol-list-cell-image">
|
|
70
82
|
<div
|
|
71
83
|
class="level-2 symbol-list-image-column symbol-list-image warning-image"
|
|
72
|
-
aria-labelledby="symbol-list-warning-level-2-text"
|
|
73
|
-
|
|
84
|
+
aria-labelledby="symbol-list-warning-level-2-text"
|
|
85
|
+
></div>
|
|
74
86
|
</div>
|
|
75
87
|
<div class="symbol-list-cell symbol-list-cell-text">
|
|
76
88
|
<div
|
|
77
89
|
id="symbol-list-warning-level-2-text"
|
|
78
|
-
class="item-text symbol-list-text"
|
|
90
|
+
class="item-text symbol-list-text"
|
|
91
|
+
>
|
|
79
92
|
{{ warningLevel2Text }}
|
|
80
93
|
</div>
|
|
81
94
|
</div>
|
|
@@ -86,13 +99,14 @@
|
|
|
86
99
|
<div class="symbol-list-cell symbol-list-cell-image">
|
|
87
100
|
<div
|
|
88
101
|
class="level-3 symbol-list-image-column symbol-list-image warning-image"
|
|
89
|
-
aria-labelledby="symbol-list-warning-level-3-text"
|
|
90
|
-
|
|
102
|
+
aria-labelledby="symbol-list-warning-level-3-text"
|
|
103
|
+
></div>
|
|
91
104
|
</div>
|
|
92
105
|
<div class="symbol-list-cell symbol-list-cell-text">
|
|
93
106
|
<div
|
|
94
107
|
id="symbol-list-warning-level-3-text"
|
|
95
|
-
class="item-text symbol-list-text"
|
|
108
|
+
class="item-text symbol-list-text"
|
|
109
|
+
>
|
|
96
110
|
{{ warningLevel3Text }}
|
|
97
111
|
</div>
|
|
98
112
|
</div>
|
|
@@ -103,13 +117,14 @@
|
|
|
103
117
|
<div class="symbol-list-cell symbol-list-cell-image">
|
|
104
118
|
<div
|
|
105
119
|
class="level-4 symbol-list-image-column symbol-list-image warning-image"
|
|
106
|
-
aria-labelledby="symbol-list-warning-level-4-text"
|
|
107
|
-
|
|
120
|
+
aria-labelledby="symbol-list-warning-level-4-text"
|
|
121
|
+
></div>
|
|
108
122
|
</div>
|
|
109
123
|
<div class="symbol-list-cell symbol-list-cell-text">
|
|
110
124
|
<div
|
|
111
125
|
id="symbol-list-warning-level-4-text"
|
|
112
|
-
class="item-text symbol-list-text"
|
|
126
|
+
class="item-text symbol-list-text"
|
|
127
|
+
>
|
|
113
128
|
{{ warningLevel4Text }}
|
|
114
129
|
</div>
|
|
115
130
|
<hr class="bottom-separator" />
|
package/src/main.js
CHANGED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core mixin for AlertClient wrapper components.
|
|
3
|
+
* Contains shared logic for both web component (App.vue) and Vue component (AlertClientVue.vue).
|
|
4
|
+
*
|
|
5
|
+
* This mixin provides:
|
|
6
|
+
* - Data state management (loading, warningsData, themeClass, etc.)
|
|
7
|
+
* - Computed properties for API queries
|
|
8
|
+
* - Lifecycle hooks (created, mounted, serverPrefetch)
|
|
9
|
+
* - Methods for fetching warnings and handling events
|
|
10
|
+
*
|
|
11
|
+
* Components using this mixin must provide:
|
|
12
|
+
* - Props with appropriate types (string-only for web components, mixed for Vue)
|
|
13
|
+
* - Normalized computed properties that convert props to correct types
|
|
14
|
+
*/
|
|
15
|
+
import fetch from 'cross-fetch'
|
|
16
|
+
|
|
17
|
+
// Helper to normalize string|boolean to boolean
|
|
18
|
+
export const toBool = (val, defaultVal = true) => {
|
|
19
|
+
if (typeof val === 'boolean') return val
|
|
20
|
+
if (typeof val === 'string') return val.toLowerCase() !== 'false'
|
|
21
|
+
return defaultVal
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Helper to normalize string|number to number
|
|
25
|
+
export const toNum = (val, defaultVal = 0) => {
|
|
26
|
+
if (typeof val === 'number') return val
|
|
27
|
+
if (typeof val === 'string') return Number(val)
|
|
28
|
+
return defaultVal
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default {
|
|
32
|
+
data() {
|
|
33
|
+
return {
|
|
34
|
+
loading: 1,
|
|
35
|
+
updatedAt: null,
|
|
36
|
+
refreshedAt: null,
|
|
37
|
+
themeClass: `${this.theme}-theme`,
|
|
38
|
+
warningsData: null,
|
|
39
|
+
visible: true,
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
computed: {
|
|
43
|
+
// API query type names
|
|
44
|
+
weatherUpdatedType() {
|
|
45
|
+
return 'weather_update_time'
|
|
46
|
+
},
|
|
47
|
+
floodUpdatedType() {
|
|
48
|
+
return 'flood_update_time'
|
|
49
|
+
},
|
|
50
|
+
weatherWarningsType() {
|
|
51
|
+
return 'weather_finland_active_all'
|
|
52
|
+
},
|
|
53
|
+
floodWarningsType() {
|
|
54
|
+
return 'flood_finland_active_all'
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// Query builders
|
|
58
|
+
weatherUpdatedQuery() {
|
|
59
|
+
return this.weatherUpdated || `${this.query}${this.weatherUpdatedType}`
|
|
60
|
+
},
|
|
61
|
+
floodUpdatedQuery() {
|
|
62
|
+
return this.floodUpdated || `${this.query}${this.floodUpdatedType}`
|
|
63
|
+
},
|
|
64
|
+
weatherWarningsQuery() {
|
|
65
|
+
return this.weatherWarnings || `${this.query}${this.weatherWarningsType}`
|
|
66
|
+
},
|
|
67
|
+
floodWarningsQuery() {
|
|
68
|
+
return (
|
|
69
|
+
this.floodWarnings ||
|
|
70
|
+
`${this.query}${this.floodWarningsType}${this.floodFilter}`
|
|
71
|
+
)
|
|
72
|
+
},
|
|
73
|
+
query() {
|
|
74
|
+
return '?service=WFS&version=1.0.0&request=GetFeature&maxFeatures=1000&outputFormat=application%2Fjson&typeName='
|
|
75
|
+
},
|
|
76
|
+
floodSupportedSeverities() {
|
|
77
|
+
return ['moderate', 'severe', 'extreme']
|
|
78
|
+
},
|
|
79
|
+
floodFilter() {
|
|
80
|
+
return `${this.floodSupportedSeverities.reduce(
|
|
81
|
+
(filter, severity, index) =>
|
|
82
|
+
`${filter + (index === 0 ? '' : ',')}%27${severity.toUpperCase()}%27`,
|
|
83
|
+
'&cql_filter=severity%20IN%20('
|
|
84
|
+
)})%20AND%20language=%27${this.capLanguage()}%27`
|
|
85
|
+
},
|
|
86
|
+
capLanguage() {
|
|
87
|
+
return () =>
|
|
88
|
+
({
|
|
89
|
+
fi: 'fi-FI',
|
|
90
|
+
sv: 'sv-SV',
|
|
91
|
+
en: 'en-US',
|
|
92
|
+
})[this.language]
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
// Current time calculation
|
|
96
|
+
currentTime() {
|
|
97
|
+
if (this.refreshedAt) {
|
|
98
|
+
return this.refreshedAt
|
|
99
|
+
}
|
|
100
|
+
if (this.currentDate) {
|
|
101
|
+
const date =
|
|
102
|
+
this.currentDate instanceof Date
|
|
103
|
+
? this.currentDate
|
|
104
|
+
: new Date(this.currentDate)
|
|
105
|
+
return date.getTime()
|
|
106
|
+
}
|
|
107
|
+
return Date.now()
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
created() {
|
|
111
|
+
if (this.warnings) {
|
|
112
|
+
this.warningsData =
|
|
113
|
+
typeof this.warnings === 'string'
|
|
114
|
+
? JSON.parse(this.warnings)
|
|
115
|
+
: this.warnings
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
mounted() {
|
|
119
|
+
const fontScaleNum = toNum(this.fontScale, 1)
|
|
120
|
+
if (fontScaleNum !== 1) {
|
|
121
|
+
let originalFontSize
|
|
122
|
+
if (
|
|
123
|
+
typeof window !== 'undefined' &&
|
|
124
|
+
typeof document !== 'undefined' &&
|
|
125
|
+
document.documentElement &&
|
|
126
|
+
window.getComputedStyle
|
|
127
|
+
) {
|
|
128
|
+
const htmlElement = document.documentElement
|
|
129
|
+
const computedStyle = window.getComputedStyle(htmlElement)
|
|
130
|
+
originalFontSize = parseFloat(computedStyle.fontSize)
|
|
131
|
+
}
|
|
132
|
+
if (originalFontSize == null || Number.isNaN(originalFontSize)) {
|
|
133
|
+
originalFontSize = 16 // Fallback
|
|
134
|
+
}
|
|
135
|
+
const scaledFontSize = fontScaleNum * originalFontSize
|
|
136
|
+
const newFontSize = Math.round(scaledFontSize * 100) / 100
|
|
137
|
+
document.documentElement.style.fontSize = `${newFontSize}px`
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
serverPrefetch() {
|
|
141
|
+
if (!this.warnings) {
|
|
142
|
+
return this.fetchWarnings()
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
methods: {
|
|
146
|
+
onLoaded(loaded) {
|
|
147
|
+
if (loaded !== 0) {
|
|
148
|
+
this.loading = loaded === -1 ? -1 : 0
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
onThemeChanged(newTheme) {
|
|
152
|
+
this.themeClass = `${
|
|
153
|
+
newTheme != null && newTheme.length > 0 ? newTheme : this.theme
|
|
154
|
+
}-theme`
|
|
155
|
+
},
|
|
156
|
+
fetchWarnings() {
|
|
157
|
+
if (this.warnings) {
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
this.loading = 1
|
|
161
|
+
// debugModeNormalized is provided by the component using this mixin
|
|
162
|
+
if (this.debugModeNormalized) {
|
|
163
|
+
console.log(`Updating warnings at ${new Date()}`)
|
|
164
|
+
}
|
|
165
|
+
const queries = new Map()
|
|
166
|
+
.set(
|
|
167
|
+
`${this.baseUrl}${this.weatherUpdatedQuery}`,
|
|
168
|
+
this.weatherUpdatedType
|
|
169
|
+
)
|
|
170
|
+
.set(`${this.baseUrl}${this.floodUpdatedQuery}`, this.floodUpdatedType)
|
|
171
|
+
.set(
|
|
172
|
+
`${this.baseUrl}${this.weatherWarningsQuery}`,
|
|
173
|
+
this.weatherWarningsType
|
|
174
|
+
)
|
|
175
|
+
.set(
|
|
176
|
+
`${this.baseUrl}${this.floodWarningsQuery}`,
|
|
177
|
+
this.floodWarningsType
|
|
178
|
+
)
|
|
179
|
+
const responseData = {}
|
|
180
|
+
return Promise.allSettled(
|
|
181
|
+
[...queries.keys()].map(async (query) =>
|
|
182
|
+
fetch(query).then((response) =>
|
|
183
|
+
response
|
|
184
|
+
.json()
|
|
185
|
+
.then((json) => {
|
|
186
|
+
const currentTime = Date.now()
|
|
187
|
+
if (this.updatedAt != null) {
|
|
188
|
+
this.refreshedAt = currentTime
|
|
189
|
+
}
|
|
190
|
+
this.updatedAt = currentTime
|
|
191
|
+
responseData[queries.get(query)] = json
|
|
192
|
+
})
|
|
193
|
+
.catch((error) => {
|
|
194
|
+
this.loading = -1
|
|
195
|
+
console.log(error)
|
|
196
|
+
})
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
).then(() => {
|
|
200
|
+
this.warningsData = responseData
|
|
201
|
+
})
|
|
202
|
+
},
|
|
203
|
+
show() {
|
|
204
|
+
this.visible = true
|
|
205
|
+
},
|
|
206
|
+
hide() {
|
|
207
|
+
this.visible = false
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
}
|