<commit_before>import {AfterViewChecked, Component, ElementRef, ViewChild} from '@angular/core';
import {NgbActiveModal, NgbModal, NgbPopover} from '@ng-bootstrap/ng-bootstrap';
import {Messages} from 'idai-components-2';
import {SettingsService} from '../../core/settings/settings-service';
import {DoceditComponent} from '../docedit/docedit.component';
import {M} from '../m';
import {ProjectNameValidator} from '../../common/project-name-validator';

const remote = require('electron').remote;

@Component({
    selector: 'projects-modal',
    moduleId: module.id,
    templateUrl: './projects-modal.html',
    host: {
        '(document:click)': 'handleClick($event)',
        '(window:keydown)': 'onKeyDown($event)'
    }
})
/**
 * @author <NAME>
 * @author <NAME>
 */
export class ProjectsModalComponent implements AfterViewChecked {

    public selectedProject: string;
    public newProject: string = '';
    public projectToDelete: string = '';

    private focusInput: boolean = false;

    @ViewChild('createPopover') private createPopover: NgbPopover;
    @ViewChild('deletePopover') private deletePopover: NgbPopover;
    @ViewChild('newProjectInput') private newProjectInput: ElementRef;
    @ViewChild('deleteProjectInput') private deleteProjectInput: ElementRef;


    constructor(public activeModal: NgbActiveModal,
                private settingsService: SettingsService,
                private modalService: NgbModal,
                private messages: Messages) {
    }


    ngAfterViewChecked() {

        if (this.focusInput) {
            if (this.newProjectInput) this.newProjectInput.nativeElement.focus();
            if (this.deleteProjectInput) this.deleteProjectInput.nativeElement.focus();
            this.focusInput = false;
        }
    }


    public getProjects = () => this.settingsService.getDbs();


    public onKeyDown(event: KeyboardEvent) {

        if (event.key === 'Escape') {
            if (this.createPopover.isOpen()) {
                this.createPopover.close();
            } else if (this.deletePopover.isOpen()) {
                this.deletePopover.close();
            } else {
                this.activeModal.close();
            }
        }
    }


    public reset() {

        this.projectToDelete = '';
        this.newProject = '';
    }


    public openMenu(popover: any) {

        this.reset();
        popover.toggle();
        this.focusInput = true;
    }


    public async selectProject() {

        this.settingsService.stopSync();

        await this.settingsService.selectProject(this.selectedProject);
        ProjectsModalComponent.reload();
    }


    public async createProject() {

        const validationErrorMessage: string[]|undefined = ProjectNameValidator.validate(
            this.newProject, this.getProjects()
        );
        if (validationErrorMessage) return this.messages.add(validationErrorMessage);

        this.settingsService.stopSync();

        await this.settingsService.createProject(
            this.newProject,
            remote.getGlobal('switches')
            && remote.getGlobal('switches').destroy_before_create
        );
        ProjectsModalComponent.reload();
    }


    public async deleteProject() {

        if (!this.canDeleteProject()) return;

        this.settingsService.stopSync();

        await this.settingsService.deleteProject(this.selectedProject);
        this.selectedProject = this.getProjects()[0];
        ProjectsModalComponent.reload();
    }


    public async editProject() {

        const document = this.settingsService.getProjectDocument();

        const doceditRef = this.modalService.open(DoceditComponent, { size: 'lg', backdrop: 'static' });
        doceditRef.componentInstance.setDocument(document);

        await doceditRef.result.then(
            () => this.settingsService.loadProjectDocument(),
            closeReason => {}
        );
    }


    public handleClick(event: Event) {

        let target: any = event.target;
        let insideCreatePopover: boolean = false;
        let insideDeletePopover: boolean = false;

        do {
            if (target.id === 'new-project-menu' || target.id === 'new-project-button') {
                insideCreatePopover = true;
            }
            if (target.id === 'delete-project-menu' || target.id === 'delete-project-button') {
                insideDeletePopover = true;
            }
            target = target.parentNode;
        } while (target);

        if (!insideCreatePopover && this.createPopover.isOpen()) this.createPopover.close();
        if (!insideDeletePopover && this.deletePopover.isOpen()) this.deletePopover.close();
    }

<commit_msg>do not close projects modal when closing docedit modal via escape key<commit_after>import {AfterViewChecked, Component, ElementRef, ViewChild} from '@angular/core';
import {NgbActiveModal, NgbModal, NgbPopover} from '@ng-bootstrap/ng-bootstrap';
import {Messages} from 'idai-components-2';
import {SettingsService} from '../../core/settings/settings-service';
import {DoceditComponent} from '../docedit/docedit.component';
import {M} from '../m';
import {ProjectNameValidator} from '../../common/project-name-validator';

const remote = require('electron').remote;

@Component({
    selector: 'projects-modal',
    moduleId: module.id,
    templateUrl: './projects-modal.html',
    host: {
        '(document:click)': 'handleClick($event)',
        '(window:keydown)': 'onKeyDown($event)'
    }
})
/**
 * @author <NAME>
 * @author <NAME>
 */
export class ProjectsModalComponent implements AfterViewChecked {

    public selectedProject: string;
    public newProject: string = '';
    public projectToDelete: string = '';

    private focusInput: boolean = false;
    private subModalOpened: boolean = false;

    @ViewChild('createPopover') private createPopover: NgbPopover;
    @ViewChild('deletePopover') private deletePopover: NgbPopover;
    @ViewChild('newProjectInput') private newProjectInput: ElementRef;
    @ViewChild('deleteProjectInput') private deleteProjectInput: ElementRef;


    constructor(public activeModal: NgbActiveModal,
                private settingsService: SettingsService,
                private modalService: NgbModal,
                private messages: Messages) {
    }


    ngAfterViewChecked() {

        if (this.focusInput) {
            if (this.newProjectInput) this.newProjectInput.nativeElement.focus();
            if (this.deleteProjectInput) this.deleteProjectInput.nativeElement.focus();
            this.focusInput = false;
        }
    }


    public getProjects = () => this.settingsService.getDbs();


    public onKeyDown(event: KeyboardEvent) {

        if (!this.subModalOpened && event.key === 'Escape') {
            if (this.createPopover.isOpen()) {
                this.createPopover.close();
            } else if (this.deletePopover.isOpen()) {
                this.deletePopover.close();
            } else {
                this.activeModal.close();
            }
        }
    }


    public reset() {

        this.projectToDelete = '';
        this.newProject = '';
    }


    public openMenu(popover: any) {

        this.reset();
        popover.toggle();
        this.focusInput = true;
    }


    public async selectProject() {

        this.settingsService.stopSync();

        await this.settingsService.selectProject(this.selectedProject);
        ProjectsModalComponent.reload();
    }


    public async createProject() {

        const validationErrorMessage: string[]|undefined = ProjectNameValidator.validate(
            this.newProject, this.getProjects()
        );
        if (validationErrorMessage) return this.messages.add(validationErrorMessage);

        this.settingsService.stopSync();

        await this.settingsService.createProject(
            this.newProject,
            remote.getGlobal('switches')
            && remote.getGlobal('switches').destroy_before_create
        );
        ProjectsModalComponent.reload();
    }


    public async deleteProject() {

        if (!this.canDeleteProject()) return;

        this.settingsService.stopSync();

        await this.settingsService.deleteProject(this.selectedProject);
        this.selectedProject = this.getProjects()[0];
        ProjectsModalComponent.reload();
    }


    public async editProject() {

        this.subModalOpened = true;

        const document = this.settingsService.getProjectDocument();

        const doceditRef = this.modalService.open(DoceditComponent,
            { size: 'lg', backdrop: 'static', keyboard: false }
        );
        doceditRef.componentInstance.setDocument(document);

        try {
            await doceditRef.result;
            await this.settingsService.loadProjectDocument();
        } catch(err) {
            // Docedit modal has been canceled
        } finally {
            this.subModalOpened = false;
        }
    }


    public handleClick(event: Event) {

        let target: any = event.target;
        let insideCreatePopover: boolean = false;
        let insideDeletePopover: boolean = false;

        do {
            if (target.id === 'new-project-menu' || target.id === 'new-project-button') {
                insideCreatePopover = true;
            }
            if (target.id === 'delete-project-menu' || target.id === 'delete-project-button') {
                insideDeletePopover = true;
            }
            target = target.parentNode;
        } while (target);

        if (!insideCreatePopover && this.createPopover.isOpen()) this.createPopover.close();
        if (!insideDeletePopover && this.deletePopover.isOpen()) this.deletePopover.close();
    }


{'fraction_non_alphanumeric': 0.11986336818134768, 'fraction_numerical': 0.0004140358140979195, 'mean_word_length': 2.5904868078781123, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2552489', 'n_tokens_mistral': 2615, 'n_tokens_neox': 2512, 'n_words': 504}