@theseam/ui-common 2.0.1-beta.115 → 2.0.1-beta.119
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/fesm2022/theseam-ui-common-google-maps.mjs +111 -11
- package/fesm2022/theseam-ui-common-google-maps.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-utils.mjs +102 -35
- package/fesm2022/theseam-ui-common-utils.mjs.map +1 -1
- package/google-maps/index.d.ts +55 -3
- package/package.json +1 -1
- package/utils/index.d.ts +12 -1
|
@@ -1138,6 +1138,13 @@ class GoogleMapsService {
|
|
|
1138
1138
|
* an attempt.
|
|
1139
1139
|
*/
|
|
1140
1140
|
deleteBlocked$ = this._deleteBlockedSubject.asObservable();
|
|
1141
|
+
/**
|
|
1142
|
+
* A file reached one of the import paths and could not be read. Plain
|
|
1143
|
+
* `Subject`, not `BehaviorSubject`: a consumer subscribing later should not
|
|
1144
|
+
* be handed a failure from before it was listening.
|
|
1145
|
+
*/
|
|
1146
|
+
_fileImportErrorSubject = new Subject();
|
|
1147
|
+
fileImportError$ = this._fileImportErrorSubject.asObservable();
|
|
1141
1148
|
_selectionSubject = new BehaviorSubject(null);
|
|
1142
1149
|
/**
|
|
1143
1150
|
* `distinctUntilChanged` collapses repeated `null`s. Several paths clear the
|
|
@@ -1193,6 +1200,7 @@ class GoogleMapsService {
|
|
|
1193
1200
|
this._editModeSubject.complete();
|
|
1194
1201
|
this._interactionModeSubject.complete();
|
|
1195
1202
|
this._deleteBlockedSubject.complete();
|
|
1203
|
+
this._fileImportErrorSubject.complete();
|
|
1196
1204
|
this._groups = undefined;
|
|
1197
1205
|
this._labelsOverlay?.destroy();
|
|
1198
1206
|
this._labelsOverlay = undefined;
|
|
@@ -1825,6 +1833,14 @@ class GoogleMapsService {
|
|
|
1825
1833
|
getFileInputHandler() {
|
|
1826
1834
|
return this._fileInputHandler;
|
|
1827
1835
|
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Reports a file the library tried to import and could not read. Called by
|
|
1838
|
+
* the import controls, not by consumers — a consumer that owns importing
|
|
1839
|
+
* through `setFileInputHandler` reports its own failures.
|
|
1840
|
+
*/
|
|
1841
|
+
notifyFileImportError(file, error) {
|
|
1842
|
+
this._fileImportErrorSubject.next({ file, error });
|
|
1843
|
+
}
|
|
1828
1844
|
setInteractionMode(mode) {
|
|
1829
1845
|
this._model =
|
|
1830
1846
|
mode === 'grouped'
|
|
@@ -2708,7 +2724,12 @@ class TheSeamGoogleMapsUploadButtonControlComponent {
|
|
|
2708
2724
|
async _importFile(file) {
|
|
2709
2725
|
const json = await readGeoFile(file);
|
|
2710
2726
|
this._mapValueManager.setValue(json, MapValueSource.Input);
|
|
2711
|
-
|
|
2727
|
+
}
|
|
2728
|
+
_reportImportError(file, error) {
|
|
2729
|
+
if (file === undefined) {
|
|
2730
|
+
return;
|
|
2731
|
+
}
|
|
2732
|
+
this._googleMaps.notifyFileImportError(file, error);
|
|
2712
2733
|
}
|
|
2713
2734
|
_createHiddenInput() {
|
|
2714
2735
|
const fileInputElement = this._renderer.createElement('input');
|
|
@@ -2716,16 +2737,32 @@ class TheSeamGoogleMapsUploadButtonControlComponent {
|
|
|
2716
2737
|
this._renderer.setAttribute(fileInputElement, 'hidden', '');
|
|
2717
2738
|
this._renderer.setAttribute(fileInputElement, 'accept', '.json,.geojson,.shp,.zip');
|
|
2718
2739
|
this._listeners.push(this._renderer.listen(fileInputElement, 'change', (event) => {
|
|
2719
|
-
|
|
2740
|
+
let file;
|
|
2741
|
+
try {
|
|
2742
|
+
file = this._getFile();
|
|
2743
|
+
}
|
|
2744
|
+
catch (err) {
|
|
2745
|
+
// `_getFile` refuses a multi-file selection. Report it like any
|
|
2746
|
+
// other reason the chosen files could not be imported. `_getFile`
|
|
2747
|
+
// has already read `files` by this point, so resetting now cannot
|
|
2748
|
+
// disturb the read.
|
|
2749
|
+
this._reportImportError(this._fileInputElement.files?.[0], err);
|
|
2750
|
+
this._resetInput();
|
|
2751
|
+
return;
|
|
2752
|
+
}
|
|
2720
2753
|
if (file === null) {
|
|
2721
2754
|
return;
|
|
2722
2755
|
}
|
|
2723
2756
|
const fileImportHandler = this._googleMaps.getFileInputHandler();
|
|
2724
2757
|
if (fileImportHandler) {
|
|
2758
|
+
// The consumer owns the file now, including reporting its failures.
|
|
2725
2759
|
fileImportHandler(file);
|
|
2760
|
+
this._resetInput();
|
|
2726
2761
|
}
|
|
2727
2762
|
else {
|
|
2728
|
-
this._importFile(file)
|
|
2763
|
+
this._importFile(file)
|
|
2764
|
+
.catch((err) => this._reportImportError(file, err))
|
|
2765
|
+
.finally(() => this._resetInput());
|
|
2729
2766
|
}
|
|
2730
2767
|
}));
|
|
2731
2768
|
return fileInputElement;
|
|
@@ -2910,16 +2947,55 @@ class TheSeamMapFileDropComponent {
|
|
|
2910
2947
|
event.preventDefault();
|
|
2911
2948
|
event.stopPropagation();
|
|
2912
2949
|
this._renderer.setStyle(this._elementRef.nativeElement, 'display', 'none');
|
|
2913
|
-
|
|
2914
|
-
|
|
2950
|
+
if (!this._isSupportedDataTransferTypes(event.dataTransfer)) {
|
|
2951
|
+
// Not a file drag at all — selected text, a link, an image dragged out
|
|
2952
|
+
// of a page. Nobody asked for an import and there is no file to name,
|
|
2953
|
+
// so this stays silent rather than reporting a failure.
|
|
2954
|
+
return;
|
|
2955
|
+
}
|
|
2956
|
+
const files = event.dataTransfer.files;
|
|
2957
|
+
if (files.length !== 1) {
|
|
2958
|
+
if (files.length > 1) {
|
|
2959
|
+
// Refused before any handler is consulted, exactly as the upload
|
|
2960
|
+
// button's `_getFile` does: `fileImportHandler` takes a single file
|
|
2961
|
+
// and cannot be handed several, so the consumer never sees these and
|
|
2962
|
+
// this output is its only way to learn the drop was rejected. Same
|
|
2963
|
+
// message as the button, so a consumer matching on it needs one
|
|
2964
|
+
// string rather than two.
|
|
2965
|
+
this._ngZone.run(() => this._googleMaps.notifyFileImportError(files[0], Error('Only one file can be imported at a time.')));
|
|
2966
|
+
}
|
|
2915
2967
|
return;
|
|
2916
2968
|
}
|
|
2917
2969
|
const item = event.dataTransfer.items[0];
|
|
2918
2970
|
const file = item.getAsFile();
|
|
2919
|
-
|
|
2971
|
+
if (file === null) {
|
|
2972
|
+
return;
|
|
2973
|
+
}
|
|
2974
|
+
// These listeners are registered outside Angular's zone, so re-enter it
|
|
2975
|
+
// before calling back into anything that expects change detection — the
|
|
2976
|
+
// consumer's handler may well render a message from here.
|
|
2977
|
+
this._ngZone.run(() => this._importDroppedFile(file));
|
|
2978
|
+
};
|
|
2979
|
+
/**
|
|
2980
|
+
* Routes a dropped file the same way the upload button routes a chosen one,
|
|
2981
|
+
* so `fileImportHandler` means "the consumer owns imported files" whichever
|
|
2982
|
+
* way the file arrived.
|
|
2983
|
+
*/
|
|
2984
|
+
_importDroppedFile(file) {
|
|
2985
|
+
const fileImportHandler = this._googleMaps.getFileInputHandler();
|
|
2986
|
+
if (fileImportHandler) {
|
|
2987
|
+
// The consumer owns the file now, including reporting its failures.
|
|
2988
|
+
fileImportHandler(file);
|
|
2989
|
+
return;
|
|
2990
|
+
}
|
|
2991
|
+
readGeoFile(file)
|
|
2992
|
+
.then((json) => {
|
|
2920
2993
|
this._mapValueManager.setValue(json, MapValueSource.Input);
|
|
2994
|
+
})
|
|
2995
|
+
.catch((error) => {
|
|
2996
|
+
this._googleMaps.notifyFileImportError(file, error);
|
|
2921
2997
|
});
|
|
2922
|
-
}
|
|
2998
|
+
}
|
|
2923
2999
|
_handleDragEnterEvent = (event) => {
|
|
2924
3000
|
if (!this._dropAllowed()) {
|
|
2925
3001
|
return;
|
|
@@ -2938,9 +3014,6 @@ class TheSeamMapFileDropComponent {
|
|
|
2938
3014
|
_dropAllowed() {
|
|
2939
3015
|
return !this._globalDragInProgress;
|
|
2940
3016
|
}
|
|
2941
|
-
_isSupportedDataTransfer(dataTransfer) {
|
|
2942
|
-
return dataTransfer.files.length === 1 && dataTransfer.types[0] === 'Files';
|
|
2943
|
-
}
|
|
2944
3017
|
_isSupportedDataTransferTypes(dataTransfer) {
|
|
2945
3018
|
return dataTransfer.types[0] === 'Files';
|
|
2946
3019
|
}
|
|
@@ -3092,6 +3165,17 @@ class TheSeamGoogleMapsComponent extends _TheSeamGoogleMapsMixinBase {
|
|
|
3092
3165
|
streetViewControlEnabled = false;
|
|
3093
3166
|
allowDrawingHoleInPolygon = false;
|
|
3094
3167
|
editingEnabled = true;
|
|
3168
|
+
/**
|
|
3169
|
+
* Intercepts a file the user chose or dropped, in place of the library's own
|
|
3170
|
+
* import handling. Covers **both** import paths: a file picked through the
|
|
3171
|
+
* upload button and one dropped onto the map (`fileDropEnabled` defaults to
|
|
3172
|
+
* `true`, so setting this now also intercepts drops a consumer relying on
|
|
3173
|
+
* the default previously had handled internally).
|
|
3174
|
+
*
|
|
3175
|
+
* Once called, the consumer owns the file, including reporting any failure
|
|
3176
|
+
* in its own UI — `fileImportError` will not fire for a file handed to this
|
|
3177
|
+
* handler.
|
|
3178
|
+
*/
|
|
3095
3179
|
set fileImportHandler(value) {
|
|
3096
3180
|
this._googleMaps.setFileInputHandler(value);
|
|
3097
3181
|
}
|
|
@@ -3161,6 +3245,15 @@ class TheSeamGoogleMapsComponent extends _TheSeamGoogleMapsMixinBase {
|
|
|
3161
3245
|
* so the consumer can explain why; only the consumer knows the reason.
|
|
3162
3246
|
*/
|
|
3163
3247
|
deleteBlocked = new EventEmitter();
|
|
3248
|
+
/**
|
|
3249
|
+
* A file reached one of the import paths and could not be read — a corrupt
|
|
3250
|
+
* archive, a `.zip` of something else, malformed GeoJSON. Emitted so the
|
|
3251
|
+
* consumer can say so in its own UI; the library has nowhere to show it.
|
|
3252
|
+
*
|
|
3253
|
+
* Not emitted for a file a `fileImportHandler` took: once the consumer owns
|
|
3254
|
+
* the file, it owns reporting the outcome too.
|
|
3255
|
+
*/
|
|
3256
|
+
fileImportError = new EventEmitter();
|
|
3164
3257
|
featureContextMenu;
|
|
3165
3258
|
_options = {
|
|
3166
3259
|
mapTypeControl: true,
|
|
@@ -3218,6 +3311,11 @@ class TheSeamGoogleMapsComponent extends _TheSeamGoogleMapsMixinBase {
|
|
|
3218
3311
|
this._googleMaps.deleteBlocked$
|
|
3219
3312
|
.pipe(tap((target) => this.deleteBlocked.emit(target)), takeUntil(this._ngUnsubscribe))
|
|
3220
3313
|
.subscribe();
|
|
3314
|
+
// As with `deleteBlocked$`, a plain Subject with nothing to replay, so no
|
|
3315
|
+
// `skip(1)`.
|
|
3316
|
+
this._googleMaps.fileImportError$
|
|
3317
|
+
.pipe(tap((value) => this.fileImportError.emit(value)), takeUntil(this._ngUnsubscribe))
|
|
3318
|
+
.subscribe();
|
|
3221
3319
|
this._contextMenuItems$ = combineLatest([
|
|
3222
3320
|
this._googleMaps.editingEnabled$,
|
|
3223
3321
|
// The RIGHT-CLICKED feature's group — what "Delete Field" is
|
|
@@ -3472,7 +3570,7 @@ class TheSeamGoogleMapsComponent extends _TheSeamGoogleMapsMixinBase {
|
|
|
3472
3570
|
return this._googleMaps.isEditMode();
|
|
3473
3571
|
}
|
|
3474
3572
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamGoogleMapsComponent, deps: [{ token: i0.ElementRef }, { token: i1.FocusMonitor }, { token: GoogleMapsService }, { token: MapValueManagerService }, { token: TheSeamGoogleMapsApiLoader }], target: i0.ɵɵFactoryTarget.Component });
|
|
3475
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: TheSeamGoogleMapsComponent, isStandalone: false, selector: "seam-google-maps", inputs: { disabled: "disabled", value: "value", tabIndex: "tabIndex", fileDropEnabled: "fileDropEnabled", fileUploadControlEnabled: "fileUploadControlEnabled", fullscreenControlEnabled: "fullscreenControlEnabled", reCenterControlEnabled: "reCenterControlEnabled", mapTypeControlEnabled: "mapTypeControlEnabled", streetViewControlEnabled: "streetViewControlEnabled", allowDrawingHoleInPolygon: "allowDrawingHoleInPolygon", editingEnabled: "editingEnabled", fileImportHandler: "fileImportHandler", zoom: "zoom", longitude: "longitude", latitude: "latitude", padding: "padding", interactionMode: "interactionMode", featureGroupProperty: "featureGroupProperty", featureLabelProperty: "featureLabelProperty", newGroupKeyFactory: "newGroupKeyFactory", selectedGroupKey: "selectedGroupKey", canDelete: "canDelete" }, outputs: { mapReady: "mapReady", selectionChange: "selectionChange", featureHoverChange: "featureHoverChange", deleteBlocked: "deleteBlocked" }, host: { properties: { "attr.disabled": "this._attrDisabled", "attr.tabindex": "this._attrTabIndex" } }, providers: [
|
|
3573
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: TheSeamGoogleMapsComponent, isStandalone: false, selector: "seam-google-maps", inputs: { disabled: "disabled", value: "value", tabIndex: "tabIndex", fileDropEnabled: "fileDropEnabled", fileUploadControlEnabled: "fileUploadControlEnabled", fullscreenControlEnabled: "fullscreenControlEnabled", reCenterControlEnabled: "reCenterControlEnabled", mapTypeControlEnabled: "mapTypeControlEnabled", streetViewControlEnabled: "streetViewControlEnabled", allowDrawingHoleInPolygon: "allowDrawingHoleInPolygon", editingEnabled: "editingEnabled", fileImportHandler: "fileImportHandler", zoom: "zoom", longitude: "longitude", latitude: "latitude", padding: "padding", interactionMode: "interactionMode", featureGroupProperty: "featureGroupProperty", featureLabelProperty: "featureLabelProperty", newGroupKeyFactory: "newGroupKeyFactory", selectedGroupKey: "selectedGroupKey", canDelete: "canDelete" }, outputs: { mapReady: "mapReady", selectionChange: "selectionChange", featureHoverChange: "featureHoverChange", deleteBlocked: "deleteBlocked", fileImportError: "fileImportError" }, host: { properties: { "attr.disabled": "this._attrDisabled", "attr.tabindex": "this._attrTabIndex" } }, providers: [
|
|
3476
3574
|
MapValueManagerService,
|
|
3477
3575
|
GoogleMapsService,
|
|
3478
3576
|
{ provide: MAP_CONTROLS_SERVICE, useClass: GoogleMapsControlsService },
|
|
@@ -3584,6 +3682,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
3584
3682
|
type: Output
|
|
3585
3683
|
}], deleteBlocked: [{
|
|
3586
3684
|
type: Output
|
|
3685
|
+
}], fileImportError: [{
|
|
3686
|
+
type: Output
|
|
3587
3687
|
}], featureContextMenu: [{
|
|
3588
3688
|
type: ViewChild,
|
|
3589
3689
|
args: ['featureContextMenu', { static: true, read: MenuComponent }]
|