all files / component/overlay/ overlay.component.ts

97.22% Statements 105/108
87.1% Branches 27/31
92.59% Functions 25/27
96.91% Lines 94/97
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206                                    46×   99×   55× 55× 25× 25× 25×       46×       46× 46× 46×           64×       36× 36×       46×     46×       46× 46×   46×     46× 46×       46× 46× 46× 46×         46× 46×   46× 46×       66× 22× 44×   43×         30×                 223×       48× 48×                   14×                 15×     66× 22×   44×       45×     14× 11×                         84×      
/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
 
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { CdkConnectedOverlay, CdkOverlayOrigin, OverlayContainer } from '@angular/cdk/overlay';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, OnDestroy, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { timer as observableTimer } from 'rxjs';
import { first, takeWhile } from 'rxjs/operators';
import { MediaService } from '../../common/core/media/media.service';
import { DejaConnectionPositionPair } from '../../common/core/overlay/connection-position-pair';
 
// providers: [ MediaService ],
@Component({
    changeDetection: ChangeDetectionStrategy.OnPush,
    encapsulation: ViewEncapsulation.None,
    selector: 'deja-overlay',
    styles: [require('./overlay.component.scss')],
    template: require('./overlay.component.html'),
})
export class DejaOverlayComponent implements OnDestroy {
    /** Renvoie une valeur qui indique si le dialog est affiché. */
    private _isVisible = false;
 
    public get isVisible() {
        return this._isVisible;
    }
    @Input() public set isVisible(value: boolean) {
        const isVisible = coerceBooleanProperty(value);
        if (this._isVisible !== isVisible) {
            this._isVisible = isVisible;
            this.changeDetectorRef.markForCheck();
            this.visibleChange.emit(this.isVisible);
        }
    }
 
    @Input() public overlayBackdropClass = 'cdk-overlay-transparent-backdrop';
 
    @Input() public set overlayContainerClass(value: string) {
        const containerElement = this.overlayContainer.getContainerElement() as HTMLElement;
        containerElement.classList.add(value);
    }
 
    private _hasBackdrop = true;
    private _width: string = null;
    private _widthForMobile = '100%';
    private _ownerElement: HTMLElement;
 
    @Input() public set hasBackdrop(value: boolean) {
        this._hasBackdrop = coerceBooleanProperty(value);
    }
 
    public get hasBackdrop() {
        return this._hasBackdrop;
    }
 
    /** Renvoie ou définit l'élement sur lequel le menu devra s'aligner */
    @Input() public set ownerElement(value: HTMLElement) {
        this._ownerElement = value;
        this.updateOriginOverlay();
    }
 
    /** Déclenché lorsque la visibilité du dialog change. */
    @Output() public visibleChange = new EventEmitter<boolean>();
 
    /** Déclenché lorsque l'overlay est fermé. */
    @Output() public closed = new EventEmitter<boolean>();
 
    /** Internal use */
    public overlayOrigin: CdkOverlayOrigin;
    @Input() public overlayOffsetX = 0;
    @Input() public overlayOffsetY = 0;
 
    private _positions = DejaConnectionPositionPair.default;
    private _positionsForMobile: DejaConnectionPositionPair[];
 
    private _isMobile = false;
    private isAlive = true;
 
    /** Overlay pane containing the options. */
    @ViewChild(CdkConnectedOverlay) private overlay: CdkConnectedOverlay;
 
    constructor(private changeDetectorRef: ChangeDetectorRef, private elementRef: ElementRef, private overlayContainer: OverlayContainer, mediaService: MediaService) {
        const containerElement = this.overlayContainer.getContainerElement() as HTMLElement;
        containerElement.classList.add('deja-overlay-container');
        containerElement.addEventListener('contextmenu', (event: Event) => {
            event.preventDefault();
            return false;
        });
 
        mediaService.isMobile$.pipe(
            takeWhile(() => this.isAlive))
            .subscribe((value) => {
                this.isMobile = value;
                this.changeDetectorRef.markForCheck();
            });
    }
 
    public get positions() {
        if (!this.isMobile) {
            return this._positions;
        } else if (this._positionsForMobile) {
            return this._positionsForMobile;
        } else {
            return DejaConnectionPositionPair.parse('start top start top');
        }
    }
 
    @Input()
    public set positions(value: DejaConnectionPositionPair[] | string) {
        this._positions = typeof value === 'string' ? DejaConnectionPositionPair.parse(value) : value;
    }
 
    /** Si pas null, sera utilisé quand isMobile est vrai. Si null et si isMobile est vrai,
     *  alors c'est la valeur 'start top start top' qui est utilisée.
     * */
    @Input()
    public set positionsForMobile(value: DejaConnectionPositionPair[] | string) {
        this._positionsForMobile = typeof value === 'string' ? DejaConnectionPositionPair.parse(value) : value;
    }
 
    public get isMobile() {
        return this._isMobile;
    }
 
    @Input()
    public set isMobile(value: boolean) {
        this._isMobile = coerceBooleanProperty(value);
        this.updateOriginOverlay();
    }
 
    public get width() {
        return this._width;
    }
 
    @Input()
    /**
     * définit la largeur de l'overlay.
     */
    public set width(width: string) {
        this._width = width;
    }
 
    public get widthForMobile() {
        return this._widthForMobile;
    }
 
    @Input()
    /**
     * définit la largeur de l'overlay quand isMobile est true. '100%' par défaut.
     */
    public set widthForMobile(widthForMobile: string) {
        this._widthForMobile = widthForMobile;
    }
 
    public get overlayWidth() {
        if (!this.isMobile) {
            return this._width;
        } else {
            return this._widthForMobile;
        }
    }
 
    public ngOnDestroy() {
        this.isAlive = false;
    }
 
    public updatePosition() {
        if (this.overlay && this.overlay.overlayRef) {
            this.overlay.overlayRef.updatePosition();
        }
    }
 
    /** Affiche le dialog. */
    public show(eventOrOffsetX: MouseEvent | number, offsetY?: number) {
        this.overlayOffsetX = offsetY !== undefined ? +eventOrOffsetX : 0;
        this.overlayOffsetY = offsetY || 0;
        const e = eventOrOffsetX as MouseEvent;
        const target = e && e.target;
        this.overlayOrigin = new CdkOverlayOrigin(new ElementRef((this.isMobile && document.body) || target || this.ownerElement || this.elementRef.nativeElement));
        this.isVisible = true;
        this.changeDetectorRef.markForCheck();
        observableTimer(1).pipe(
            first())
            .subscribe(() => {
                this.updatePosition();
            });
    }
 
    /** Ferme le dialog. */
    public close() {
        this.isVisible = false;
        this.closed.emit(true);
        this.changeDetectorRef.markForCheck();
    }
 
    private updateOriginOverlay() {
        this.overlayOrigin = new CdkOverlayOrigin(new ElementRef((this.isMobile && document.body) || this._ownerElement || this.elementRef.nativeElement));
    }
}