2020-06-24 00:35:19 +02:00
import { OsmConnection } from "./Logic/OsmConnection" ;
import { Changes } from "./Logic/Changes" ;
import { ElementStorage } from "./Logic/ElementStorage" ;
import { UIEventSource } from "./UI/UIEventSource" ;
import { UserBadge } from "./UI/UserBadge" ;
import { Basemap } from "./Logic/Basemap" ;
import { PendingChanges } from "./UI/PendingChanges" ;
import { CenterMessageBox } from "./UI/CenterMessageBox" ;
import { Helpers } from "./Helpers" ;
2020-06-29 03:12:44 +02:00
import { Tag , TagUtils } from "./Logic/TagsFilter" ;
2020-06-24 00:35:19 +02:00
import { FilteredLayer } from "./Logic/FilteredLayer" ;
import { LayerUpdater } from "./Logic/LayerUpdater" ;
2020-06-27 03:06:51 +02:00
import { UIElement } from "./UI/UIElement" ;
import { MessageBoxHandler } from "./UI/MessageBoxHandler" ;
import { Overpass } from "./Logic/Overpass" ;
import { FeatureInfoBox } from "./UI/FeatureInfoBox" ;
2020-06-28 02:42:22 +02:00
import { GeoLocationHandler } from "./Logic/GeoLocationHandler" ;
2020-06-29 03:12:44 +02:00
import { StrayClickHandler } from "./Logic/StrayClickHandler" ;
import { SimpleAddUI } from "./UI/SimpleAddUI" ;
import { VariableUiElement } from "./UI/Base/VariableUIElement" ;
2020-07-01 02:12:33 +02:00
import { SearchAndGo } from "./UI/SearchAndGo" ;
2020-07-01 21:21:29 +02:00
import { CollapseButton } from "./UI/Base/CollapseButton" ;
2020-07-05 18:59:47 +02:00
import { AllKnownLayouts } from "./Customizations/AllKnownLayouts" ;
2020-07-13 16:18:04 +02:00
import { All } from "./Customizations/Layouts/All" ;
2020-07-20 12:39:43 +02:00
import Translations from "./UI/i18n/Translations" ;
import Translation from "./UI/i18n/Translation" ;
import Locale from "./UI/i18n/Locale" ;
2020-07-21 00:07:04 +02:00
import { Layout } from "./Customizations/Layout" ;
import { DropDown } from "./UI/Input/DropDown" ;
import { FixedInputElement } from "./UI/Input/FixedInputElement" ;
import { FixedUiElement } from "./UI/Base/FixedUiElement" ;
2020-06-24 00:35:19 +02:00
2020-07-11 11:50:03 +02:00
// --------------------- Read the URL parameters -----------------
2020-07-12 23:19:05 +02:00
// @ts-ignore
2020-07-15 14:03:44 +02:00
if ( location . href . startsWith ( "http://buurtnatuur.be" ) ) {
2020-07-11 11:50:03 +02:00
// Reload the https version. This is important for the 'locate me' button
2020-07-15 14:03:44 +02:00
window . location . replace ( "https://buurtnatuur.be" ) ;
2020-07-11 11:50:03 +02:00
}
2020-06-25 03:39:31 +02:00
let dryRun = false ;
2020-06-24 00:35:19 +02:00
2020-06-25 03:39:31 +02:00
if ( location . hostname === "localhost" || location . hostname === "127.0.0.1" ) {
// Set to true if testing and changes should NOT be saved
2020-07-15 14:03:44 +02:00
dryRun = true ;
2020-06-25 03:39:31 +02:00
// If you have a testfile somewhere, enable this to spoof overpass
// This should be hosted independantly, e.g. with `cd assets; webfsd -p 8080` + a CORS plugin to disable cors rules
2020-07-17 18:57:07 +02:00
//Overpass.testUrl = "http://127.0.0.1:8080/streetwidths.geojson";
2020-06-25 03:39:31 +02:00
}
2020-06-24 00:35:19 +02:00
// ----------------- SELECT THE RIGHT QUESTSET -----------------
2020-06-27 03:06:51 +02:00
2020-07-15 13:15:36 +02:00
let defaultLayout = "buurtnatuur"
2020-07-13 16:18:04 +02:00
2020-07-15 13:15:36 +02:00
// Run over all questsets. If a part of the URL matches a searched-for part in the layout, it'll take that as the default
2020-07-13 16:18:04 +02:00
for ( const k in AllKnownLayouts . allSets ) {
const layout = AllKnownLayouts . allSets [ k ] ;
const possibleParts = layout . locationContains ? ? [ ] ;
for ( const locationMatch of possibleParts ) {
2020-07-15 13:15:36 +02:00
if ( locationMatch === "" ) {
2020-07-13 16:18:04 +02:00
continue
}
2020-07-15 13:15:36 +02:00
if ( window . location . href . toLowerCase ( ) . indexOf ( locationMatch . toLowerCase ( ) ) >= 0 ) {
defaultLayout = layout . name ;
2020-07-13 16:18:04 +02:00
}
}
}
2020-07-15 13:15:36 +02:00
// Read the query string to grap settings
let paramDict : any = { } ;
2020-06-24 00:35:19 +02:00
if ( window . location . search ) {
const params = window . location . search . substr ( 1 ) . split ( "&" ) ;
for ( const param of params ) {
var kv = param . split ( "=" ) ;
paramDict [ kv [ 0 ] ] = kv [ 1 ] ;
}
}
2020-07-05 18:59:47 +02:00
2020-07-15 13:15:36 +02:00
if ( paramDict . layout ) {
2020-07-16 09:25:20 +02:00
defaultLayout = paramDict . layout
2020-07-15 13:15:36 +02:00
}
if ( paramDict . test ) {
2020-07-17 18:57:07 +02:00
dryRun = paramDict . test === "true" ;
2020-07-15 13:15:36 +02:00
}
2020-07-05 18:59:47 +02:00
2020-07-20 12:39:43 +02:00
const layoutToUse : Layout = AllKnownLayouts . allSets [ defaultLayout ] ;
2020-07-15 13:15:36 +02:00
console . log ( "Using layout: " , layoutToUse . name ) ;
2020-07-21 00:07:04 +02:00
document . title = layoutToUse . title . InnerRender ( ) ;
2020-07-20 12:39:43 +02:00
Locale . language . addCallback ( e = > {
2020-07-21 00:07:04 +02:00
document . title = layoutToUse . title . InnerRender ( ) ;
2020-07-20 12:39:43 +02:00
} )
2020-06-24 00:35:19 +02:00
// ----------------- Setup a few event sources -------------
2020-07-21 00:07:04 +02:00
// const LanguageSelect = document.getElementById('language-select') as HTMLOptionElement
// eLanguageSelect.addEventListener('selectionchange')
2020-06-24 00:35:19 +02:00
// The message that should be shown at the center of the screen
const centerMessage = new UIEventSource < string > ( "" ) ;
// The countdown: if set to e.g. ten, it'll start counting down. When reaching zero, changes will be saved. NB: this is implemented later, not in the eventSource
const secondsTillChangesAreSaved = new UIEventSource < number > ( 0 ) ;
2020-07-21 00:07:04 +02:00
// const leftMessage = new UIEventSource<() => UIElement>(undefined);
// This message is shown full screen on mobile devices
const fullScreenMessage = new UIEventSource < UIElement > ( undefined ) ;
2020-06-27 03:06:51 +02:00
const selectedElement = new UIEventSource < any > ( undefined ) ;
2020-06-29 03:12:44 +02:00
const locationControl = new UIEventSource < { lat : number , lon : number , zoom : number } > ( {
2020-07-15 13:15:36 +02:00
zoom : layoutToUse.startzoom ,
lat : layoutToUse.startLat ,
lon : layoutToUse.startLon
2020-06-24 00:35:19 +02:00
} ) ;
// ----------------- Prepare the important objects -----------------
2020-07-21 00:07:04 +02:00
const osmConnection = new OsmConnection ( dryRun ) ;
Locale . language . syncWith ( osmConnection . GetPreference ( "language" ) ) ;
window . setLanguage = function ( language : string ) {
Locale . language . setData ( language )
}
2020-07-05 18:59:47 +02:00
const saveTimeout = 30000 ; // After this many milliseconds without changes, saves are sent of to OSM
2020-06-24 00:35:19 +02:00
const allElements = new ElementStorage ( ) ;
2020-06-27 03:06:51 +02:00
const changes = new Changes (
2020-07-15 13:15:36 +02:00
"Beantwoorden van vragen met #MapComplete voor vragenset #" + layoutToUse . name ,
2020-07-05 18:59:47 +02:00
osmConnection , allElements ) ;
2020-06-29 03:12:44 +02:00
const bm = new Basemap ( "leafletDiv" , locationControl , new VariableUiElement (
locationControl . map ( ( location ) = > {
const mapComplete = "<a href='https://github.com/pietervdvn/MapComplete' target='_blank'>Mapcomple</a> " +
" " +
"<a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'><img src='./assets/bug.svg' alt='Report bug' class='small-userbadge-icon'></a>" ;
let editHere = "" ;
if ( location !== undefined ) {
editHere = " | " +
"<a href='https://www.openstreetmap.org/edit?editor=id#map=" + location . zoom + "/" + location . lat + "/" + location . lon + "' target='_blank'>" +
"<img src='./assets/pencil.svg' alt='edit here' class='small-userbadge-icon'>" +
"</a>"
}
return mapComplete + editHere ;
} )
) ) ;
2020-06-24 00:35:19 +02:00
// ------------- Setup the layers -------------------------------
2020-07-15 15:55:08 +02:00
const controls = { } ;
2020-06-24 00:35:19 +02:00
const addButtons : {
name : string ,
icon : string ,
tags : Tag [ ] ,
layerToAddTo : FilteredLayer
} [ ]
= [ ] ;
const flayers : FilteredLayer [ ] = [ ]
2020-07-01 21:21:29 +02:00
let minZoom = 0 ;
2020-07-15 13:15:36 +02:00
for ( const layer of layoutToUse . layers ) {
2020-06-24 00:35:19 +02:00
2020-07-01 16:32:17 +02:00
const generateInfo = ( tagsES ) = > {
return new FeatureInfoBox (
tagsES ,
2020-07-05 18:59:47 +02:00
layer . title ,
2020-07-01 16:32:17 +02:00
layer . elementsToShow ,
changes ,
2020-07-14 20:18:44 +02:00
osmConnection . userDetails
2020-07-01 16:32:17 +02:00
)
} ;
2020-07-01 21:21:29 +02:00
minZoom = Math . max ( minZoom , layer . minzoom ) ;
2020-07-15 13:15:36 +02:00
const flayer = layer . asLayer ( bm , allElements , changes , osmConnection . userDetails , selectedElement , generateInfo ) ;
2020-06-24 00:35:19 +02:00
2020-07-15 15:55:08 +02:00
controls [ layer . name ] = flayer . isDisplayed ;
2020-06-24 00:35:19 +02:00
const addButton = {
name : layer.name ,
icon : layer.icon ,
tags : layer.newElementTags ,
layerToAddTo : flayer
}
addButtons . push ( addButton ) ;
flayers . push ( flayer ) ;
}
2020-07-01 21:21:29 +02:00
const layerUpdater = new LayerUpdater ( bm , minZoom , flayers ) ;
2020-06-24 00:35:19 +02:00
// ------------------ Setup various UI elements ------------
2020-07-21 00:07:04 +02:00
let languagePicker = new DropDown ( " " , layoutToUse . supportedLanguages . map ( lang = > {
return { value : lang , shown : lang }
}
) , Locale . language ) . AttachTo ( "language-select" ) ;
2020-06-29 03:12:44 +02:00
2020-07-21 00:07:04 +02:00
new StrayClickHandler ( bm , selectedElement , fullScreenMessage , ( ) = > {
2020-06-29 03:12:44 +02:00
return new SimpleAddUI ( bm . Location ,
bm . LastClickLocation ,
changes ,
selectedElement ,
2020-06-29 03:40:19 +02:00
layerUpdater . runningQuery ,
2020-06-29 16:21:36 +02:00
osmConnection . userDetails ,
2020-06-29 03:12:44 +02:00
addButtons ) ;
}
) ;
2020-06-27 03:06:51 +02:00
/ * *
2020-07-21 00:07:04 +02:00
* Show the questions and information for the selected element on the fullScreen
2020-06-27 03:06:51 +02:00
* /
selectedElement . addCallback ( ( data ) = > {
2020-06-29 03:12:44 +02:00
// Which is the applicable set?
2020-07-15 13:15:36 +02:00
for ( const layer of layoutToUse . layers ) {
2020-06-29 03:12:44 +02:00
const applicable = layer . overpassFilter . matches ( TagUtils . proprtiesToKV ( data ) ) ;
if ( applicable ) {
// This layer is the layer that gives the questions
2020-07-21 00:07:04 +02:00
const featureBox = new FeatureInfoBox (
allElements . getElement ( data . id ) ,
layer . title ,
layer . elementsToShow ,
changes ,
osmConnection . userDetails
) ;
fullScreenMessage . setData ( featureBox ) ;
2020-06-29 03:12:44 +02:00
break ;
2020-06-27 03:06:51 +02:00
}
2020-06-29 03:12:44 +02:00
}
2020-06-27 03:06:51 +02:00
}
) ;
2020-06-24 00:35:19 +02:00
2020-06-29 03:12:44 +02:00
2020-06-27 03:06:51 +02:00
const pendingChanges = new PendingChanges (
2020-07-19 00:13:45 +02:00
changes , secondsTillChangesAreSaved , ) ;
2020-06-24 00:35:19 +02:00
2020-07-21 00:07:04 +02:00
new UserBadge ( osmConnection . userDetails ,
pendingChanges ,
new FixedUiElement ( "" ) ,
bm )
2020-06-24 00:35:19 +02:00
. AttachTo ( 'userbadge' ) ;
2020-07-01 02:12:33 +02:00
new SearchAndGo ( bm ) . AttachTo ( "searchbox" ) ;
2020-07-01 21:21:29 +02:00
new CollapseButton ( "messagesbox" )
. AttachTo ( "collapseButton" ) ;
2020-07-05 18:59:47 +02:00
2020-07-21 00:07:04 +02:00
var generateWelcomeMessage = ( ) = > {
2020-06-27 03:06:51 +02:00
return new VariableUiElement (
osmConnection . userDetails . map ( ( userdetails ) = > {
2020-07-15 13:15:36 +02:00
var login = layoutToUse . gettingStartedPlzLogin ;
2020-06-27 03:06:51 +02:00
if ( userdetails . loggedIn ) {
2020-07-15 13:15:36 +02:00
login = layoutToUse . welcomeBackMessage ;
2020-06-27 03:06:51 +02:00
}
return "<div id='welcomeMessage'>" +
2020-07-20 12:39:43 +02:00
layoutToUse . welcomeMessage . Render ( ) + login + layoutToUse . welcomeTail +
2020-06-27 03:06:51 +02:00
"</div>" ;
} ) ,
2020-06-29 03:12:44 +02:00
function ( ) {
2020-06-27 03:06:51 +02:00
osmConnection . registerActivateOsmAUthenticationClass ( )
} ) ;
}
2020-07-21 00:07:04 +02:00
generateWelcomeMessage ( ) . AttachTo ( "messagesbox" ) ;
fullScreenMessage . setData ( generateWelcomeMessage ( ) ) ;
2020-06-24 00:35:19 +02:00
2020-07-21 00:07:04 +02:00
var messageBox = new MessageBoxHandler ( fullScreenMessage , ( ) = > {
2020-07-16 14:56:19 +02:00
selectedElement . setData ( undefined )
} ) ;
2020-06-24 00:35:19 +02:00
new CenterMessageBox (
2020-07-01 21:21:29 +02:00
minZoom ,
2020-06-24 00:35:19 +02:00
centerMessage ,
osmConnection ,
locationControl ,
layerUpdater . runningQuery )
. AttachTo ( "centermessage" ) ;
2020-06-27 03:06:51 +02:00
Helpers . SetupAutoSave ( changes , secondsTillChangesAreSaved , saveTimeout ) ;
2020-06-24 00:35:19 +02:00
Helpers . LastEffortSave ( changes ) ;
2020-06-27 03:06:51 +02:00
osmConnection . registerActivateOsmAUthenticationClass ( ) ;
2020-06-24 00:35:19 +02:00
2020-06-28 02:42:22 +02:00
new GeoLocationHandler ( bm ) . AttachTo ( "geolocate-button" ) ;
2020-06-24 00:35:19 +02:00
// --------------- Send a ping to start various action --------
locationControl . ping ( ) ;
2020-06-27 03:06:51 +02:00
messageBox . update ( ) ;
2020-07-20 12:39:43 +02:00