Your IP : 18.118.142.122


Current Path : /var/www/www-root/data/www/www.monolith-realty.ru/bitrix/js/location/google/src/
Upload File :
Current File : /var/www/www-root/data/www/www.monolith-realty.ru/bitrix/js/location/google/src/mapmobile.js

import {
	Event,
	Text,
	Tag,
	Dom,
} from 'main.core';
import {
	Location,
	LocationRepository,
	ControlMode,
	MapBase,
	ErrorPublisher
} from 'location.core';

/**
 * Class for the autocomplete locations and addresses inputs
 */
export default class Map extends MapBase
{
	static #onChangedEvent = 'onChanged';
	static #onStartChanging = 'onStartChanging';
	static #onEndChanging = 'onEndChanging';
	static #onMapViewChanged = 'onMapViewChanged';

	/** {string} */
	#languageId;
	/** {google.maps.Map} */
	#googleMap;
	/** {GoogleSource} */
	#googleSource;
	#markerNode;
	/** {google.maps.Marker} */
	#locationMarker;

	/** {number} */
	#zoom;
	/** {ControlMode} */
	#mode;
	/** Location */
	#location;
	#geocoder;
	#locationRepository;
	#timerId = null;
	#changeDelay;
	#loaderPromise = null;
	#isMapChanging = false;

	constructor(props)
	{
		super(props);
		this.#languageId = props.languageId;
		this.#googleSource = props.googleSource;
		this.#locationRepository = props.locationRepository || new LocationRepository();
		this.#changeDelay = props.changeDelay || 700;
	}

	render(props: Object): Promise
	{
		this.#loaderPromise = this.#googleSource.loaderPromise.then(() => {
			this.#initGoogleMap(props);
		});

		return this.#loaderPromise;
	}

	get loaderPromise(): Promise
	{
		return this.#loaderPromise;
	}

	set mode(mode: string)
	{
		this.#mode = mode;
	}

	#convertLocationToPosition(location: ?Location): Object
	{
		if (!location)
		{
			return null;
		}

		if (typeof google === 'undefined' || typeof google.maps === 'undefined')
		{
			return null;
		}

		return new google.maps.LatLng(location.latitude, location.longitude);
	}

	#adjustZoom(): void
	{
		if (!this.#location)
		{
			return;
		}

		const zoom = Map.getZoomByLocation(this.#location);
		if (zoom !== null && zoom !== this.#zoom)
		{
			this.zoom = zoom;
		}
	}

	get zoom(): number
	{
		return this.#zoom;
	}

	set zoom(zoom: number): void
	{
		this.#zoom = zoom;

		if (this.#googleMap)
		{
			this.#googleMap.setZoom(zoom);
		}
	}

	#getPositionToLocationPromise(position): Promise
	{
		return new Promise( (resolve) => {
			this.#geocoder.geocode({'location': position}, (results, status)  => {
				if (status === 'OK' && results[0])
				{
					resolve(results[0].place_id);
				}
				else if (status === 'ZERO_RESULTS')
				{
					resolve('');
				}
				else
				{
					throw Error('Geocoder failed due to: ' + status);
				}
			});
		})
		.then((placeId) => {
			let result;

			if (placeId)
			{
				result = this.#locationRepository.findByExternalId(
					placeId,
					this.#googleSource.sourceCode,
					this.#languageId
				);
			}
			else
			{
				result = new Promise((resolve) => {
					resolve(null);
				});
			}

			return result;
		});
	}

	set location(location: Location)
	{
		this.#location = location;
		const position = this.#convertLocationToPosition(location);

		if (position && this.#googleMap)
		{
			this.#googleMap.panTo(position);
		}

		this.#adjustZoom();
	}

	panTo(latitude: string, longitude: string): void
	{
		if (
			typeof google !== 'undefined'
			&& typeof google.maps !== 'undefined'
			&& this.#googleMap
		)
		{
			this.#googleMap.panTo(new google.maps.LatLng(latitude, longitude));

			this.#adjustZoom();
		}
	}

	get location(): Location
	{
		return this.#location;
	}

	onLocationChangedEventSubscribe(listener: function): void
	{
		this.subscribe(Map.#onChangedEvent, listener);
	}

	onStartChangingSubscribe(listener: function): void
	{
		this.subscribe(Map.#onStartChanging, listener);
	}

	onEndChangingSubscribe(listener: function): void
	{
		this.subscribe(Map.#onEndChanging, listener);
	}

	onMapViewChangedSubscribe(listener: function): void
	{
		this.subscribe(Map.#onMapViewChanged, listener);
	}

	#emitOnLocationChangedEvent(location: ?Location)
	{
		if (this.#mode === ControlMode.edit)
		{
			this.emit(Map.#onChangedEvent, { location: location	});
		}
	}

	#createTimer()
	{
		if (this.#timerId !== null)
		{
			clearTimeout(this.#timerId);
		}

		this.#timerId = setTimeout(
			() => {
				const requestId = Text.getRandom();
				this.emit(Map.#onStartChanging, { requestId });

				this.#timerId = null;
				const position = this.#googleMap.getCenter();
				this.#fulfillOnChangedEvent(position, requestId);
			},
			this.#changeDelay
		);
	}

	#fulfillOnChangedEvent(position, requestId)
	{
		this.#getPositionToLocationPromise(position)
			.then((location) => {
				this.emit(Map.#onEndChanging, { requestId });
				this.#emitOnLocationChangedEvent(location);
			})
			.catch((response) => {
				this.emit(Map.#onEndChanging, { requestId });
				ErrorPublisher.getInstance().notify(response.errors);
			});
	}

	#onDrag()
	{
		if (this.#timerId !== null)
		{
			clearTimeout(this.#timerId);
		}
	}

	#onDragStart()
	{
		this.#onMapChanging();
		this.emit(Map.#onMapViewChanged);
	}

	#onZoomChanged()
	{
		this.#onMapChanging();
		this.emit(Map.#onMapViewChanged);
	}

	#onMapChanging()
	{
		if (this.#mode === ControlMode.edit)
		{
			this.#isMapChanging = true;

			Dom.addClass(this.#markerNode, 'location-map-mobile-center-marker-up');
		}
	}

	#onIdle()
	{
		if (this.#mode === ControlMode.edit)
		{
			if (this.#isMapChanging === false)
			{
				return;
			}

			const upClass = 'location-map-mobile-center-marker-up';
			if (Dom.hasClass(this.#markerNode, upClass))
			{
				Dom.removeClass(this.#markerNode, upClass);
			}

			this.#createTimer();
			this.#isMapChanging = false;
		}
	}

	#initGoogleMap(props): void
	{
		this.#mode = props.mode;
		this.#location = props.location || null;

		if (typeof google === 'undefined' || typeof google.maps.Map === 'undefined')
		{
			throw new Error('google.maps.Map must be defined');
		}

		const position = this.#convertLocationToPosition(this.#location);

		const mapProps = {
			gestureHandling: 'greedy',
			disableDefaultUI: true,
			zoomControl: BX.prop.getBoolean(props, 'zoomControl', true),
			zoomControlOptions: {
				position: google.maps.ControlPosition.TOP_LEFT
			}
		};

		const zoom = Map.getZoomByLocation(this.#location);
		if (zoom)
		{
			mapProps.zoom = zoom;
		}

		if (position)
		{
			mapProps.center = position;
		}

		this.#googleMap = new google.maps.Map(
			props.mapContainer,
			mapProps
		);
		if (this.#mode === ControlMode.edit)
		{
			this.#markerNode = Tag.render`<div class="location-map-mobile-center-marker"></div>`;
			this.#googleMap.getDiv().appendChild(this.#markerNode);
		}
		else
		{
			this.#locationMarker = new google.maps.Marker({
				position: position,
				map: this.#googleMap,
				draggable: false,
				icon: '/bitrix/js/location/css/image/marker.png',
			});
		}

		this.#googleMap.addListener('dragstart', () => this.#onDragStart());
		this.#googleMap.addListener('idle', () => this.#onIdle());
		this.#googleMap.addListener('drag', () => this.#onDrag());
		this.#googleMap.addListener('zoom_changed', () => this.#onZoomChanged());
		if (typeof google.maps.Geocoder === 'undefined')
		{
			throw new Error('google.maps.Geocoder must be defined');
		}

		this.#geocoder = new google.maps.Geocoder;

		if (props.searchOnRender)
		{
			this.#createTimer();
		}
	}

	get googleMap(): ?Object
	{
		return this.#googleMap;
	}

	destroy()
	{
		Event.unbindAll(this);
		this.#googleMap = null;
		this.#geocoder = null;
		this.#timerId = null;
		this.#loaderPromise = null;
		super.destroy();
	}
}