import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { Directive, Self, Optional, HostBinding, Input, NgModule } from '@angular/core';
import * as i1 from '@angular/forms';
import { FormsModule } from '@angular/forms';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Destroy, KeyCodes } from '@deja-js/component/core';
import { BehaviorSubject, fromEvent, takeUntil, distinctUntilChanged, map, timer, take, filter, switchMap } from 'rxjs';

/*
 *  @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
 */
class DejaEditableDirective extends Destroy {
    constructor(elementRef, control) {
        super();
        this.control = control;
        this._disabled = null;
        this._inEdition = false;
        this._editMode = false;
        this._mandatory = false;
        this._multiline = false;
        this.edit$ = new BehaviorSubject([false, false]);
        this.onTouchedCallback = () => undefined;
        this.onChangeCallback = (_a) => undefined;
        if (this.control) {
            this.control.valueAccessor = this;
        }
        this.element = elementRef.nativeElement;
        const mouseDownEvent$ = fromEvent(this.element, 'mousedown');
        mouseDownEvent$.pipe(takeUntil(this.destroyed$)).subscribe(e => {
            if (this.inEdition || this.disabled) {
                e.cancelBubble = true;
                return false;
            }
            else if (this.editMode) {
                this.edit$.next([true, true]);
                e.cancelBubble = true;
                return false;
            }
            return undefined;
        });
        const inEdition$ = this.edit$.pipe(distinctUntilChanged(), map(([value, selectOnFocus]) => {
            if (selectOnFocus ?? true) {
                timer(10).pipe(take(1), takeUntil(this.destroyed$)).subscribe(() => {
                    this.selectAll();
                    this.focus();
                });
            }
            this._inEdition = value;
            if (value) {
                this.element.setAttribute('contenteditable', 'true');
            }
            else {
                this.element.removeAttribute('contenteditable');
            }
            this.refreshView();
            return value;
        }));
        const kill$ = inEdition$.pipe(filter(value => !value));
        const mouseDown$ = fromEvent(this.element.ownerDocument, 'mousedown').pipe(filter(event => !this.isChildElement(event.target)), takeUntil(kill$));
        inEdition$.pipe(filter(value => value), switchMap(() => mouseDown$), takeUntil(this.destroyed$)).subscribe(() => {
            const text = this.element.innerText.replace(/\n/g, '<br />').replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
            this.onTouchedCallback();
            if (text || !this.mandatory) {
                this.value = text;
            }
            this.inEdition = false;
        });
        const keyDown$ = fromEvent(this.element, 'keydown').pipe(takeUntil(kill$));
        inEdition$.pipe(filter(value => value), switchMap(() => keyDown$), takeUntil(this.destroyed$)).subscribe(e => {
            e.cancelBubble = true;
            e.stopPropagation();
            if (e.code === KeyCodes.Enter && !this.multiline) {
                const text = this.element.innerText;
                if (text || !this.mandatory) {
                    this.value = text;
                }
                this.inEdition = false;
            }
            else if (e.code === KeyCodes.Escape) {
                this.inEdition = false;
            }
            return false;
        });
    }
    /** Définit une valeur indiquant si le contenu édité est obligatoire. Si la valeur est 'true' la sortie du mode édition ne sera pas possible tant qu'un contenu n'est pas ajouté. */
    set mandatory(value) {
        this._mandatory = coerceBooleanProperty(value);
    }
    /** Retourne une valeur indiquant si le contenu édité est obligatoire. Si la valeur est 'true' la sortie du mode édition ne sera pas possible tant qu'un contenu n'est pas ajouté. */
    get mandatory() {
        return this._mandatory;
    }
    /** Définit une valeur indiquant si le contenu édité est multiligne */
    set multiline(value) {
        this._multiline = coerceBooleanProperty(value);
    }
    /** Retourne une valeur indiquant si le contenu édité est multiligne */
    get multiline() {
        return this._multiline;
    }
    /** Permet de désactiver le controle */
    set disabled(value) {
        const disabled = coerceBooleanProperty(value);
        this._disabled = disabled || null;
        if (this.disabled) {
            this.edit$.next([false, false]);
        }
    }
    get disabled() {
        return this.control?.disabled || this._disabled;
    }
    /** Définit une valeur indiquant si l'édition est activée. */
    set editMode(value) {
        this._editMode = coerceBooleanProperty(value);
    }
    /** Retourne une valeur indiquant si l'édition est activée. */
    get editMode() {
        return this._editMode;
    }
    /** Définit une valeur indiquant si l'élément est en édition. */
    set inEdition(value) {
        if (this.disabled) {
            return;
        }
        this.edit$.next([coerceBooleanProperty(value), false]);
    }
    /** Retourne une valeur indiquant si l'élément est en édition. */
    get inEdition() {
        return this._inEdition;
    }
    // ************* ControlValueAccessor Implementation **************
    // set accessor including call the onchange callback
    set value(model) {
        if (model !== this.model) {
            this.writeValue(model);
            this.onChangeCallback(model);
        }
    }
    // get accessor
    get value() {
        return this.model;
    }
    // From ControlValueAccessor interface
    writeValue(value) {
        this.model = value;
        this.refreshView();
    }
    // From ControlValueAccessor interface
    registerOnChange(fn) {
        this.onChangeCallback = fn;
    }
    // From ControlValueAccessor interface
    registerOnTouched(fn) {
        this.onTouchedCallback = fn;
    }
    setDisabledState(isDisabled) {
        this.disabled = isDisabled;
    }
    // ************* End of ControlValueAccessor Implementation **************
    ngOnInit() {
        this.model = this.element.innerHTML;
    }
    /** Donne le focus à la zone d'édition. */
    focus() {
        this.element.focus();
    }
    /** Place toute la zone d'édition en selectioné. */
    selectAll() {
        const range = document.createRange();
        range.selectNodeContents(this.element);
        const sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    }
    /** Active la zone d'édition. */
    edit(selectOnFocus) {
        this.edit$.next([!this.disabled, selectOnFocus]);
    }
    isChildElement(element) {
        let parentElement = element;
        // eslint-disable-next-line no-loops/no-loops
        while (parentElement && parentElement !== this.element) {
            parentElement = parentElement.parentElement;
        }
        return parentElement === this.element;
    }
    refreshView() {
        if (!this.model) {
            return;
        }
        if (this.inEdition) {
            this.element.innerText = this.model.replace(/<br\s*[/]?>/gi, '\n');
        }
        else {
            this.element.innerHTML = this.model.replace(/\n/g, '<br />');
        }
    }
}
DejaEditableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DejaEditableDirective, deps: [{ token: i0.ElementRef }, { token: i1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
DejaEditableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.1.3", type: DejaEditableDirective, selector: "[deja-editable]", inputs: { mandatory: "mandatory", multiline: "multiline", disabled: "disabled", editMode: ["deja-editable", "editMode"], inEdition: "inEdition" }, host: { properties: { "attr.disabled": "this._disabled" } }, usesInheritance: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DejaEditableDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[deja-editable]'
                }]
        }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.NgControl, decorators: [{
                    type: Self
                }, {
                    type: Optional
                }] }]; }, propDecorators: { _disabled: [{
                type: HostBinding,
                args: ['attr.disabled']
            }], mandatory: [{
                type: Input
            }], multiline: [{
                type: Input
            }], disabled: [{
                type: Input
            }], editMode: [{
                type: Input,
                args: ['deja-editable']
            }], inEdition: [{
                type: Input
            }] } });

/*
 *  @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
 */
class DejaEditableModule {
}
DejaEditableModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DejaEditableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
DejaEditableModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.1.3", ngImport: i0, type: DejaEditableModule, declarations: [DejaEditableDirective], imports: [CommonModule,
        FormsModule], exports: [DejaEditableDirective] });
DejaEditableModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DejaEditableModule, imports: [CommonModule,
        FormsModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DejaEditableModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [DejaEditableDirective],
                    exports: [DejaEditableDirective],
                    imports: [
                        CommonModule,
                        FormsModule
                    ]
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { DejaEditableDirective, DejaEditableModule };
//# sourceMappingURL=deja-js-component-content-editable.mjs.map
