import WithRender from "./import.vue" ; import Vue from "vue" ; import { Component , Ref } from "vue-property-decorator" ; import { InjectContext , InjectMapComponents , InjectMapContext } from "../../utils/decorators" ; import { MapComponents , MapContext } from "../leaflet-map/leaflet-map" ; import { showErrorToast } from "../../utils/toasts" ; import { FileResultObject , parseFiles } from "../../utils/files" ; import pluralize from "pluralize" ; import Icon from "../ui/icon/icon" ; import "./import.scss" ; import { SearchResultsLayer } from "facilmap-leaflet" ; import { Util } from "leaflet" ; import FileResults from "../file-results/file-results" ; import { Portal } from "portal-vue" ; import { Context } from "../facilmap/facilmap" ; @ WithRender @ Component ( { components : { Icon , FileResults , Portal } } ) export default class Import extends Vue { @ InjectContext ( ) context ! : Context ; @ InjectMapComponents ( ) mapComponents ! : MapComponents ; @ InjectMapContext ( ) mapContext ! : MapContext ; @ Ref ( ) fileInput ! : HTMLInputElement ; files : Array < FileResultObject & { title : string ; } > = [ ] ; layers ! : SearchResultsLayer [ ] ; created ( ) { this . layers = [ ] ; } mounted ( ) { this . mapContext . $on ( "fm-import-file" , this . handleImportFile ) ; this . mapContext . $on ( "fm-open-selection" , this . handleOpenSelection ) ; this . mapComponents . container . addEventListener ( "dragenter" , this . handleMapDragEnter ) ; this . mapComponents . container . addEventListener ( "dragover" , this . handleMapDragOver ) ; this . mapComponents . container . addEventListener ( "drop" , this . handleMapDrop ) ; } beforeDestroy ( ) { this . mapContext . $off ( "fm-import-file" , this . handleImportFile ) ; this . mapContext . $off ( "fm-open-selection" , this . handleOpenSelection ) ; this . mapComponents . container . removeEventListener ( "dragenter" , this . handleMapDragEnter ) ; this . mapComponents . container . removeEventListener ( "dragover" , this . handleMapDragOver ) ; this . mapComponents . container . removeEventListener ( "drop" , this . handleMapDrop ) ; } get layerIds ( ) : number [ ] { return this . files . map ( ( file , i ) => { return Util . stamp ( this . layers [ i ] ) ; } ) ; } handleImportFile ( ) { this . fileInput . click ( ) ; } handleOpenSelection ( ) { for ( let i = 0 ; i < this . layerIds . length ; i ++ ) { if ( this . mapContext . selection . some ( ( item ) => item . type == "searchResult" && item . layerId == this . layerIds [ i ] ) ) { this . mapContext . $emit ( "fm-search-box-show-tab" , `fm${ this . context . id }-import-tab-${ i }` ) ; break ; } } } handleMapDragEnter ( event ) { event . preventDefault ( ) ; } handleMapDragOver ( event ) { event . preventDefault ( ) ; } handleMapDrop ( event ) { event . preventDefault ( ) ; this . importFiles ( event . dataTransfer ?. files ) ; } async importFiles ( files ) { this . $bvToast . hide ( `fm${ this . context . id }-import-error` ) ; if ( ! files || files . length == 0 ) return ; try { const loadedFiles = await Promise . all ( [ ... files ] . map ( ( file ) => new Promise < string > ( ( resolve , reject ) => { const reader = new FileReader ( ) ; reader . onload = ( ) => { resolve ( reader . result as string ) ; } ; reader . onerror = ( ) => { reject ( reader . error ) ; } ; reader . readAsText ( file ) ; } ) ) ) ; const result = { ... parseFiles ( loadedFiles ) , title : ( files . length == 1 && files [ 0 ] . name ) || pluralize ( "file" , files . length , true ) } ; if ( result . features . length == 0 && result . errors ) showErrorToast ( this , `fm${ this . context . id }-import-error` , "Parsing error" , `The selected ${ pluralize ( "file" , files . length ) } could not be parsed.` ) ; else if ( result . features . length == 0 ) showErrorToast ( this , `fm${ this . context . id }-import-error` , "No geometries" , `The selected ${ pluralize ( "file" , files . length ) } did not contain any geometries.` ) ; else { if ( result . errors ) showErrorToast ( this , `fm${ this . context . id }-import-error` , "Parsing error" , "Some of the selected files could not be parsed." , { variant : "warning" } ) ; const layer = new SearchResultsLayer ( result . features , { pathOptions : { weight : 7 } } ) . addTo ( this . mapComponents . map ) ; this . mapComponents . map . flyToBounds ( layer . getBounds ( ) ) ; this . mapComponents . selectionHandler . addSearchResultLayer ( layer ) ; this . files . push ( result ) ; this . layers . push ( layer ) ; setTimeout ( ( ) => { this . mapContext . $emit ( "fm-search-box-show-tab" , `fm${ this . context . id }-import-tab-${ this . files . length - 1 }` ) ; } , 0 ) ; } } catch ( err ) { showErrorToast ( this , `fm${ this . context . id }-import-error` , "Error reading files" , err ) ; } } close ( idx ) { this . files . splice ( idx , 1 ) ; this . mapComponents . selectionHandler . removeSearchResultLayer ( this . layers [ idx ] ) ; this . layers [ idx ] . remove ( ) ; this . layers . splice ( idx , 1 ) ; } }