UNPKG

gp-crm-ui

Version:

Модуль компонентов UI Имя модуля: `gp-crm-ui`

288 lines (242 loc) 7.42 kB
import { Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; import { Component, ElementRef, EventEmitter, forwardRef, HostListener, Injector, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; // Сенсор import { ResizeSensor } from 'css-element-queries'; // Интерфейсы import { IPowerSelect } from '../../interfaces'; // Токены import { POWER_SELECT_DATA } from '../../tokens'; // Перечисления import { PowerSelectType } from '../../enums'; // Компоненты import { CrmPowerSelectGroupPopupComponent } from '../../components/crm-power-select-group-popup/crm-power-select-group-popup.component'; import { CrmPowerSelectPopupComponent } from '../../components/crm-power-select-popup/crm-power-select-popup.component'; import { CrmPowerSelectTreePopupComponent } from '../../components/crm-power-select-tree-popup/crm-power-select-tree-popup.component'; // Селектор @Component({ selector: 'crm-power-select', templateUrl: './crm-power-select.component.html', styleUrls: ['./crm-power-select.component.scss'], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CrmPowerSelectComponent), multi: true }] }) export class CrmPowerSelectComponent implements OnInit, OnDestroy, OnChanges, ControlValueAccessor { constructor( private readonly el: ElementRef, private readonly injector: Injector, private readonly overlay: Overlay ) { this.selectItem.subscribe((selected: IPowerSelect) => { this.selected = selected; }); } // Тип слайдера @Input() public type: PowerSelectType = PowerSelectType.List; // Список элементов @Input() public items: IPowerSelect[]; // Выбраный элемент private _selected: IPowerSelect; @Input() public set selected(value: IPowerSelect) { this._selected = value; this.POPUP_DATA.selected = value; if (this.onChange) { this.onChange(value); } } public get selected(): IPowerSelect { return this._selected; } // Кнопка @Input() public button: any; // Событие нажатия кнопки @Output() public buttonClick: EventEmitter<any> = new EventEmitter<any>(); // Событие выбора элемента @Output() public selectItem: EventEmitter<IPowerSelect> = new EventEmitter<IPowerSelect>(); // Событие поиска @Output() public searchTerms: EventEmitter<string> = new EventEmitter<string>(); // Вызовем когда значение изменится private onChange: (value: IPowerSelect) => void; // Вызовем при любом дествии пользователя с контроллом private onTouched: () => void; // Флаг, отключено public disabled: boolean = false; // Конфигурация всплывающего окна private overlayConfig: OverlayConfig; // Ссылка на открытое окно private overlayRef: OverlayRef; // Данные всплывающего окна private readonly POPUP_DATA: any = { loaded: new EventEmitter<void>(), items: [], selected: null, button: this.button, buttonClick: this.buttonClick, selectItem: this.selectItem, searchTerms: this.searchTerms, width: 0 }; // Сенсор изменения размера private resizeSensor: any; // -------------------------------------------------------------------------- // Обновить размер private updateSize(): void { this.POPUP_DATA.width = this.el && this.el.nativeElement && this.el.nativeElement.offsetWidth; } // Обработчик открытия всплывающего окна public onOpenPopup(): void { if (!this.disabled) { this.open(); } } // Открыть окно private open(): void { if (!this.overlayRef || !this.overlayRef.hasAttached()) { // Создание слоя всплывающего окна this.overlayRef = this.overlay.create(this.overlayConfig); // Токены const injectionTokens = new WeakMap(); injectionTokens.set(OverlayRef, this.overlayRef); injectionTokens.set(POWER_SELECT_DATA, this.POPUP_DATA); // Создание инжектора const injector = new PortalInjector(this.injector, injectionTokens); // Компонент let component = CrmPowerSelectPopupComponent; switch (this.type) { case PowerSelectType.GroupList: component = CrmPowerSelectGroupPopupComponent; break; case PowerSelectType.Tree: component = CrmPowerSelectTreePopupComponent; break; default: } // Создание контейнера const containerPortal = new ComponentPortal( component, null, injector ); // Добавить к слою this.overlayRef.attach(containerPortal); } } // Закрыть окно private close(): void { if (this.overlayRef) { this.overlayRef.dispose(); } } // Добавить сенсор private addSensor(): void { if (this.el && this.el.nativeElement) { this.resizeSensor = new ResizeSensor( this.el.nativeElement, this.updateSize.bind(this) ); } } // Удалить сенсор private removeSensor(): void { if (this.resizeSensor) { this.resizeSensor.detach(); } } // Создать конфигурацию private createConfig(): void { // Стратегия const strategy = this.overlay.position() .connectedTo( this.el, { originX: 'start', originY: this.type === PowerSelectType.Tree ? 'bottom' : 'top' }, { overlayX: 'start', overlayY: 'top' } ); // Конфигурация this.overlayConfig = new OverlayConfig({ positionStrategy: strategy }); } // -------------------------------------------------------------------------- // Реакция на клик хост-элемента @HostListener('click') public onClick(): void { if (this.onTouched) { this.onTouched(); } } // Вызовет форма, если значение изменилось извне public writeValue(selected: IPowerSelect): void { this.selected = selected; } // Сохраняем обратный вызов для изменений public registerOnChange(fn: any): void { this.onChange = fn; } // Сохраняем обратный вызов для "касаний" public registerOnTouched(fn: any): void { this.onTouched = fn; } // Установка состояния disabled public setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; } // -------------------------------------------------------------------------- // HOOKS // Инициализация public ngOnInit(): void { this.createConfig(); this.addSensor(); this.updateSize(); } // Уничтожение public ngOnDestroy(): void { this.removeSensor(); this.close(); } // Изменение входных параметров public ngOnChanges(changes: SimpleChanges): void { if (changes.items) { this.POPUP_DATA.items = this.items; this.POPUP_DATA.loaded.emit(); } if (changes.selected) { this.POPUP_DATA.selected = this.selected; } if (changes.button) { this.POPUP_DATA.button = this.button; } } }