Your IP : 52.15.224.97


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

import {
	Tag,
	Type,
	Dom,
	Event,
	Loc
} from 'main.core';
import {
	Address,
	Format,
	Location,
	ControlMode,
	MapBase,
	GeocodingServiceBase,
	AddressStringConverter,
	LocationType
} from 'location.core';
import {EventEmitter} from 'main.core.events';
import AddressString from './addressstring';
import AddressApplier from './addressapplier';
import Popup from './popup';

import 'ui.design-tokens';
import './css/mappopup.css';

export default class MapPopup extends EventEmitter
{
	static #onChangedEvent = 'onChanged';
	static #onMouseOverEvent = 'onMouseOver';
	static #onMouseOutEvent = 'onMouseOut';
	static #onShowedEvent = 'onShow';
	static #onClosedEvent = 'onClose';

	#map;
	#mode;
	#address;
	#popup;
	#addressString;
	#addressApplier;
	#addressFormat;
	#gallery;
	#locationRepository;
	#isMapRendered = false;
	#mapInnerContainer;
	#geocodingService;
	#contentWrapper;
	#userLocationPoint;

	constructor(props)
	{
		super(props);
		this.setEventNamespace('BX.Location.Widget.MapPopup');

		if (!(props.map instanceof MapBase))
		{
			BX.debug('map must be instance of Map');
		}

		this.#map = props.map;

		if (props.geocodingService instanceof GeocodingServiceBase)
		{
			this.#geocodingService = props.geocodingService;
		}

		this.#map.onLocationChangedEventSubscribe(this.#onLocationChanged.bind(this));

		if (!(props.popup instanceof Popup))
		{
			BX.debug('popup must be instance of Popup');
		}

		this.#popup = props.popup;

		if (!(props.addressFormat instanceof Format))
		{
			BX.debug('addressFormat must be instance of Format');
		}

		this.#addressFormat = props.addressFormat;

		this.#addressString = new AddressString({
			addressFormat: this.#addressFormat
		});
		this.#createAddressApplier();

		if (props.gallery)
		{
			this.#gallery = props.gallery;
		}

		this.#locationRepository = props.locationRepository;
		this.#userLocationPoint = props.userLocationPoint;
	}

	#createAddressApplier()
	{
		this.#addressApplier = new AddressApplier(
			{
				propsData: {
					address: this.#address,
					addressFormat: this.#addressFormat,
					isHidden: true,
				}
			}
		);
		this.#addressApplier.$mount();
		this.#addressApplier.$on('apply', (event) => {
			const prevAddress = event.address;

			this.#address = prevAddress;
			this.#addressString.address = prevAddress;
			this.#addressApplier.$props.isHidden = true;

			this.emit(
				MapPopup.#onChangedEvent,
				{address: prevAddress}
			);
		});
	}

	#onLocationChanged(event: Event)
	{
		const data = event.getData();
		const location = data.location;
		const address = location.toAddress();

		if (!this.#address)
		{
			this.#address = address;
			this.#addressString.address = address;
			this.emit(
				MapPopup.#onChangedEvent,
				{address: address}
			);
		}
		else if (address.fieldCollection.isEqual(this.#address.fieldCollection, LocationType.ADDRESS_LINE_1))
		{
			this.#address.latitude = address.latitude;
			this.#address.longitude = address.longitude;

			if (this.#address.location)
			{
				this.#address.location.latitude = address.latitude;
				this.#address.location.longitude = address.longitude;
			}

			this.emit(
				MapPopup.#onChangedEvent,
				{address: this.#address}
			);

			this.#addressApplier.$props.isHidden = true;
		}
		else
		{
			this.#addressString.address = address;
			this.#addressApplier.$props.address = address;
			this.#addressApplier.$props.isHidden = false;
		}

		if (this.#gallery)
		{
			this.#gallery.location = location;
		}
	}

	render(props: object): void
	{
		this.#address = props.address;
		this.#mode = props.mode;
		this.#isMapRendered = false;
		this.#mapInnerContainer = Tag.render`<div class="location-map-inner"></div>`;
		this.#renderPopup(props.bindElement, this.#mapInnerContainer);
	}

	#renderPopup(bindElement: Element, mapInnerContainer: Element): Popup
	{
		let gallery = '';

		if (this.#gallery)
		{
			gallery = this.#gallery.render();
		}

		const thirdPartyWarningNode = Tag.render`
			<div class="location-map-address-third-party-warning">
				${Loc.getMessage('LOCATION_WIDGET_THIRD_PARTY_WARNING')}
			</div>
		`;

		this.#contentWrapper = Tag.render`
			<div class="location-map-wrapper">
				<div class="location-map-container">
					${mapInnerContainer}
					${gallery}
				</div>
				${this.#mode === ControlMode.edit ? this.#addressString.render({address: this.#address}) : ''}
				${thirdPartyWarningNode}
				${this.#mode === ControlMode.edit ? this.#addressApplier.$el : ''}
			</div>`;

		Event.bind(this.#contentWrapper, 'click', (e) => e.stopPropagation());
		Event.bind(this.#contentWrapper, 'mouseover', (e) => this.emit(MapPopup.#onMouseOverEvent, e));
		Event.bind(this.#contentWrapper, 'mouseout', (e) => this.emit(MapPopup.#onMouseOutEvent, e));
		this.bindElement = bindElement;
		this.#popup.setContent(this.#contentWrapper);
	}

	get bindElement()
	{
		return this.#popup.getBindElement();
	}

	set bindElement(bindElement: Element)
	{
		if (Type.isDomNode(bindElement))
		{
			this.#popup.setBindElement(bindElement);
		}
		else
		{
			BX.debug('bindElement must be type of dom node');
		}
	}

	set address(address: ?Address): void
	{
		this.#address = address;
		this.#addressString.address = address;

		this.#convertAddressToLocation(address)
			.then((location) => {
				this.#setLocationInternal(location);
			});
	}

	#extractLatLon(address: Address): ?Array
	{
		let result = null;
		let lat;
		let lon;

		if (address.latitude && address.longitude)
		{
			lat = address.latitude;
			lon = address.longitude;
		}
		else if (address.location
			&& address.location.latitude
			&& address.location.longitude
		)
		{
			lat = address.location.latitude;
			lon = address.location.longitude;
		}

		if (lat && lat !== '0' && lon && lon !== '0')
		{
			result = [lat, lon];
		}

		return result;
	}

	#convertAddressToLocation(address: ?Address, useUserLocation: boolean = false): Promise<?Location>
	{
		return new Promise((resolve) => {
			if (useUserLocation)
			{
				resolve(
					this.#userLocationPoint && this.#mode !== ControlMode.view
						? new Location({
							latitude: this.#userLocationPoint.latitude,
							longitude: this.#userLocationPoint.longitude
						})
						: null
				);
				return;
			}

			if (address)
			{
				const latLon = this.#extractLatLon(address);

				if (latLon)
				{
					resolve(new Location({
						latitude: latLon[0],
						longitude: latLon[1],
						type: address.getType()
					}));
					return;
				}
			}

			resolve(null);
		});
	}

	#setLocationInternal(location: ?Location): void
	{
		if (this.#map)
		{
			this.#map.location = location;
		}

		if (this.#gallery)
		{
			this.#gallery.location = location;
		}
	}

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

	#renderMap({location})
	{
		return this.#map.render({
			mapContainer: this.#mapInnerContainer,
			location: location,
			mode: this.#mode
		});
	}

	show(useUserLocation: boolean = false): void
	{
		this.#convertAddressToLocation(this.#address, useUserLocation)
			.then((location) => {
				if (!location)
				{
					return;
				}

				this.#popup.show();

				if (!this.#isMapRendered)
				{
					this.#renderMap({location})
						.then(() => {
							if (this.#gallery)
							{
								this.#gallery.location = location;
							}
							this.emit(MapPopup.#onShowedEvent);
							this.#map.onMapShow();
						});

					this.#isMapRendered = true;
				}
				else
				{
					this.#map.location = location;

					if (this.#gallery)
					{
						this.#gallery.location = location;
					}

					this.emit(MapPopup.#onShowedEvent);
					this.#map.onMapShow();
				}
			});
	}

	isShown(): boolean
	{
		return this.#popup.isShown();
	}

	close(): void
	{
		this.#popup.close();
		this.#addressApplier.$props.isHidden = true;
		this.emit(MapPopup.#onClosedEvent);
	}

	onChangedEventSubscribe(listener: Function): void
	{
		this.subscribe(MapPopup.#onChangedEvent, listener);
	}

	onMouseOverSubscribe(listener: Function): void
	{
		this.subscribe(MapPopup.#onMouseOverEvent, listener);
	}

	onMouseOutSubscribe(listener: Function): void
	{
		this.subscribe(MapPopup.#onMouseOutEvent, listener);
	}

	subscribeOnShowedEvent(listener: Function): void
	{
		this.subscribe(MapPopup.#onShowedEvent, listener);
	}

	subscribeOnClosedEvent(listener: Function): void
	{
		this.subscribe(MapPopup.#onClosedEvent, listener);
	}

	destroy()
	{
		this.#map = null;
		this.#gallery = null;
		this.#addressString = null;
		this.#addressApplier = null;

		this.#popup.destroy();
		this.#popup = null;
		Dom.remove(this.#contentWrapper);
		this.#contentWrapper = null;
		Event.unbindAll(this);
	}
}