"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mathViewAndEditPlugin = exports.MathBlockNodeView = exports.MathInlineNodeView = exports.MathNodeView = void 0;
const prosemirror_keymap_1 = require("prosemirror-keymap");
const prosemirror_state_1 = require("prosemirror-state");
const prosemirror_view_1 = require("prosemirror-view");
const selection_1 = require("../../../utils/selection.js");
const commands_1 = require("./commands.js");
const const_1 = require("./const.js");
const hint_1 = require("./hint.js");
require("./view-and-edit.css");
const MATH_ACTIVE_DECO = 'math_active_decoration';
class MathNodeView {
    dom;
    contentDOM;
    node;
    texContent;
    mathViewDOM;
    mathHintContainerDOM;
    hintRendererItem;
    reactRenderer;
    loadRuntimeScript;
    katexRunOptions;
    hasActiveDeco = false;
    constructor(node, opts) {
        this.node = node;
        this.texContent = this.getTexContent();
        this.katexRunOptions = {
            ...opts.katexOptions,
            sanitize: opts.sanitize,
        };
        this.reactRenderer = opts.reactRenderer;
        this.loadRuntimeScript = opts.loadRuntimeScript;
        const elems = this.createDOM();
        this.dom = elems.dom;
        this.contentDOM = elems.contentDOM;
        this.mathViewDOM = elems.mathViewDOM;
        this.mathHintContainerDOM = elems.mathHintContainerDOM;
        this.hintRendererItem = elems.hintRendererItem;
        window.latexJsonp ??= [];
        this.loadRuntimeScript();
        this.renderKatex();
    }
    update(node, decos) {
        if (this.node.type !== node.type)
            return false;
        this.node = node;
        const isActive = decos.some((deco) => deco.spec[MATH_ACTIVE_DECO]);
        if (isActive === this.hasActiveDeco)
            return true;
        if (!isActive) {
            const newTexContent = this.getTexContent();
            if (this.texContent !== newTexContent) {
                this.texContent = newTexContent;
                this.renderKatex();
            }
        }
        this.hasActiveDeco = isActive;
        return true;
    }
    ignoreMutation(mutation) {
        if (mutation.type === 'selection' || mutation.type === 'attributes')
            return true;
        return (mutation.type === 'childList' &&
            (mutation.target === this.mathHintContainerDOM ||
                this.mathHintContainerDOM.contains(mutation.target) ||
                this.mathViewDOM.contains(mutation.target)));
    }
    destroy() {
        this.hintRendererItem.remove();
    }
    renderKatex() {
        const displayMode = this.isDisplayMode();
        const runOptions = { displayMode };
        const econtent = encodeURIComponent(this.texContent);
        const eoptions = encodeURIComponent(JSON.stringify(runOptions));
        const elem = document.createElement(displayMode ? 'p' : 'span');
        elem.classList.add('yfm-latex');
        elem.setAttribute('data-content', econtent);
        elem.setAttribute('data-options', eoptions);
        this.mathViewDOM.replaceChildren(elem);
        this.toggleErrorView(false);
        window.latexJsonp.push(async (api) => {
            try {
                await api.run({
                    ...this.katexRunOptions,
                    ...runOptions,
                    nodes: [elem],
                    throwOnError: true,
                });
            }
            catch (err) {
                const errorElem = document.createElement('span');
                errorElem.classList.add('math-error');
                errorElem.innerText = `(error) ${this.texContent}`;
                errorElem.title = String(err);
                this.mathViewDOM.replaceChildren(errorElem);
                this.toggleErrorView(true);
            }
        });
    }
    toggleErrorView(isError) {
        this.dom.classList.toggle('math-container-error', isError);
        this.mathViewDOM.classList.toggle('math-view-error', isError);
    }
    getTexContent() {
        return this.node.textContent;
    }
}
exports.MathNodeView = MathNodeView;
class MathInlineNodeView extends MathNodeView {
    destroy() {
        this.hintRendererItem?.remove();
    }
    isDisplayMode() {
        return false;
    }
    createDOM() {
        const dom = document.createElement('span');
        dom.classList.add('math-container', 'math-inline-container');
        const mathViewDOM = document.createElement('span');
        mathViewDOM.classList.add('math-view', 'math-inline-view');
        mathViewDOM.contentEditable = 'false';
        const mathInlineDOM = this.createMathInlineDOM();
        const mathHintContainerDOM = document.createElement('div');
        mathHintContainerDOM.contentEditable = 'false';
        mathHintContainerDOM.classList.add(...(0, hint_1.b)({ view: 'inline' }).split(' '));
        dom.appendChild(mathViewDOM);
        dom.appendChild(mathInlineDOM.container);
        dom.appendChild(mathHintContainerDOM);
        const hintRendererItem = this.reactRenderer.createItem('math-inline-hint', () => (0, hint_1.renderMathHint)({}, mathHintContainerDOM));
        return {
            dom,
            contentDOM: mathInlineDOM.content,
            mathViewDOM,
            mathHintContainerDOM,
            hintRendererItem,
        };
    }
    // same as math-inline spec toDOM()
    createMathInlineDOM() {
        const container = document.createElement('span');
        container.classList.add(const_1.CLASSNAMES.Inline.Container);
        const sharpBefore = document.createElement('span');
        sharpBefore.classList.add(const_1.CLASSNAMES.Inline.Sharp);
        sharpBefore.contentEditable = 'false';
        sharpBefore.textContent = '$';
        const sharpAfter = sharpBefore.cloneNode(true);
        const content = document.createElement('span');
        content.classList.add(const_1.CLASSNAMES.Inline.Content);
        container.replaceChildren(sharpBefore, content, sharpAfter);
        return { container, content };
    }
}
exports.MathInlineNodeView = MathInlineNodeView;
class MathBlockNodeView extends MathNodeView {
    isDisplayMode() {
        return true;
    }
    createDOM() {
        const dom = document.createElement('div');
        dom.classList.add('math-container', 'math-block-container');
        const mathViewDOM = document.createElement('div');
        mathViewDOM.classList.add('math-view', 'math-block-view');
        mathViewDOM.contentEditable = 'false';
        const contentDOM = document.createElement('div');
        contentDOM.classList.add('math-block');
        const mathHintContainerDOM = document.createElement('div');
        mathHintContainerDOM.contentEditable = 'false';
        mathHintContainerDOM.classList.add(...(0, hint_1.b)({ view: 'block' }).split(' '));
        dom.appendChild(mathHintContainerDOM);
        dom.appendChild(mathViewDOM);
        dom.appendChild(contentDOM);
        const hintRendererItem = this.reactRenderer.createItem('math-block-hint', () => (0, hint_1.renderMathHint)({}, mathHintContainerDOM));
        return { dom, contentDOM, mathViewDOM, mathHintContainerDOM, hintRendererItem };
    }
}
exports.MathBlockNodeView = MathBlockNodeView;
const mathViewAndEditPlugin = (options) => new prosemirror_state_1.Plugin({
    props: {
        handleKeyDown: (0, prosemirror_keymap_1.keydownHandler)({
            ArrowRight: commands_1.moveCursorRightOfMathInline,
            ArrowLeft: commands_1.moveCursorLeftOfMathInline,
        }),
        nodeViews: {
            [const_1.MathNode.Block]: (node) => new MathBlockNodeView(node, options),
            [const_1.MathNode.Inline]: (node) => new MathInlineNodeView(node, options),
        },
        decorations: (state) => {
            const { selection } = state;
            if ((0, selection_1.isTextSelection)(selection)) {
                const decorations = [];
                state.doc.nodesBetween(selection.from, selection.to, (node, pos) => {
                    const typeName = node.type.name;
                    if (typeName === const_1.MathNode.Inline || typeName === const_1.MathNode.Block) {
                        decorations.push(prosemirror_view_1.Decoration.node(pos, pos + node.nodeSize, {
                            class: 'math-active',
                        }, { [MATH_ACTIVE_DECO]: true }));
                    }
                });
                if (decorations.length) {
                    return prosemirror_view_1.DecorationSet.create(state.doc, decorations);
                }
            }
            return prosemirror_view_1.DecorationSet.empty;
        },
    },
});
exports.mathViewAndEditPlugin = mathViewAndEditPlugin;
//# sourceMappingURL=view-and-edit.js.map
