@lblod/ember-rdfa-editor-lblod-plugins 20.0.0 → 21.0.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/CHANGELOG.md +32 -0
- package/addon/components/location-plugin/edit.gts +5 -2
- package/addon/components/location-plugin/insert.gts +99 -50
- package/addon/components/location-plugin/map.gts +246 -68
- package/addon/components/snippet-plugin/nodes/snippet.gts +194 -0
- package/addon/components/snippet-plugin/search-modal.ts +2 -0
- package/addon/components/snippet-plugin/snippet-insert.ts +15 -6
- package/addon/components/snippet-plugin/snippets/snippet-preview.ts +5 -2
- package/addon/components/structure-plugin/_private/structure.gts +23 -1
- package/addon/models/sign.ts +2 -2
- package/addon/plugins/decision-plugin/utils/build-article-structure.ts +8 -3
- package/addon/plugins/location-plugin/node-contents/address.ts +6 -5
- package/addon/plugins/location-plugin/node-contents/area.ts +60 -0
- package/addon/plugins/location-plugin/node-contents/index.ts +13 -7
- package/addon/plugins/location-plugin/node-contents/place.ts +8 -5
- package/addon/plugins/location-plugin/node-contents/point.ts +29 -15
- package/addon/plugins/location-plugin/node.ts +10 -6
- package/addon/plugins/location-plugin/utils/address-helpers.ts +2 -2
- package/addon/plugins/location-plugin/utils/geo-helpers.ts +94 -51
- package/addon/plugins/snippet-plugin/nodes/snippet.ts +86 -0
- package/addon/plugins/standard-template-plugin/index.ts +0 -27
- package/addon/plugins/structure-plugin/node.ts +172 -47
- package/addon/services/roadsign-registry.ts +3 -1
- package/addon/utils/translation.ts +10 -0
- package/app/components/snippet-plugin/nodes/snippet.js +1 -0
- package/app/styles/snippet-plugin.scss +56 -0
- package/declarations/addon/components/location-plugin/insert.d.ts +2 -0
- package/declarations/addon/components/location-plugin/map.d.ts +10 -6
- package/declarations/addon/components/snippet-plugin/nodes/snippet.d.ts +25 -0
- package/declarations/addon/components/snippet-plugin/search-modal.d.ts +2 -0
- package/declarations/addon/components/snippet-plugin/snippet-insert.d.ts +1 -1
- package/declarations/addon/components/snippet-plugin/snippets/snippet-preview.d.ts +1 -1
- package/declarations/addon/components/structure-plugin/_private/structure.d.ts +6 -1
- package/declarations/addon/models/sign.d.ts +2 -2
- package/declarations/addon/plugins/location-plugin/node-contents/area.d.ts +4 -0
- package/declarations/addon/plugins/location-plugin/node-contents/index.d.ts +9 -5
- package/declarations/addon/plugins/location-plugin/node-contents/point.d.ts +3 -3
- package/declarations/addon/plugins/location-plugin/utils/geo-helpers.d.ts +25 -13
- package/declarations/addon/plugins/snippet-plugin/nodes/snippet.d.ts +3 -0
- package/declarations/addon/plugins/standard-template-plugin/index.d.ts +0 -12
- package/declarations/addon/plugins/structure-plugin/node.d.ts +3 -0
- package/declarations/addon/utils/translation.d.ts +5 -1
- package/package.json +3 -1
- package/pnpm-lock.yaml +25 -0
- package/translations/en-US.yaml +16 -0
- package/translations/nl-BE.yaml +17 -0
- package/types/ember-leaflet.d.ts +72 -23
- package/types/tracked-toolbox/index.d.ts +2 -1
- package/addon/plugins/standard-template-plugin/utils/nodes.ts +0 -485
- package/declarations/addon/plugins/standard-template-plugin/utils/nodes.d.ts +0 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @lblod/ember-rdfa-editor-lblod-plugins
|
|
2
2
|
|
|
3
|
+
## 21.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#449](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/449) [`335cb673df926d26a0d421a958c414d334653575`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/335cb673df926d26a0d421a958c414d334653575) Thanks [@elpoelma](https://github.com/elpoelma)! - Drop obsolete decision nodes from `standard-template` plugin
|
|
8
|
+
|
|
9
|
+
### Minor Changes
|
|
10
|
+
|
|
11
|
+
- [#443](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/443) [`9f53a0c5a0e0db0414b0c84aed978d01752ccbf8`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/9f53a0c5a0e0db0414b0c84aed978d01752ccbf8) Thanks [@piemonkey](https://github.com/piemonkey)! - Add ability to specify area locations in the location-plugin
|
|
12
|
+
|
|
13
|
+
- [#445](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/445) [`06fe546cea3d3e7076f3a0ab4549c8de389a43d7`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/06fe546cea3d3e7076f3a0ab4549c8de389a43d7) Thanks [@lagartoverde](https://github.com/lagartoverde)! - Support for repeatable fragments
|
|
14
|
+
|
|
15
|
+
Addition of a custom, interactive `fragment` node and nodeview.
|
|
16
|
+
Using the fragment node interactive buttons, you can replace, add and remove fragments.
|
|
17
|
+
|
|
18
|
+
- [#444](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/444) [`3eea339d0d4bd5bf746d6c8cd9c99cf95e127825`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/3eea339d0d4bd5bf746d6c8cd9c99cf95e127825) Thanks [@elpoelma](https://github.com/elpoelma)! - Addition of a backwards-compatible parsing-rule for decision articles to `structure` node-spec
|
|
19
|
+
|
|
20
|
+
- [#446](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/446) [`f9b4a65a743b214d4f5fa2ba3936fc9fca9fa4c2`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/f9b4a65a743b214d4f5fa2ba3936fc9fca9fa4c2) Thanks [@elpoelma](https://github.com/elpoelma)! - Introduce some modifications to new `structure` node-spec:
|
|
21
|
+
- Drop `structureName` node-attribute. This attribute has been replaced by both the `structureType` and `displayStructureName` attributes.
|
|
22
|
+
- Introduction of a required `structureType` attribute. Examples of `structureType` values are:
|
|
23
|
+
- `article`
|
|
24
|
+
- `title`
|
|
25
|
+
- `chapter`
|
|
26
|
+
- `section`
|
|
27
|
+
- `subsection`
|
|
28
|
+
- `paragraph`
|
|
29
|
+
- Introduction of a `displayStructureName` attribute. This attribute controls whether the internationalizated (based on the document language) version of the structure name is displayed inside the header of the structure. The internationalized structure name is based on the `structureType` value and the entries included in the translation files. `displayStructureName` has a default value of `false`.
|
|
30
|
+
|
|
31
|
+
### Patch Changes
|
|
32
|
+
|
|
33
|
+
- [#447](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/447) [`f06edfdf1681fc2c52e46462cad8faa5d97215c4`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/f06edfdf1681fc2c52e46462cad8faa5d97215c4) Thanks [@elpoelma](https://github.com/elpoelma)! - Ensure `zonality` is set up as optional when fetching traffic signs
|
|
34
|
+
|
|
3
35
|
## 20.0.0
|
|
4
36
|
|
|
5
37
|
### Major Changes
|
|
@@ -349,10 +349,13 @@ export default class LocationPluginEditComponent extends Component<Signature> {
|
|
|
349
349
|
<Group.Radio @value='place'>
|
|
350
350
|
{{t 'location-plugin.types.place'}}
|
|
351
351
|
</Group.Radio>
|
|
352
|
+
<Group.Radio @value='area'>
|
|
353
|
+
{{t 'location-plugin.types.area'}}
|
|
354
|
+
</Group.Radio>
|
|
352
355
|
</AuRadioGroup>
|
|
353
356
|
</fs.content>
|
|
354
357
|
</AuFieldset>
|
|
355
|
-
{{#
|
|
358
|
+
{{#unless (eq @locationType 'address')}}
|
|
356
359
|
<AuFormRow>
|
|
357
360
|
<AuLabel for='place-name'>
|
|
358
361
|
{{t 'location-plugin.search.place-name.label'}}*
|
|
@@ -371,7 +374,7 @@ export default class LocationPluginEditComponent extends Component<Signature> {
|
|
|
371
374
|
<p class='au-u-para-tiny au-u-margin-none'>
|
|
372
375
|
{{t 'location-plugin.search.hint'}}
|
|
373
376
|
</p>
|
|
374
|
-
{{/
|
|
377
|
+
{{/unless}}
|
|
375
378
|
<AuFormRow>
|
|
376
379
|
<AuLabel for='municipality-select'>
|
|
377
380
|
{{t 'location-plugin.search.municipality.label'}}
|
|
@@ -16,11 +16,13 @@ import { ResolvedPNode } from '@lblod/ember-rdfa-editor/utils/_private/types';
|
|
|
16
16
|
|
|
17
17
|
import { Address } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/location-plugin/utils/address-helpers';
|
|
18
18
|
import {
|
|
19
|
+
Area,
|
|
19
20
|
convertWGS84CoordsToLambert,
|
|
20
21
|
GeoPos,
|
|
21
22
|
type GlobalCoordinates,
|
|
22
23
|
Place,
|
|
23
24
|
Point,
|
|
25
|
+
Polygon,
|
|
24
26
|
} from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/location-plugin/utils/geo-helpers';
|
|
25
27
|
import { replaceSelectionWithAddress } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/location-plugin/utils/node-utils';
|
|
26
28
|
import { type LocationPluginConfig } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/location-plugin/node';
|
|
@@ -30,6 +32,23 @@ import LocationMap, { type LocationType } from './map';
|
|
|
30
32
|
|
|
31
33
|
export type CurrentLocation = Address | GlobalCoordinates | undefined;
|
|
32
34
|
|
|
35
|
+
function updateFromNode<T extends Address | Place | Area, R>(
|
|
36
|
+
Class: new (...args: unknown[]) => T,
|
|
37
|
+
extractFunc: (current: T) => R,
|
|
38
|
+
defaultValue?: R,
|
|
39
|
+
) {
|
|
40
|
+
return (component: LocationPluginInsertComponent): R | undefined => {
|
|
41
|
+
const curLocation = component.selectedLocationNode?.value.attrs.value as
|
|
42
|
+
| Address
|
|
43
|
+
| Area
|
|
44
|
+
| Place
|
|
45
|
+
| null;
|
|
46
|
+
return curLocation instanceof Class
|
|
47
|
+
? extractFunc(curLocation)
|
|
48
|
+
: defaultValue;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
33
52
|
interface Signature {
|
|
34
53
|
Args: {
|
|
35
54
|
controller: SayController;
|
|
@@ -46,43 +65,41 @@ export default class LocationPluginInsertComponent extends Component<Signature>
|
|
|
46
65
|
@tracked isLoading = false;
|
|
47
66
|
|
|
48
67
|
@trackedReset({
|
|
49
|
-
memo: '
|
|
50
|
-
update
|
|
51
|
-
const currentLocation = component.selectedLocationNode?.value.attrs
|
|
52
|
-
.value as Address | Place | null;
|
|
53
|
-
return currentLocation instanceof Address ? currentLocation : undefined;
|
|
54
|
-
},
|
|
68
|
+
memo: 'modalOpen',
|
|
69
|
+
update: updateFromNode(Address, (address) => address),
|
|
55
70
|
})
|
|
56
71
|
addressToInsert?: Address;
|
|
57
72
|
|
|
58
73
|
@trackedReset({
|
|
59
|
-
memo: '
|
|
60
|
-
update
|
|
61
|
-
const currentLocation = component.selectedLocationNode?.value.attrs
|
|
62
|
-
.value as Address | Place | null;
|
|
63
|
-
return currentLocation instanceof Place
|
|
64
|
-
? currentLocation.location.location
|
|
65
|
-
: undefined;
|
|
66
|
-
},
|
|
74
|
+
memo: 'modalOpen',
|
|
75
|
+
update: updateFromNode(Place, (place) => place.location.location),
|
|
67
76
|
})
|
|
68
77
|
savedLocation: GeoPos | undefined;
|
|
69
78
|
|
|
70
79
|
@trackedReset({
|
|
71
|
-
memo: '
|
|
80
|
+
memo: 'modalOpen',
|
|
72
81
|
update(component: LocationPluginInsertComponent) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
return (
|
|
83
|
+
updateFromNode(Place, (place) => place.name)(component) ??
|
|
84
|
+
updateFromNode(Area, (area) => area.name, '')(component)
|
|
85
|
+
);
|
|
76
86
|
},
|
|
77
87
|
})
|
|
78
88
|
placeName: string = '';
|
|
79
89
|
|
|
80
90
|
@trackedReset({
|
|
81
|
-
memo: '
|
|
91
|
+
memo: 'modalOpen',
|
|
92
|
+
update: updateFromNode(Area, (area) => area.shape.locations),
|
|
93
|
+
})
|
|
94
|
+
savedArea: GeoPos[] | undefined;
|
|
95
|
+
|
|
96
|
+
@trackedReset({
|
|
97
|
+
memo: 'modalOpen',
|
|
82
98
|
update(component: LocationPluginInsertComponent) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
99
|
+
return (
|
|
100
|
+
updateFromNode(Place, () => 'place')(component) ??
|
|
101
|
+
updateFromNode(Area, () => 'area', 'address')(component)
|
|
102
|
+
);
|
|
86
103
|
},
|
|
87
104
|
})
|
|
88
105
|
locationType: LocationType = 'address';
|
|
@@ -121,14 +138,27 @@ export default class LocationPluginInsertComponent extends Component<Signature>
|
|
|
121
138
|
}
|
|
122
139
|
|
|
123
140
|
get canInsert() {
|
|
141
|
+
// trackedReset only actually resets any values if the values are used somewhere. Since we're
|
|
142
|
+
// not actually rendering anything inside the modal if this.modalOpen is false, we need to use
|
|
143
|
+
// these values somewhere outside of the modal contents block.
|
|
144
|
+
this.addressToInsert;
|
|
145
|
+
this.placeName;
|
|
146
|
+
this.savedLocation;
|
|
147
|
+
this.savedArea;
|
|
148
|
+
this.locationType;
|
|
124
149
|
return !!this.controller.activeEditorView.props.nodeViews?.oslo_location;
|
|
125
150
|
}
|
|
126
151
|
|
|
127
152
|
get disableConfirm() {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
153
|
+
switch (this.locationType) {
|
|
154
|
+
case 'place':
|
|
155
|
+
return (
|
|
156
|
+
!this.selectedLocationNode || !this.placeName || !this.chosenPoint
|
|
157
|
+
);
|
|
158
|
+
case 'address':
|
|
159
|
+
return !this.selectedLocationNode || !this.addressToInsert;
|
|
160
|
+
default:
|
|
161
|
+
return !this.selectedLocationNode || !this.placeName || !this.savedArea;
|
|
132
162
|
}
|
|
133
163
|
}
|
|
134
164
|
|
|
@@ -139,9 +169,8 @@ export default class LocationPluginInsertComponent extends Component<Signature>
|
|
|
139
169
|
|
|
140
170
|
@action
|
|
141
171
|
setChosenPoint(point: GlobalCoordinates) {
|
|
142
|
-
// Since we only use the global coordinates, we don't have to do a conversion to lambert here
|
|
143
172
|
this.chosenPoint = {
|
|
144
|
-
lambert:
|
|
173
|
+
lambert: convertWGS84CoordsToLambert(point),
|
|
145
174
|
global: point,
|
|
146
175
|
};
|
|
147
176
|
}
|
|
@@ -153,6 +182,7 @@ export default class LocationPluginInsertComponent extends Component<Signature>
|
|
|
153
182
|
|
|
154
183
|
@action
|
|
155
184
|
closeModal() {
|
|
185
|
+
this.chosenPoint = undefined;
|
|
156
186
|
this.modalOpen = false;
|
|
157
187
|
}
|
|
158
188
|
|
|
@@ -179,41 +209,58 @@ export default class LocationPluginInsertComponent extends Component<Signature>
|
|
|
179
209
|
this.addressToInsert = address;
|
|
180
210
|
}
|
|
181
211
|
|
|
212
|
+
@action
|
|
213
|
+
setArea(vertices: GlobalCoordinates[]) {
|
|
214
|
+
this.savedArea = vertices.map((vertex) => ({
|
|
215
|
+
global: vertex,
|
|
216
|
+
lambert: convertWGS84CoordsToLambert(vertex),
|
|
217
|
+
}));
|
|
218
|
+
}
|
|
219
|
+
|
|
182
220
|
@action
|
|
183
221
|
confirmLocation() {
|
|
184
222
|
if (this.selectedLocationNode) {
|
|
185
|
-
let toInsert: Address | Place | undefined;
|
|
223
|
+
let toInsert: Address | Place | Area | undefined;
|
|
186
224
|
const { pos } = this.selectedLocationNode;
|
|
187
225
|
if (this.locationType === 'address' && this.addressToInsert) {
|
|
188
226
|
toInsert = this.addressToInsert;
|
|
189
|
-
this.controller.withTransaction((tr) => {
|
|
190
|
-
return tr.setNodeAttribute(pos, 'value', toInsert);
|
|
191
|
-
});
|
|
192
|
-
this.modalOpen = false;
|
|
193
227
|
} else if (
|
|
194
228
|
this.locationType === 'place' &&
|
|
195
229
|
this.chosenPoint?.global &&
|
|
196
230
|
this.placeName
|
|
197
231
|
) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
232
|
+
toInsert = new Place({
|
|
233
|
+
uri: this.nodeContentsUtils.fallbackPlaceUri(),
|
|
234
|
+
name: this.placeName,
|
|
235
|
+
location: new Point({
|
|
236
|
+
uri: this.nodeContentsUtils.fallbackGeometryUri(),
|
|
237
|
+
location: {
|
|
238
|
+
lambert: convertWGS84CoordsToLambert(this.chosenPoint.global),
|
|
239
|
+
global: this.chosenPoint?.global,
|
|
240
|
+
},
|
|
241
|
+
}),
|
|
242
|
+
});
|
|
243
|
+
this.chosenPoint = undefined;
|
|
244
|
+
} else if (
|
|
245
|
+
this.locationType === 'area' &&
|
|
246
|
+
this.savedArea &&
|
|
247
|
+
this.placeName
|
|
248
|
+
) {
|
|
249
|
+
toInsert = new Area({
|
|
250
|
+
uri: this.nodeContentsUtils.fallbackPlaceUri(),
|
|
251
|
+
name: this.placeName,
|
|
252
|
+
shape: new Polygon({
|
|
253
|
+
uri: this.nodeContentsUtils.fallbackGeometryUri(),
|
|
254
|
+
locations: this.savedArea,
|
|
255
|
+
}),
|
|
215
256
|
});
|
|
216
257
|
}
|
|
258
|
+
if (toInsert) {
|
|
259
|
+
this.controller.withTransaction((tr) => {
|
|
260
|
+
return tr.setNodeAttribute(pos, 'value', toInsert);
|
|
261
|
+
});
|
|
262
|
+
this.modalOpen = false;
|
|
263
|
+
}
|
|
217
264
|
}
|
|
218
265
|
}
|
|
219
266
|
|
|
@@ -263,6 +310,8 @@ export default class LocationPluginInsertComponent extends Component<Signature>
|
|
|
263
310
|
@location={{this.chosenPoint}}
|
|
264
311
|
@existingLocation={{this.savedLocation}}
|
|
265
312
|
@setLocation={{this.setChosenPoint}}
|
|
313
|
+
@existingArea={{this.savedArea}}
|
|
314
|
+
@setArea={{this.setArea}}
|
|
266
315
|
/>
|
|
267
316
|
</div>
|
|
268
317
|
</modal.Body>
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import Component from '@glimmer/component';
|
|
2
|
-
import { action } from '@ember/object';
|
|
3
2
|
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { action } from '@ember/object';
|
|
4
|
+
import { fn } from '@ember/helper';
|
|
4
5
|
import and from 'ember-truth-helpers/helpers/and';
|
|
5
6
|
import eq from 'ember-truth-helpers/helpers/eq';
|
|
6
7
|
import t from 'ember-intl/helpers/t';
|
|
7
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
LeafletMap,
|
|
10
|
+
type LeafletMapSig,
|
|
11
|
+
type LeafletMapStart,
|
|
12
|
+
} from 'ember-leaflet';
|
|
13
|
+
import { type LatLngBoundsExpression } from 'leaflet';
|
|
8
14
|
import { type LeafletMouseEvent } from 'leaflet';
|
|
9
|
-
import {
|
|
10
|
-
import { task as trackedTask } from 'ember-resources/util/ember-concurrency';
|
|
11
|
-
import AuLoader from '@appuniversum/ember-appuniversum/components/au-loader';
|
|
15
|
+
import { trackedReset } from 'tracked-toolbox';
|
|
12
16
|
import { Address } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/location-plugin/utils/address-helpers';
|
|
13
17
|
import {
|
|
14
18
|
convertLambertCoordsToWGS84,
|
|
@@ -16,13 +20,23 @@ import {
|
|
|
16
20
|
type GlobalCoordinates,
|
|
17
21
|
} from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/location-plugin/utils/geo-helpers';
|
|
18
22
|
|
|
19
|
-
export type LocationType = 'address' | 'place';
|
|
23
|
+
export type LocationType = 'address' | 'place' | 'area';
|
|
20
24
|
|
|
25
|
+
const MAP_TILE_ATTRIBUTION =
|
|
26
|
+
'© <a target="_blank" href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
|
|
27
|
+
const MAP_TILE_URL = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
|
|
21
28
|
const COORD_SYSTEM_CENTER: GlobalCoordinates = {
|
|
22
29
|
lng: 4.450822554431,
|
|
23
30
|
lat: 50.50526730529,
|
|
24
31
|
};
|
|
32
|
+
const COORD_SYSTEM_START = {
|
|
33
|
+
center: COORD_SYSTEM_CENTER,
|
|
34
|
+
zoom: 7,
|
|
35
|
+
};
|
|
25
36
|
|
|
37
|
+
function isLast(array: unknown[], index: number) {
|
|
38
|
+
return array.length === index + 1;
|
|
39
|
+
}
|
|
26
40
|
function displayLocation(location: GeoPos | undefined) {
|
|
27
41
|
const { lambert } = location ?? {};
|
|
28
42
|
return lambert
|
|
@@ -37,95 +51,259 @@ interface Signature {
|
|
|
37
51
|
location?: GeoPos;
|
|
38
52
|
setLocation: (loc: GlobalCoordinates) => void;
|
|
39
53
|
existingLocation?: GeoPos;
|
|
54
|
+
existingArea?: GeoPos[];
|
|
55
|
+
setArea: (vertices: GlobalCoordinates[]) => void;
|
|
40
56
|
};
|
|
41
57
|
Element: HTMLElement;
|
|
42
58
|
}
|
|
43
59
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
60
|
+
function ensureGlobalCoordinates(geoPos: GeoPos) {
|
|
61
|
+
return geoPos.global || convertLambertCoordsToWGS84(geoPos.lambert);
|
|
62
|
+
}
|
|
63
|
+
function areaLocations(
|
|
64
|
+
locationType: LocationType,
|
|
65
|
+
positions: GeoPos[] | undefined,
|
|
66
|
+
) {
|
|
67
|
+
return locationType === 'area' && positions?.length !== 0
|
|
68
|
+
? positions?.map((pos) => ensureGlobalCoordinates(pos))
|
|
69
|
+
: undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Find the southWest and northEast corners bounding an arbitrary set of points */
|
|
73
|
+
function generateBoundsFromShape(
|
|
74
|
+
areaForBounds: GeoPos[] | undefined,
|
|
75
|
+
): LatLngBoundsExpression | undefined {
|
|
76
|
+
if (areaForBounds && areaForBounds.length !== 0) {
|
|
77
|
+
const southWest = { ...ensureGlobalCoordinates(areaForBounds[0]) };
|
|
78
|
+
const northEast = { ...ensureGlobalCoordinates(areaForBounds[0]) };
|
|
79
|
+
areaForBounds.forEach((pos) => {
|
|
80
|
+
const vertex = ensureGlobalCoordinates(pos);
|
|
81
|
+
if (vertex.lat < southWest.lat) {
|
|
82
|
+
southWest.lat = vertex.lat;
|
|
83
|
+
} else if (vertex.lat > northEast.lat) {
|
|
84
|
+
northEast.lat = vertex.lat;
|
|
85
|
+
}
|
|
86
|
+
if (vertex.lng < southWest.lng) {
|
|
87
|
+
southWest.lng = vertex.lng;
|
|
88
|
+
} else if (vertex.lng > northEast.lng) {
|
|
89
|
+
northEast.lng = vertex.lng;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return [
|
|
93
|
+
[southWest.lat, southWest.lng],
|
|
94
|
+
[northEast.lat, northEast.lng],
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
type MapWrapperSig = {
|
|
101
|
+
Args: Omit<
|
|
102
|
+
LeafletMapSig['Args'],
|
|
103
|
+
'bounds' | 'center' | 'zoom' | 'lat' | 'lng'
|
|
104
|
+
> & {
|
|
105
|
+
mapStart: LeafletMapStart;
|
|
106
|
+
};
|
|
107
|
+
Blocks: LeafletMapSig['Blocks'];
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* LeafletMap doesn't handle undefined being passed for the bounds argument, so we use a wrapper
|
|
112
|
+
* component to make sure only to pass the relevant args
|
|
113
|
+
*/
|
|
114
|
+
class MapWrapper extends Component<MapWrapperSig> {
|
|
115
|
+
get unwrappedBounds() {
|
|
116
|
+
return 'bounds' in this.args.mapStart ? this.args.mapStart.bounds : false;
|
|
117
|
+
}
|
|
118
|
+
get isOrigin() {
|
|
119
|
+
return (
|
|
120
|
+
'center' in this.args.mapStart &&
|
|
121
|
+
this.args.mapStart.center === COORD_SYSTEM_CENTER
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
get unwrappedCenter() {
|
|
125
|
+
return 'center' in this.args.mapStart
|
|
126
|
+
? {
|
|
127
|
+
center: this.args.mapStart.center,
|
|
128
|
+
zoom: this.args.mapStart.zoom,
|
|
129
|
+
}
|
|
130
|
+
: false;
|
|
131
|
+
}
|
|
132
|
+
get unwrappedLatLng() {
|
|
133
|
+
return 'lat' in this.args.mapStart
|
|
134
|
+
? {
|
|
135
|
+
lat: this.args.mapStart.lat,
|
|
136
|
+
lng: this.args.mapStart.lng,
|
|
137
|
+
zoom: this.args.mapStart.zoom,
|
|
138
|
+
}
|
|
139
|
+
: false;
|
|
47
140
|
}
|
|
48
|
-
|
|
141
|
+
<template>
|
|
142
|
+
{{#if this.unwrappedBounds}}
|
|
143
|
+
<LeafletMap
|
|
144
|
+
@bounds={{this.unwrappedBounds}}
|
|
145
|
+
@onClick={{@onClick}}
|
|
146
|
+
as |layers|
|
|
147
|
+
>
|
|
148
|
+
{{yield layers}}
|
|
149
|
+
</LeafletMap>
|
|
150
|
+
{{else if this.isOrigin}}
|
|
151
|
+
{{! If we're at the default center, use hard-coded values to avoid map jumps }}
|
|
152
|
+
<LeafletMap
|
|
153
|
+
@center={{COORD_SYSTEM_CENTER}}
|
|
154
|
+
@zoom={{7}}
|
|
155
|
+
@onClick={{@onClick}}
|
|
156
|
+
as |layers|
|
|
157
|
+
>
|
|
158
|
+
{{yield layers}}
|
|
159
|
+
</LeafletMap>
|
|
160
|
+
{{else if this.unwrappedCenter}}
|
|
161
|
+
<LeafletMap
|
|
162
|
+
@center={{this.unwrappedCenter.center}}
|
|
163
|
+
@zoom={{this.unwrappedCenter.zoom}}
|
|
164
|
+
@onClick={{@onClick}}
|
|
165
|
+
as |layers|
|
|
166
|
+
>
|
|
167
|
+
{{yield layers}}
|
|
168
|
+
</LeafletMap>
|
|
169
|
+
{{else if this.unwrappedLatLng}}
|
|
170
|
+
<LeafletMap
|
|
171
|
+
@lat={{this.unwrappedLatLng.lat}}
|
|
172
|
+
@lng={{this.unwrappedLatLng.lng}}
|
|
173
|
+
@zoom={{this.unwrappedLatLng.zoom}}
|
|
174
|
+
@onClick={{@onClick}}
|
|
175
|
+
as |layers|
|
|
176
|
+
>
|
|
177
|
+
{{yield layers}}
|
|
178
|
+
</LeafletMap>
|
|
179
|
+
{{/if}}
|
|
180
|
+
</template>
|
|
49
181
|
}
|
|
50
182
|
|
|
51
183
|
export default class LocationPluginMapComponent extends Component<Signature> {
|
|
52
|
-
@tracked
|
|
53
|
-
@tracked zoom = 7;
|
|
54
|
-
@tracked existingLocationCoords: GlobalCoordinates | undefined;
|
|
184
|
+
@tracked vertices: GlobalCoordinates[] = [];
|
|
55
185
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
186
|
+
// Use untracked properties as otherwise the map jumps to any area or location we pick
|
|
187
|
+
existingAreaBounds = generateBoundsFromShape(this.args.existingArea);
|
|
188
|
+
existingLocationCoords = this.args.existingLocation
|
|
189
|
+
? ensureGlobalCoordinates(this.args.existingLocation)
|
|
190
|
+
: undefined;
|
|
191
|
+
|
|
192
|
+
@trackedReset({
|
|
193
|
+
memo(component: LocationPluginMapComponent) {
|
|
194
|
+
return (
|
|
195
|
+
component.args.address ||
|
|
196
|
+
component.args.existingLocation ||
|
|
197
|
+
component.existingAreaBounds
|
|
198
|
+
);
|
|
199
|
+
},
|
|
200
|
+
update(component: LocationPluginMapComponent) {
|
|
201
|
+
if (component.args.address) {
|
|
202
|
+
return {
|
|
203
|
+
center: ensureGlobalCoordinates(
|
|
204
|
+
component.args.address.location.location,
|
|
205
|
+
),
|
|
206
|
+
zoom: 18,
|
|
207
|
+
};
|
|
208
|
+
} else if (component.args.existingLocation) {
|
|
209
|
+
return {
|
|
210
|
+
center: ensureGlobalCoordinates(component.args.existingLocation),
|
|
211
|
+
zoom: 18,
|
|
212
|
+
};
|
|
213
|
+
} else if (component.existingAreaBounds) {
|
|
214
|
+
return {
|
|
215
|
+
bounds: component.existingAreaBounds,
|
|
216
|
+
};
|
|
217
|
+
} else {
|
|
218
|
+
return COORD_SYSTEM_START;
|
|
68
219
|
}
|
|
69
|
-
return COORD_SYSTEM_CENTER;
|
|
70
220
|
},
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
this,
|
|
74
|
-
this.addressLatLngLookup,
|
|
75
|
-
() => [this.args.address, this.args.existingLocation],
|
|
76
|
-
);
|
|
221
|
+
})
|
|
222
|
+
mapLocation: LeafletMapStart = COORD_SYSTEM_START;
|
|
77
223
|
|
|
78
|
-
get
|
|
79
|
-
return this.
|
|
224
|
+
get foundAddress() {
|
|
225
|
+
return 'center' in this.mapLocation ? this.mapLocation.center : false;
|
|
80
226
|
}
|
|
81
227
|
|
|
82
228
|
@action
|
|
83
229
|
onMapClick(event: LeafletMouseEvent) {
|
|
84
230
|
if (this.args.locationType === 'place') {
|
|
85
231
|
this.args.setLocation(event.latlng);
|
|
232
|
+
} else if (this.args.locationType === 'area') {
|
|
233
|
+
this.vertices = [...this.vertices, event.latlng];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@action
|
|
238
|
+
onVertexClick(index: number) {
|
|
239
|
+
if (index + 1 === this.vertices.length) {
|
|
240
|
+
// Last vertex, click to remove
|
|
241
|
+
this.vertices = this.vertices.slice(0, -1);
|
|
242
|
+
} else if (index === 0) {
|
|
243
|
+
// First vertex, click to end
|
|
244
|
+
this.args.setArea(this.vertices);
|
|
245
|
+
this.vertices = [];
|
|
86
246
|
}
|
|
87
247
|
}
|
|
88
248
|
|
|
89
249
|
<template>
|
|
90
250
|
<div class='map-wrapper' ...attributes>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
<
|
|
97
|
-
@
|
|
98
|
-
@
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
251
|
+
<MapWrapper
|
|
252
|
+
@mapStart={{this.mapLocation}}
|
|
253
|
+
@onClick={{this.onMapClick}}
|
|
254
|
+
as |layers|
|
|
255
|
+
>
|
|
256
|
+
<layers.tile
|
|
257
|
+
@url={{MAP_TILE_URL}}
|
|
258
|
+
@attribution={{MAP_TILE_ATTRIBUTION}}
|
|
259
|
+
/>
|
|
260
|
+
{{#if (and @address (eq @locationType 'address') this.foundAddress)}}
|
|
261
|
+
<layers.marker @location={{this.foundAddress}} as |marker|>
|
|
262
|
+
<marker.tooltip>
|
|
263
|
+
{{@address.formatted}}
|
|
264
|
+
</marker.tooltip>
|
|
265
|
+
</layers.marker>
|
|
266
|
+
{{/if}}
|
|
267
|
+
{{#if this.existingLocationCoords}}
|
|
268
|
+
<layers.marker
|
|
269
|
+
@opacity={{if @location 0.3 1}}
|
|
270
|
+
@location={{this.existingLocationCoords}}
|
|
271
|
+
as |marker|
|
|
272
|
+
>
|
|
273
|
+
<marker.tooltip>
|
|
274
|
+
{{displayLocation @existingLocation}}
|
|
275
|
+
</marker.tooltip>
|
|
276
|
+
</layers.marker>
|
|
277
|
+
{{/if}}
|
|
278
|
+
{{#if (and @location (eq @locationType 'place'))}}
|
|
279
|
+
<layers.marker @location={{@location.global}} />
|
|
280
|
+
{{/if}}
|
|
281
|
+
{{#if (eq @locationType 'area')}}
|
|
282
|
+
<layers.polyline @locations={{this.vertices}} />
|
|
283
|
+
{{#each this.vertices as |vertex index|}}
|
|
114
284
|
<layers.marker
|
|
115
|
-
@
|
|
116
|
-
@
|
|
285
|
+
@location={{vertex}}
|
|
286
|
+
@onClick={{(fn this.onVertexClick index)}}
|
|
117
287
|
as |marker|
|
|
118
288
|
>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
289
|
+
{{#if (eq index 0)}}
|
|
290
|
+
<marker.tooltip>
|
|
291
|
+
{{t 'location-plugin.map.hint.finish-shape'}}
|
|
292
|
+
</marker.tooltip>
|
|
293
|
+
{{else if (isLast this.vertices index)}}
|
|
294
|
+
<marker.tooltip>
|
|
295
|
+
{{t 'location-plugin.map.hint.delete-point'}}
|
|
296
|
+
</marker.tooltip>
|
|
297
|
+
{{/if}}
|
|
122
298
|
</layers.marker>
|
|
123
|
-
{{/
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
299
|
+
{{/each}}
|
|
300
|
+
{{/if}}
|
|
301
|
+
{{#if (areaLocations @locationType @existingArea)}}
|
|
302
|
+
<layers.polygon
|
|
303
|
+
@locations={{(areaLocations @locationType @existingArea)}}
|
|
304
|
+
/>
|
|
305
|
+
{{/if}}
|
|
306
|
+
</MapWrapper>
|
|
129
307
|
</div>
|
|
130
308
|
</template>
|
|
131
309
|
}
|