forked from MapComplete/MapComplete
		
	More refactoring, stabilizing rotation and direction_gradient
This commit is contained in:
		
							parent
							
								
									5fec108ba2
								
							
						
					
					
						commit
						778044d0fb
					
				
					 45 changed files with 656 additions and 640 deletions
				
			
		|  | @ -5,7 +5,7 @@ import {Utils} from "../../Utils"; | |||
| import Svg from "../../Svg"; | ||||
| import Img from "../../UI/Base/Img"; | ||||
| 
 | ||||
| export class GeoLocationHandler extends UIElement { | ||||
| export default class GeoLocationHandler extends UIElement { | ||||
| 
 | ||||
|     private readonly _isActive: UIEventSource<boolean> = new UIEventSource<boolean>(false); | ||||
|     private readonly _permission: UIEventSource<string> = new UIEventSource<string>(""); | ||||
|  | @ -13,17 +13,14 @@ export class GeoLocationHandler extends UIElement { | |||
|     private readonly _hasLocation: UIEventSource<boolean>; | ||||
|     private readonly _currentGPSLocation: UIEventSource<{ latlng: any; accuracy: number }>; | ||||
|     private readonly _leafletMap: UIEventSource<L.Map>; | ||||
|     private readonly _featureSwitch: UIEventSource<boolean>; | ||||
| 
 | ||||
|     constructor(currentGPSLocation: UIEventSource<{ latlng: any; accuracy: number }>, | ||||
|                 leafletMap: UIEventSource<L.Map>, | ||||
|                 featureSwitch: UIEventSource<boolean>) { | ||||
|                 leafletMap: UIEventSource<L.Map>) { | ||||
|         super(undefined); | ||||
|         this._currentGPSLocation = currentGPSLocation; | ||||
|         this._leafletMap = leafletMap; | ||||
|         this._featureSwitch = featureSwitch; | ||||
|         this._hasLocation = currentGPSLocation.map((location) => location !== undefined); | ||||
|         var self = this; | ||||
|         const self = this; | ||||
|         import("../../vendor/Leaflet.AccuratePosition.js").then(() => { | ||||
|             self.init(); | ||||
|         }) | ||||
|  | @ -92,10 +89,6 @@ export class GeoLocationHandler extends UIElement { | |||
|     } | ||||
| 
 | ||||
|     InnerRender(): string { | ||||
|         if (!this._featureSwitch.data) { | ||||
|             return ""; | ||||
|         } | ||||
| 
 | ||||
|         if (this._hasLocation.data) { | ||||
|             return Svg.crosshair_blue_img; | ||||
|         } | ||||
|  | @ -124,7 +117,7 @@ export class GeoLocationHandler extends UIElement { | |||
| 
 | ||||
|     private StartGeolocating(zoomlevel = 19) { | ||||
|         const self = this; | ||||
|         const map : any = this._leafletMap.data; | ||||
|         const map: any = this._leafletMap.data; | ||||
|         if (self._permission.data === "denied") { | ||||
|             return ""; | ||||
|         } | ||||
|  |  | |||
|  | @ -8,14 +8,14 @@ import Img from "../../UI/Base/Img"; | |||
|  * The stray-click-hanlders adds a marker to the map if no feature was clicked. | ||||
|  * Shows the given uiToShow-element in the messagebox | ||||
|  */ | ||||
| export class StrayClickHandler { | ||||
| export default class StrayClickHandler { | ||||
|     private _lastMarker; | ||||
|     private _uiToShow: (() => UIElement); | ||||
| 
 | ||||
|     constructor( | ||||
|         lastClickLocation: UIEventSource<{ lat: number, lon:number }>, | ||||
|         lastClickLocation: UIEventSource<{ lat: number, lon: number }>, | ||||
|         selectedElement: UIEventSource<string>, | ||||
|         filteredLayers: UIEventSource<{ readonly isDisplayed: UIEventSource<boolean>}[]>, | ||||
|         filteredLayers: UIEventSource<{ readonly isDisplayed: UIEventSource<boolean> }[]>, | ||||
|         leafletMap: UIEventSource<L.Map>, | ||||
|         fullscreenMessage: UIEventSource<UIElement>, | ||||
|         uiToShow: (() => UIElement)) { | ||||
|  | @ -23,14 +23,14 @@ export class StrayClickHandler { | |||
|         const self = this; | ||||
|         filteredLayers.data.forEach((filteredLayer) => { | ||||
|             filteredLayer.isDisplayed.addCallback(isEnabled => { | ||||
|                 if(isEnabled && self._lastMarker && leafletMap.data !== undefined){ | ||||
|                 if (isEnabled && self._lastMarker && leafletMap.data !== undefined) { | ||||
|                     // When a layer is activated, we remove the 'last click location' in order to force the user to reclick
 | ||||
|                     // This reclick might be at a location where a feature now appeared...
 | ||||
|                      leafletMap.data.removeLayer(self._lastMarker); | ||||
|                     leafletMap.data.removeLayer(self._lastMarker); | ||||
|                 } | ||||
|             }) | ||||
|         }) | ||||
|          | ||||
| 
 | ||||
|         lastClickLocation.addCallback(function (lastClick) { | ||||
|             selectedElement.setData(undefined); | ||||
| 
 | ||||
|  |  | |||
|  | @ -38,6 +38,7 @@ export default class UpdateFromOverpass implements FeatureSource{ | |||
|         location: UIEventSource<Loc>, | ||||
|         layoutToUse: UIEventSource<LayoutConfig>, | ||||
|         leafletMap: UIEventSource<L.Map>) { | ||||
|         console.log("Crating overpass updater") | ||||
|         this._location = location; | ||||
|         this._layoutToUse = layoutToUse; | ||||
|         this._leafletMap = leafletMap; | ||||
|  |  | |||
							
								
								
									
										68
									
								
								Logic/FeatureSource/FeatureDuplicatorPerLayer.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								Logic/FeatureSource/FeatureDuplicatorPerLayer.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| import FeatureSource from "./FeatureSource"; | ||||
| import {UIEventSource} from "../UIEventSource"; | ||||
| import LayerConfig from "../../Customizations/JSON/LayerConfig"; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * In some rare cases, some elements are shown on multiple layers (when 'passthrough' is enabled) | ||||
|  * If this is the case, multiple objects with a different _matching_layer_id are generated. | ||||
|  * If not, the _feature_layter_id is added | ||||
|  */ | ||||
| export default class FeatureDuplicatorPerLayer implements FeatureSource { | ||||
|     public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>; | ||||
| 
 | ||||
| 
 | ||||
|     constructor(layers: { layerDef: LayerConfig }[], upstream: FeatureSource) { | ||||
|         let noPassthroughts = true; | ||||
|         for (const layer of layers) { | ||||
|             if (layer.layerDef.passAllFeatures) { | ||||
|                 noPassthroughts = false; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         this.features = upstream.features.map(features => { | ||||
|             const newFeatures: { feature: any, freshness: Date }[] = []; | ||||
|             if(features === undefined){ | ||||
|                 return newFeatures; | ||||
|             } | ||||
| 
 | ||||
|             | ||||
|             for (const f of features) { | ||||
|                 if (f.feature._matching_layer_id) { | ||||
|                     // Already matched previously
 | ||||
|                     // We simply add it
 | ||||
|                     newFeatures.push(f); | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 for (const layer of layers) { | ||||
|                     if (layer.layerDef.overpassTags.matchesProperties(f.feature.properties)) { | ||||
|                         if (layer.layerDef.passAllFeatures) { | ||||
| 
 | ||||
|                             // We copy the feature; the "properties" field is kept identical though!
 | ||||
|                             // Keeping "properties" identical is needed, as it might break the 'allElementStorage' otherwise
 | ||||
|                             const newFeature = { | ||||
|                                 geometry: f.feature.geometry, | ||||
|                                 id: f.feature.id, | ||||
|                                 type: f.feature.type, | ||||
|                                 properties: f.feature.properties, | ||||
|                                 _matching_layer_id : layer.layerDef.id | ||||
|                             } | ||||
|                             newFeatures.push({feature: newFeature, freshness: f.freshness}); | ||||
|                         } else { | ||||
|                             // If not 'passAllFeatures', we are done
 | ||||
|                             f.feature._matching_layer_id = layer.layerDef.id; | ||||
|                             newFeatures.push(f); | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             return newFeatures; | ||||
| 
 | ||||
|         }) | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -18,7 +18,7 @@ export default class FeatureSourceMerger implements FeatureSource { | |||
|         let all = {}; // Mapping 'id' -> {feature, freshness}
 | ||||
|         for (const source of this._sources) { | ||||
|             for (const f of source.features.data) { | ||||
|                 const id = f.feature.properties.id+f.feature.geometry.type; | ||||
|                 const id = f.feature.properties.id+f.feature.geometry.type+f.feature._matching_layer_id; | ||||
|                 const oldV = all[id]; | ||||
|                 if(oldV === undefined){ | ||||
|                     all[id] = f; | ||||
|  |  | |||
|  | @ -14,14 +14,13 @@ export default class FilteringFeatureSource implements FeatureSource { | |||
|                 upstream: FeatureSource) { | ||||
| 
 | ||||
|         const layerDict = {}; | ||||
|         | ||||
| 
 | ||||
|         const self = this; | ||||
|          | ||||
| 
 | ||||
|         function update() { | ||||
|             console.log("UPdating...") | ||||
|             const features: { feature: any, freshness: Date }[] = upstream.features.data; | ||||
|             const newFeatures = features.filter(f => { | ||||
|                 const layerId = f.feature.properties._matching_layer_id; | ||||
|                 const layerId = f.feature._matching_layer_id; | ||||
|                 if (layerId === undefined) { | ||||
|                     console.error(f) | ||||
|                     throw "feature._matching_layer_id is undefined" | ||||
|  | @ -37,16 +36,22 @@ export default class FilteringFeatureSource implements FeatureSource { | |||
|             }); | ||||
|             self.features.setData(newFeatures); | ||||
|         } | ||||
| 
 | ||||
|         for (const layer of layers) { | ||||
|             layerDict[layer.layerDef.id] = layer; | ||||
|             layer.isDisplayed.addCallback(update) | ||||
|             layer.isDisplayed.addCallback(() => { | ||||
|                 console.log("Updating due to layer change") | ||||
|                 update()}) | ||||
|         } | ||||
|         upstream.features.addCallback(update); | ||||
|         location.map(l => l.zoom).addCallback(update); | ||||
|         upstream.features.addCallback(() => { | ||||
|             console.log("Updating due to upstream change") | ||||
|             update()}); | ||||
|         location.map(l => l.zoom).addCallback(() => { | ||||
|             console.log("UPdating due to zoom level change") | ||||
|             update();}); | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -45,7 +45,7 @@ export default class NoOverlapSource { | |||
|                     partitions[layerId] = [] | ||||
|                 } | ||||
|                 for (const feature of features) { | ||||
|                     partitions[feature.feature.properties._matching_layer_id].push(feature); | ||||
|                     partitions[feature.feature._matching_layer_id].push(feature); | ||||
|                 } | ||||
| 
 | ||||
|                 // With this partitioning in hand, we run over every layer and remove every underlying feature if needed
 | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ export default class WayHandlingApplyingFeatureSource implements FeatureSource { | |||
|                 const newFeatures: { feature: any, freshness: Date }[] = []; | ||||
|                 for (const f of features) { | ||||
|                     const feat = f.feature; | ||||
|                     const layerId = feat.properties._matching_layer_id; | ||||
|                     const layerId = feat._matching_layer_id; | ||||
|                     const layer: LayerConfig = layerDict[layerId].layerDef; | ||||
|                     if (layer === undefined) { | ||||
|                         throw "No layer found with id " + layerId; | ||||
|  | @ -50,6 +50,7 @@ export default class WayHandlingApplyingFeatureSource implements FeatureSource { | |||
|                     } | ||||
| 
 | ||||
|                     const centerPoint = GeoOperations.centerpoint(feat); | ||||
|                     centerPoint._matching_layer_id = feat._matching_layer_id; | ||||
|                     newFeatures.push({feature: centerPoint, freshness: f.freshness}); | ||||
|                      | ||||
|                     if(layer.wayHandling === LayerConfig.WAYHANDLING_CENTER_AND_WAY){ | ||||
|  |  | |||
|  | @ -1,163 +0,0 @@ | |||
| import {TagsFilter, TagUtils} from "./Tags"; | ||||
| import {UIEventSource} from "./UIEventSource"; | ||||
| import * as L from "leaflet" | ||||
| import {Layer} from "leaflet" | ||||
| import {GeoOperations} from "./GeoOperations"; | ||||
| import {UIElement} from "../UI/UIElement"; | ||||
| import State from "../State"; | ||||
| import LayerConfig from "../Customizations/JSON/LayerConfig"; | ||||
| import Hash from "./Web/Hash"; | ||||
| import LazyElement from "../UI/Base/LazyElement"; | ||||
| 
 | ||||
| /*** | ||||
|  *  | ||||
|  */ | ||||
| export class FilteredLayer { | ||||
| 
 | ||||
|     public readonly name: string | UIElement; | ||||
|     public readonly isDisplayed: UIEventSource<boolean> = new UIEventSource(true); | ||||
|     public readonly layerDef: LayerConfig; | ||||
| 
 | ||||
|     private readonly filters: TagsFilter; | ||||
|     private readonly _maxAllowedOverlap: number; | ||||
| 
 | ||||
|     /** The featurecollection from overpass | ||||
|      */ | ||||
|     private _dataFromOverpass: any[]; | ||||
|     /** | ||||
|      * The leaflet layer object which should be removed on rerendering | ||||
|      */ | ||||
|     private _geolayer; | ||||
| 
 | ||||
|     private _showOnPopup: (tags: UIEventSource<any>, feature: any) => UIElement; | ||||
| 
 | ||||
| 
 | ||||
|     constructor( | ||||
|         layerDef: LayerConfig, | ||||
|         showOnPopup: ((tags: UIEventSource<any>, feature: any) => UIElement) | ||||
|     ) { | ||||
|         this.layerDef = layerDef; | ||||
| 
 | ||||
|         this._showOnPopup = showOnPopup; | ||||
|         this.name = name; | ||||
|         this.filters = layerDef.overpassTags; | ||||
|         this._maxAllowedOverlap = layerDef.hideUnderlayingFeaturesMinPercentage; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * The main function to load data into this layer. | ||||
|      * The data that is NOT used by this layer, is returned as a geojson object; the other data is rendered | ||||
|      */ | ||||
|     public SetApplicableData(features: any[]): any[] { | ||||
|         const leftoverFeatures = []; | ||||
|         const selfFeatures = []; | ||||
|         for (let feature of features) { | ||||
|             const tags = TagUtils.proprtiesToKV(feature.properties); | ||||
|             const matches = this.filters.matches(tags); | ||||
|             if (matches) { | ||||
|                 selfFeatures.push(feature); | ||||
|             } | ||||
|             if (!matches || this.layerDef.passAllFeatures) { | ||||
|                 leftoverFeatures.push(feature); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         this.RenderLayer(selfFeatures) | ||||
|         return leftoverFeatures; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private RenderLayer(features: any[]) { | ||||
| 
 | ||||
|         if (this._geolayer !== undefined && this._geolayer !== null) { | ||||
|             // Remove the old geojson layer from the map - we'll reshow all the elements later on anyway
 | ||||
|             State.state.leafletMap.data.removeLayer(this._geolayer); | ||||
|         } | ||||
| 
 | ||||
|         // We fetch all the data we have to show:
 | ||||
|         const data = { | ||||
|             type: "FeatureCollection", | ||||
|             features: features | ||||
|         } | ||||
| 
 | ||||
|         let self = this; | ||||
|         this._geolayer = L.geoJSON(data, { | ||||
|             style: feature => { | ||||
|                 const tagsSource = State.state.allElements.getEventSourceFor(feature); | ||||
|                 return self.layerDef.GenerateLeafletStyle(tagsSource, self._showOnPopup !== undefined); | ||||
|             }, | ||||
|             pointToLayer: function (feature, latLng) { | ||||
|                 // Point to layer converts the 'point' to a layer object - as the geojson layer natively cannot handle points
 | ||||
|                 // Click handling is done in the next step
 | ||||
|                 const tagSource = State.state.allElements.getEventSourceFor(feature); | ||||
| 
 | ||||
|                 const style = self.layerDef.GenerateLeafletStyle(tagSource, self._showOnPopup !== undefined); | ||||
|                 let marker; | ||||
|                 if (style.icon === undefined) { | ||||
|                     marker = L.circle(latLng, { | ||||
|                         radius: 25, | ||||
|                         color: style.color | ||||
|                     }); | ||||
|                 } else { | ||||
|                     marker = L.marker(latLng, { | ||||
|                         icon: L.divIcon({ | ||||
|                             html: style.icon.html.Render(), | ||||
|                             className: style.icon.className, | ||||
|                             iconAnchor: style.icon.iconAnchor, | ||||
|                             iconUrl: style.icon.iconUrl, | ||||
|                             popupAnchor: style.icon.popupAnchor, | ||||
|                             iconSize: style.icon.iconSize | ||||
|                         }) | ||||
|                     }); | ||||
|                 } | ||||
|                 return marker; | ||||
|             }, | ||||
|             onEachFeature: function (feature, layer: Layer) { | ||||
| 
 | ||||
|                 if (self._showOnPopup === undefined) { | ||||
|                     // No popup contents defined -> don't do anything
 | ||||
|                     return; | ||||
|                 } | ||||
|                 const popup = L.popup({ | ||||
|                     autoPan: true, | ||||
|                     closeOnEscapeKey: true, | ||||
|                 }, layer); | ||||
| 
 | ||||
| 
 | ||||
|                 const eventSource = State.state.allElements.getEventSourceFor(feature); | ||||
|                 let uiElement: LazyElement = new LazyElement(() => self._showOnPopup(eventSource, feature)); | ||||
|                 popup.setContent(uiElement.Render()); | ||||
|                 layer.bindPopup(popup); | ||||
|                 // We first render the UIelement (which'll still need an update later on...)
 | ||||
|                 // But at least it'll be visible already
 | ||||
| 
 | ||||
| 
 | ||||
|                 layer.on("click", (e) => { | ||||
|                     // We set the element as selected...
 | ||||
|                     uiElement.Activate(); | ||||
|                     State.state.selectedElement.setData(feature); | ||||
|                 }); | ||||
| 
 | ||||
|                 if (feature.properties.id.replace(/\//g, "_") === Hash.Get().data) { | ||||
|                     // This element is in the URL, so this is a share link
 | ||||
|                     // We already open it
 | ||||
|                     uiElement.Activate(); | ||||
|                     popup.setContent(uiElement.Render()); | ||||
| 
 | ||||
|                     const center = GeoOperations.centerpoint(feature).geometry.coordinates; | ||||
|                     popup.setLatLng({lat: center[1], lng: center[0]}); | ||||
|                     popup.openOn(State.state.leafletMap.data); | ||||
|                     State.state.selectedElement.setData(feature); | ||||
|                     uiElement.Update(); | ||||
|                 } | ||||
| 
 | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         this._geolayer.addTo(State.state.leafletMap.data); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -8,7 +8,7 @@ import Svg from "../../Svg"; | |||
| import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; | ||||
| import Img from "../../UI/Base/Img"; | ||||
| 
 | ||||
| export class UserDetails { | ||||
| export default class UserDetails { | ||||
| 
 | ||||
|     public loggedIn = false; | ||||
|     public name = "Not logged in"; | ||||
|  | @ -21,15 +21,15 @@ export class UserDetails { | |||
| } | ||||
| 
 | ||||
| export class OsmConnection { | ||||
|      | ||||
| 
 | ||||
|     public auth; | ||||
|     public userDetails: UIEventSource<UserDetails>; | ||||
|     _dryRun: boolean; | ||||
| 
 | ||||
|     public preferencesHandler: OsmPreferences; | ||||
|     public changesetHandler: ChangesetHandler; | ||||
|      | ||||
|     private _onLoggedIn : ((userDetails: UserDetails) => void)[] = []; | ||||
| 
 | ||||
|     private _onLoggedIn: ((userDetails: UserDetails) => void)[] = []; | ||||
| 
 | ||||
|     constructor(dryRun: boolean, oauth_token: UIEventSource<string>, | ||||
|                 // Used to keep multiple changesets open and to write to the correct changeset
 | ||||
|  | @ -44,11 +44,11 @@ export class OsmConnection { | |||
|         } catch (e) { | ||||
|             console.warn("Detecting standalone mode failed", e, ". Assuming in browser and not worrying furhter") | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         const iframeMode = window !== window.top; | ||||
| 
 | ||||
| 
 | ||||
|         if ( iframeMode || pwaStandAloneMode || !singlePage) { | ||||
|         if (iframeMode || pwaStandAloneMode || !singlePage) { | ||||
|             // In standalone mode, we DON'T use single page login, as 'redirecting' opens a new window anyway...
 | ||||
|             // Same for an iframe...
 | ||||
|             this.auth = new osmAuth({ | ||||
|  | @ -74,7 +74,7 @@ export class OsmConnection { | |||
|         this._dryRun = dryRun; | ||||
| 
 | ||||
|         this.preferencesHandler = new OsmPreferences(this.auth, this); | ||||
|          | ||||
| 
 | ||||
|         this.changesetHandler = new ChangesetHandler(layoutName, dryRun, this, this.auth); | ||||
|         if (oauth_token.data !== undefined) { | ||||
|             console.log(oauth_token.data) | ||||
|  | @ -86,7 +86,7 @@ export class OsmConnection { | |||
|                 }, this.auth); | ||||
| 
 | ||||
|             oauth_token.setData(undefined); | ||||
|             | ||||
| 
 | ||||
|         } | ||||
|         if (this.auth.authenticated()) { | ||||
|             this.AttemptLogin(); // Also updates the user badge
 | ||||
|  | @ -100,7 +100,8 @@ export class OsmConnection { | |||
|         layout: LayoutConfig, | ||||
|         allElements: ElementStorage, | ||||
|         generateChangeXML: (csid: string) => string, | ||||
|                            continuation: () => void = () => {}) { | ||||
|         continuation: () => void = () => { | ||||
|         }) { | ||||
|         this.changesetHandler.UploadChangeset(layout, allElements, generateChangeXML, continuation); | ||||
|     } | ||||
| 
 | ||||
|  | @ -112,10 +113,10 @@ export class OsmConnection { | |||
|         return this.preferencesHandler.GetLongPreference(key, prefix); | ||||
|     } | ||||
| 
 | ||||
|     public OnLoggedIn(action: (userDetails: UserDetails) => void){ | ||||
|     public OnLoggedIn(action: (userDetails: UserDetails) => void) { | ||||
|         this._onLoggedIn.push(action); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     public LogOut() { | ||||
|         this.auth.logout(); | ||||
|         this.userDetails.data.loggedIn = false; | ||||
|  | @ -132,7 +133,7 @@ export class OsmConnection { | |||
|             method: 'GET', | ||||
|             path: '/api/0.6/user/details' | ||||
|         }, function (err, details) { | ||||
|             if(err != null){ | ||||
|             if (err != null) { | ||||
|                 console.log(err); | ||||
|                 return; | ||||
|             } | ||||
|  | @ -140,9 +141,9 @@ export class OsmConnection { | |||
|             if (details == null) { | ||||
|                 return; | ||||
|             } | ||||
|              | ||||
| 
 | ||||
|             self.CheckForMessagesContinuously(); | ||||
|              | ||||
| 
 | ||||
|             // details is an XML DOM of user details
 | ||||
|             let userInfo = details.getElementsByTagName("user")[0]; | ||||
| 
 | ||||
|  | @ -177,7 +178,7 @@ export class OsmConnection { | |||
|                 action(self.userDetails.data); | ||||
|             } | ||||
|             self._onLoggedIn = []; | ||||
|            | ||||
| 
 | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | @ -189,7 +190,7 @@ export class OsmConnection { | |||
|                 console.log("Checking for messages") | ||||
|                 this.AttemptLogin(); | ||||
|             } | ||||
|         },  5 * 60 * 1000); | ||||
|         }, 5 * 60 * 1000); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue