"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PromptHandle = exports.VALIDATE_CLASS_NAME = exports.PROMPT_VALIDATE_TYPE = void 0;
const ide_utils_1 = require("@opensumi/ide-utils");
const input_1 = require("../../input");
const utils_1 = require("../../utils");
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
var PROMPT_VALIDATE_TYPE;
(function (PROMPT_VALIDATE_TYPE) {
    PROMPT_VALIDATE_TYPE[PROMPT_VALIDATE_TYPE["INFO"] = 1] = "INFO";
    PROMPT_VALIDATE_TYPE[PROMPT_VALIDATE_TYPE["ERROR"] = 2] = "ERROR";
    PROMPT_VALIDATE_TYPE[PROMPT_VALIDATE_TYPE["WARNING"] = 3] = "WARNING";
})(PROMPT_VALIDATE_TYPE || (exports.PROMPT_VALIDATE_TYPE = PROMPT_VALIDATE_TYPE = {}));
var VALIDATE_CLASS_NAME;
(function (VALIDATE_CLASS_NAME) {
    VALIDATE_CLASS_NAME["INFO"] = "validate-info";
    VALIDATE_CLASS_NAME["ERROR"] = "validate-error";
    VALIDATE_CLASS_NAME["WARNING"] = "validate-warning";
})(VALIDATE_CLASS_NAME || (exports.VALIDATE_CLASS_NAME = VALIDATE_CLASS_NAME = {}));
/**
 * 输入输出框需要在外部手动进行管理，由于我们使用的是虚拟的react节点渲染，一旦用户向上或向下滚动超出渲染访问，相关的React组件会被回收
 * 故这里在外部手动维护输入框对象
 */
class PromptHandle {
    constructor() {
        this.disposables = new ide_utils_1.DisposableCollection();
        this.isInPendingCommitState = false;
        this._destroyed = false;
        this._hasValidateElement = false;
        this._hasAddonAfter = false;
        this._inComposition = false;
        // event
        this.onChangeEmitter = new ide_utils_1.Emitter();
        this.onCommitEmitter = new ide_utils_1.Emitter();
        this.onCancelEmitter = new ide_utils_1.Emitter();
        this.onFocusEmitter = new ide_utils_1.Emitter();
        this.onBlurEmitter = new ide_utils_1.Emitter();
        this.onDestroyEmitter = new ide_utils_1.Emitter();
        this.markdownRenderer = (0, utils_1.createMarkedRenderer)();
        this.handleClick = (ev) => {
            ev.stopPropagation();
        };
        this.handleDBClick = (ev) => {
            ev.stopPropagation();
        };
        this.handleCompositionstart = () => {
            this._inComposition = true;
        };
        this.handleCompositionend = () => {
            this._inComposition = false;
        };
        this.handleKeyup = () => {
            if (this._inComposition) {
                return;
            }
            this.onChangeEmitter.fire(this.$.value);
        };
        this.handleKeydown = async (ev) => {
            if (this._inComposition) {
                return;
            }
            if (ev.key === 'Escape') {
                const res = await this.onCancelEmitter.fireAndAwait(this.$.value);
                // 当有回调函数报错或返回结果为false时，终止后续操作
                if (res.some((r) => r.result === false || !!r.err)) {
                    return;
                }
                this.destroy();
            }
            if (ev.key === 'Enter') {
                this.isInPendingCommitState = true;
                this.$.disabled = true;
                const res = await this.onCommitEmitter.fireAndAwait(this.$.value);
                // 当有回调函数报错或返回结果为false时，终止后续操作
                if (res.some((r) => r.result === false || !!r.err)) {
                    this.isInPendingCommitState = false;
                    this.$.disabled = false;
                    this.$.focus();
                    return;
                }
                this.isInPendingCommitState = false;
                this.$.disabled = false;
                this.destroy();
            }
        };
        this.handleFocus = () => {
            this.onFocusEmitter.fire(this.$.value);
        };
        this.handleBlur = async (ev) => {
            // 如果Input由于`react-virtualized`被从视图中卸载，在下一帧前Input的isConnected属性不会被更新
            await delay(0);
            // 如果Input组件不在DOM中，但也没有被手动销毁，则表示由于其不在视窗内被`react-virtualized`卸载
            if (!this.$.isConnected && !this.destroyed) {
                return;
            }
            const res = await this.onBlurEmitter.fireAndAwait(this.$.value);
            // 当有回调函数报错或返回结果为false时，终止后续操作
            if (res.some((r) => r.result === false || !!r.err)) {
                return;
            }
            if (!this.isInPendingCommitState) {
                this.destroy();
            }
        };
        this.$ = document.createElement('input');
        this.$.setAttribute('type', 'text');
        this.$.setAttribute('name', 'no_keybinding');
        // reset props
        this.$.setAttribute('spellcheck', 'false');
        this.$.setAttribute('autoCapitalize', 'off');
        this.$.setAttribute('autoCorrect', 'off');
        this.$.setAttribute('autoComplete', 'off');
        this.ProxiedInput = (0, input_1.bindInputElement)(this.$);
        this.$.addEventListener('click', this.handleClick);
        this.$.addEventListener('dblclick', this.handleDBClick);
        this.$.addEventListener('keyup', this.handleKeyup);
        this.$.addEventListener('keydown', this.handleKeydown);
        this.$.addEventListener('focus', this.handleFocus);
        this.$.addEventListener('blur', this.handleBlur);
        this.$.addEventListener('compositionstart', this.handleCompositionstart);
        this.$.addEventListener('compositionend', this.handleCompositionend);
        this.$validate = document.createElement('div');
        this.$validate.setAttribute('style', 'top: 100%;');
        this.$addonAfter = document.createElement('div');
        this.$addonAfter.setAttribute('class', 'kt-input-addon-after');
        // 可能存在PromptHandle创建后没被使用的情况
    }
    get destroyed() {
        return this._destroyed;
    }
    get onChange() {
        return this.onChangeEmitter.event;
    }
    get onCommit() {
        return this.onCommitEmitter.event;
    }
    get onCancel() {
        return this.onCancelEmitter.event;
    }
    get onFocus() {
        return this.onFocusEmitter.event;
    }
    get onBlur() {
        return this.onBlurEmitter.event;
    }
    get onDestroy() {
        return this.onDestroyEmitter.event;
    }
    focus() {
        this.$.focus();
    }
    setSelectionRange(start, end) {
        this.$.setSelectionRange(start, end);
    }
    addClassName(classname) {
        this.$.classList.add(classname);
    }
    removeClassName(classname) {
        this.$.classList.remove(classname);
    }
    addAddonAfter(classname) {
        var _a, _b;
        if (!this._hasAddonAfter && !this._destroyed) {
            (_b = (_a = this.$.parentElement) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.appendChild(this.$addonAfter);
            this._hasAddonAfter = true;
        }
        const addElement = document.createElement('div');
        addElement.setAttribute('class', classname);
        this.$addonAfter.appendChild(addElement);
    }
    removeAddonAfter() {
        var _a, _b, _c;
        if (this._hasAddonAfter) {
            (_a = this.$addonAfter.firstChild) === null || _a === void 0 ? void 0 : _a.remove();
            (_c = (_b = this.$.parentElement) === null || _b === void 0 ? void 0 : _b.parentElement) === null || _c === void 0 ? void 0 : _c.removeChild(this.$addonAfter);
            this._hasAddonAfter = false;
        }
    }
    addValidateMessage(validateMessage) {
        var _a, _b, _c, _d, _e, _f, _g;
        if (!this._hasValidateElement && !this._destroyed) {
            // 移动到与input-box同级别
            (_c = (_b = (_a = this.$.parentElement) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.parentElement) === null || _c === void 0 ? void 0 : _c.appendChild(this.$validate);
            this._hasValidateElement = true;
        }
        let validateBoxClassName = 'validate-message popup ';
        if (validateMessage && validateMessage.type === PROMPT_VALIDATE_TYPE.ERROR) {
            this._validateClassName = VALIDATE_CLASS_NAME.ERROR;
        }
        else if (validateMessage && validateMessage.type === PROMPT_VALIDATE_TYPE.WARNING) {
            this._validateClassName = VALIDATE_CLASS_NAME.WARNING;
        }
        else {
            this._validateClassName = VALIDATE_CLASS_NAME.INFO;
        }
        validateBoxClassName += this._validateClassName;
        this.$validate.classList.value = validateBoxClassName;
        this.$validate.innerHTML = (0, utils_1.toMarkdownHtml)(validateMessage.message || '', { renderer: this.markdownRenderer });
        (_e = (_d = this.$.parentElement) === null || _d === void 0 ? void 0 : _d.parentElement) === null || _e === void 0 ? void 0 : _e.classList.remove(VALIDATE_CLASS_NAME.INFO, VALIDATE_CLASS_NAME.ERROR, VALIDATE_CLASS_NAME.WARNING);
        (_g = (_f = this.$.parentElement) === null || _f === void 0 ? void 0 : _f.parentElement) === null || _g === void 0 ? void 0 : _g.classList.add(this._validateClassName);
    }
    removeValidateMessage() {
        var _a, _b, _c, _d, _e;
        if (this._hasValidateElement) {
            (_c = (_b = (_a = this.$.parentElement) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.parentElement) === null || _c === void 0 ? void 0 : _c.removeChild(this.$validate);
            this._hasValidateElement = false;
            (_e = (_d = this.$.parentElement) === null || _d === void 0 ? void 0 : _d.parentElement) === null || _e === void 0 ? void 0 : _e.classList.remove(this._validateClassName);
        }
    }
    destroy() {
        if (this._destroyed) {
            return;
        }
        // 获取最顶层的父级焦点容器
        const element = this.focusPrevActiveElement();
        this._destroyed = true;
        this.$.removeEventListener('click', this.handleClick);
        this.$.removeEventListener('keyup', this.handleKeyup);
        this.$.removeEventListener('keydown', this.handleKeydown);
        this.$.removeEventListener('focus', this.handleFocus);
        this.$.removeEventListener('blur', this.handleBlur);
        this.removeValidateMessage();
        this.removeAddonAfter();
        this.$.disabled = false;
        this.onDestroyEmitter.fire(this.$.value);
        this.disposables.dispose();
        requestAnimationFrame(() => {
            element === null || element === void 0 ? void 0 : element.focus();
        });
    }
    focusPrevActiveElement() {
        let parentElement = this.$.parentElement;
        while (parentElement) {
            if (typeof parentElement.attributes['tabindex'] !== 'undefined') {
                break;
            }
            parentElement = parentElement === null || parentElement === void 0 ? void 0 : parentElement.parentElement;
        }
        return parentElement;
    }
}
exports.PromptHandle = PromptHandle;
//# sourceMappingURL=PromptHandle.js.map