Your IP : 216.73.216.86


Current Path : /var/www/homesaver/www/bitrix/js/landing/ui/field/color/src/control/spectrum/
Upload File :
Current File : /var/www/homesaver/www/bitrix/js/landing/ui/field/color/src/control/spectrum/spectrum.js

import {BaseEvent} from 'main.core.events';
import {Dom, Event, Tag, Text} from 'main.core';

import ColorValue from "../../color_value";
import './css/spectrum.css';
import BaseControl from "../base_control/base_control";
import {PageObject} from 'landing.pageobject';

export default class Spectrum extends BaseControl
{
	static DEFAULT_SATURATION: number = 100;
	static HUE_RANGE: number = 375;
	static HUE_RANGE_GRAY_THRESHOLD: number = 360;
	static HUE_RANGE_GRAY_MIDDLE: number = 367;
	static HIDE_CLASS: string = 'hidden';

	// todo: debug, del method, change calls, change css
	static getDefaultSaturation()
	{
		const global = window.top.document.location.saturation;
		const urlParam = (new URL(window.top.document.location)).searchParams.get('saturation');
		const saturation = global || urlParam || Spectrum.DEFAULT_SATURATION;

		window.top.document.body.style.setProperty('--saturation', saturation + '%');

		return parseInt(saturation);
	}

	constructor(options)
	{
		super();
		this.setEventNamespace('BX.Landing.UI.Field.Color.Spectrum');

		this.onPickerDragStart = this.onPickerDragStart.bind(this);
		this.onPickerDragMove = this.onPickerDragMove.bind(this);
		this.onPickerDragEnd = this.onPickerDragEnd.bind(this);
		this.onScroll = this.onScroll.bind(this);

		this.document = PageObject.getRootWindow().document;
		this.scrollContext = options.contentRoot;

		Event.bind(this.getLayout(), 'mousedown', this.onPickerDragStart);
	}

	buildLayout(): HTMLDivElement
	{
		return Tag.render`
			<div class="landing-ui-field-color-spectrum">
				${this.getPicker()}
			</div>
		`;
	}

	getPicker(): HTMLDivElement
	{
		return this.cache.remember('picker', () => {
			return Tag.render`<div class="landing-ui-field-color-spectrum-picker"></div>`;
		});
	}

	getPickerPos(): {x: number, y: number}
	{
		return {
			x: Text.toNumber(Dom.style(this.getPicker(), 'left')),
			y: Text.toNumber(Dom.style(this.getPicker(), 'top')),
		};
	}

	onPickerDragStart(event: MouseEvent)
	{
		if (event.ctrlKey || event.metaKey || event.button)
		{
			return;
		}

		Event.bind(this.scrollContext, 'scroll', this.onScroll);
		Event.bind(this.document, 'mousemove', this.onPickerDragMove);
		Event.bind(this.document, 'mouseup', this.onPickerDragEnd);

		Dom.addClass(this.document.body, 'landing-ui-field-color-draggable');
		this.onScroll();
		this.showPicker();
		this.onPickerDragMove(event);
	}

	onPickerDragMove(event: MouseEvent)
	{
		if (event.target === this.getPicker())
		{
			return;
		}
		this.setPickerPos(event.pageX, event.pageY);
		this.onChange();
	}

	onPickerDragEnd()
	{
		Event.unbind(this.scrollContext, 'scroll', this.onScroll);
		Event.unbind(this.document, 'mousemove', this.onPickerDragMove);
		Event.unbind(this.document, 'mouseup', this.onPickerDragEnd);

		Dom.removeClass(this.document.body, 'landing-ui-field-color-draggable');
	}

	onScroll()
	{
		this.cache.delete('layoutSize');
	}

	getLayoutRect(): {}
	{
		return this.cache.remember('layoutSize', () => {
			const layoutRect = this.getLayout().getBoundingClientRect();
			return {
				width: layoutRect.width,
				height: layoutRect.height,
				top: layoutRect.top,
				left: layoutRect.left,
			};
		});
	}

	/**
	 * Set picker by absolut page coords
	 * @param x
	 * @param y
	 */
	setPickerPos(x: number, y: number)
	{
		const {width, height, top, left} = this.getLayoutRect();

		let leftToSet = Math.min(Math.max((x - left), 0), width);
		leftToSet = (leftToSet > width / Spectrum.HUE_RANGE * Spectrum.HUE_RANGE_GRAY_THRESHOLD)
			? width / Spectrum.HUE_RANGE * Spectrum.HUE_RANGE_GRAY_MIDDLE
			: leftToSet
		;

		Dom.style(this.getPicker(), {
			left: `${leftToSet}px`,
			top: `${Math.min(Math.max((y - top), 0), height)}px`,
		});
	}

	getValue(): ?ColorValue
	{
		return this.cache.remember('value', () => {
			if (Dom.hasClass(this.getPicker(), Spectrum.HIDE_CLASS))
			{
				return null;
			}

			const layoutWidth = this.getLayout().getBoundingClientRect().width;
			const h = (this.getPickerPos().x / layoutWidth) * Spectrum.HUE_RANGE;
			const layoutHeight = this.getLayout().getBoundingClientRect().height;
			const l = (1 - this.getPickerPos().y / layoutHeight) * 100;

			if (isNaN(h) || isNaN(l))
			{
				return null;
			}

			return new ColorValue({
				h: Math.min(h, Spectrum.HUE_RANGE_GRAY_THRESHOLD),
				s: (h >= Spectrum.HUE_RANGE_GRAY_THRESHOLD) ? 0 : Spectrum.getDefaultSaturation(),
				l: l,
			});
		});
	}

	setValue(value: ?ColorValue)
	{
		super.setValue(value);

		if ((value !== null) && Spectrum.isSpectrumValue(value))
		{
			// in first set value we can't match bounding client rect (layout not render). Then, use percents
			const {h, s, l} = value.getHsl();

			const left = (s === 0)
				? Spectrum.HUE_RANGE_GRAY_MIDDLE / Spectrum.HUE_RANGE * 100
				: h / Spectrum.HUE_RANGE * 100;
			Dom.style(this.getPicker(), 'left', `${left}%`);

			const top = 100 - l;
			Dom.style(this.getPicker(), 'top', `${top}%`);

			this.showPicker();
		}
		else
		{
			this.hidePicker();
		}
	}

	hidePicker()
	{
		Dom.addClass(this.getPicker(), Spectrum.HIDE_CLASS);
	}

	showPicker()
	{
		Dom.removeClass(this.getPicker(), Spectrum.HIDE_CLASS);
	}

	isActive(): boolean
	{
		return (this.getValue() !== null) && Spectrum.isSpectrumValue(this.getValue());
	}

	static isSpectrumValue(value: ColorValue): boolean
	{
		return (value !== null)
			&& (
				value.getHsl().s === Spectrum.getDefaultSaturation()
				|| value.getHsl().s === 0
			);
	}
}