"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const React = require("react");
const draft_js_1 = require("draft-js");
const Draft = require("draft-js");
const core_1 = require("./core");
const katex = require("katex");
class DraftEditor extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.editor = null;
        this.state = { editor_state: this.props.initial_state };
    }
    static serialize_state(editor_state) {
        return JSON.stringify(Draft.convertToRaw(editor_state.getCurrentContent()));
    }
    static deserialize_state(raw_content) {
        try {
            return draft_js_1.EditorState.createWithContent(Draft.convertFromRaw(JSON.parse(raw_content)), DraftEditor.decorator());
        }
        catch (e) {
            return DraftEditor.empty_state();
        }
    }
    static empty_state() {
        return draft_js_1.EditorState.createEmpty(DraftEditor.decorator());
    }
    onChange(new_editor_state, on_success) {
        if (this.props.editable) {
            this.setState(Object.assign({}, this.state, { editor_state: new_editor_state }), () => {
                if (on_success)
                    on_success();
                this.props.set_state(new_editor_state);
            });
        }
    }
    toggle_block_type(block_type) {
        this.onChange(draft_js_1.RichUtils.toggleBlockType(this.state.editor_state, block_type), () => this.editor.focus());
    }
    toggle_style(command) {
        this.handleKeyCommand(command);
    }
    handleKeyCommand(command) {
        let new_state = draft_js_1.RichUtils.handleKeyCommand(this.state.editor_state, command);
        if (new_state) {
            this.onChange(new_state, () => {
                this.editor.focus();
            });
            return "handled";
        }
        return "not-handled";
    }
    insert_media(contentState, url, url_type) {
        let selectionState = this.state.editor_state.getSelection();
        let new_content_state = contentState.createEntity(url_type, 'IMMUTABLE', { src: url });
        let entity_key = new_content_state.getLastCreatedEntityKey();
        let new_editor_state = draft_js_1.AtomicBlockUtils.insertAtomicBlock(this.state.editor_state, entity_key, ' ');
        // new_content_state = new_editor_state.getCurrentContent()
        // var anchorKey = selectionState.getAnchorKey();
        // var currentContentBlock = new_content_state.getBlockForKey(anchorKey)
        // let blockMap = new_content_state.getBlockMap()
        // let newBlockMap = currentContentBlock.getText() == "" ? blockMap.remove(currentContentBlock.getKey()) : blockMap
        // const newContentState = contentState.set('blockMap', newBlockMap) as ContentState;
        // let newEditorState = EditorState.createWithContent(newContentState)
        let newEditorState = new_editor_state;
        this.setState(Object.assign({}, this.state, { editor_state: newEditorState }), () => {
            this.props.set_state(new_editor_state);
        });
    }
    insert_link(contentState, url) {
        let contentStateWithEntity = contentState.createEntity('LINK', 'IMMUTABLE', { url: url });
        let entityKey = contentStateWithEntity.getLastCreatedEntityKey();
        let newEditorState = draft_js_1.RichUtils.toggleLink(this.state.editor_state, this.state.editor_state.getSelection(), entityKey);
        this.setState(Object.assign({}, this.state, { editor_state: newEditorState }), () => {
            this.props.set_state(newEditorState);
        });
    }
    render() {
        return (React.createElement("div", { className: "editor__inner" },
            this.props.editable ?
                React.createElement(SlideEditorButtonsBar, { toggle_style: (s) => this.toggle_style(s), toggle_block_type: (s) => this.toggle_block_type(s), insert_media: (url, url_type) => this.insert_media(this.state.editor_state.getCurrentContent(), url, url_type), insert_link: (url) => this.insert_link(this.state.editor_state.getCurrentContent(), url) })
                :
                    null,
            React.createElement("div", { className: "slide__text__editor" },
                React.createElement(draft_js_1.Editor, { editorState: this.state.editor_state, onBlur: () => { }, onChange: es => this.onChange(es), handleKeyCommand: (c) => this.handleKeyCommand(c), readOnly: !this.props.editable, blockRendererFn: mediaBlockRenderer(this.state.editor_state.getCurrentContent(), this.props.editable), ref: (editor) => this.editor = editor, spellCheck: true }))));
    }
}
DraftEditor.decorator = () => new draft_js_1.CompositeDecorator([
    {
        strategy: DraftEditor.findLinkentities,
        component: Link,
    },
]);
DraftEditor.findLinkentities = (contentBlock, callback) => {
    contentBlock.findEntityRanges((character) => {
        const entityKey = character.getEntity();
        return (entityKey !== null &&
            draft_js_1.Entity.get(entityKey).getType() === 'LINK');
    }, callback);
};
function mediaBlockRenderer(contentState, editable) {
    return (block) => {
        if (block.getType() === 'atomic') {
            return {
                component: Media(editable),
                editable: false,
            };
        }
        return null;
    };
}
class Math extends React.Component {
    constructor(props) {
        super(props);
    }
    onClick() {
        if (!this.props.editable) {
            return;
        }
        let block = this.props.block;
        let contentState = this.props.contentState;
        let newTex = prompt("Enter your tex here", this.props.src) || this.props.src;
        let entityKey = block.getEntityAt(0);
        contentState.mergeEntityData(entityKey, { src: newTex });
    }
    render() {
        return React.createElement("div", null,
            React.createElement(MathOutput, { content: this.props.src, onClick: () => this.onClick() }));
    }
}
class MathOutput extends React.Component {
    constructor(props) {
        super(props);
        this._timer = null;
        this._container = null;
    }
    _update() {
        if (this._timer) {
            clearTimeout(this._timer);
        }
        this._timer = setTimeout(() => {
            katex.render(this.props.content, this._container, { displayMode: false });
        }, 0);
    }
    componentDidMount() {
        this._update();
    }
    componentWillReceiveProps(props) {
        if (props.src !== this.props.content) {
            this._update();
        }
    }
    componentWillUnmount() {
        clearTimeout(this._timer);
        this._timer = null;
    }
    render() {
        return React.createElement("span", { ref: (c) => this._container = c, onClick: this.props.onClick });
    }
}
const Image = (props) => {
    return React.createElement("img", { src: props.src });
};
const Video = (props) => {
    return React.createElement("video", { controls: true, src: props.src });
};
const YouTube = (props) => {
    return (React.createElement("iframe", { width: "420", height: "315", src: props.src }));
};
const Link = (props) => {
    const { url } = draft_js_1.Entity.get(props.entityKey).getData();
    return (React.createElement("a", { href: url }, props.children));
};
let Media = (editable) => (props) => {
    let entity = props.contentState.getEntity(props.block.getEntityAt(0));
    let { src } = entity.getData();
    let type = entity.getType();
    if (type === 'image') {
        return React.createElement(Image, { src: src });
    }
    else if (type === 'video') {
        return React.createElement(Video, { src: src });
    }
    else if (type === 'youtube') {
        return React.createElement(YouTube, { src: src });
    }
    else if (type === 'mathblock') {
        return React.createElement(Math, { src: src, editable: editable, contentState: props.contentState, block: props.block });
    }
    return null;
};
class SlideEditorButtonsBar extends React.Component {
    constructor(props, context) {
        super(props, context);
    }
    render() {
        return (React.createElement("div", { style: { display: "inline-block" }, className: "text-editor__menu-bar" },
            React.createElement("div", { className: "text-editor__menu-group" },
                React.createElement("button", { className: "text-editor__menu-button text-editor__menu-button--bold", onClick: () => this.props.toggle_style('bold') }),
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--italic`, onClick: () => this.props.toggle_style('italic') }),
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--underline`, onClick: () => this.props.toggle_style('underline') })),
            React.createElement("div", { className: "text-editor__menu-group" },
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--h1`, onClick: () => this.props.toggle_block_type('header-one') }),
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--h2`, onClick: () => this.props.toggle_block_type('header-two') }),
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--h3`, onClick: () => this.props.toggle_block_type('header-three') })),
            React.createElement("div", { className: "text-editor__menu-group" },
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--ul`, onClick: () => this.props.toggle_block_type('unordered-list-item') }),
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--ol`, onClick: () => this.props.toggle_block_type('ordered-list-item') })),
            React.createElement("div", { className: "text-editor__menu-group" },
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--code`, onClick: () => this.props.toggle_block_type('code-block') }),
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--blockquote`, onClick: () => this.props.toggle_block_type('blockquote') }),
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--latex`, onClick: () => this.props.insert_media(prompt("Insert your latex code here"), "mathblock") }),
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--image`, onClick: () => this.file_input.click() }),
                React.createElement("button", { className: `text-editor__menu-button text-editor__menu-button--link`, onClick: () => this.props.insert_link(prompt("Insert your link here")) })),
            React.createElement("input", { type: "file", onChange: (e) => {
                    let file = e.target.files[0];
                    if (!file)
                        return;
                    let reader = new FileReader();
                    reader.onload = (e) => {
                        let contents = e.target.result;
                        this.props.insert_media(contents, "image");
                    };
                    reader.readAsDataURL(file);
                }, ref: (file_input) => this.file_input = file_input, style: { display: "none" } })));
    }
}
class RichText extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.state = { current_state: props.json_state };
    }
    componentWillReceiveProps(new_props) {
        let new_state = new_props.json_state;
        if (this.state.current_state != new_state) {
            this.setState(Object.assign({}, this.state, { current_state: new_state }), () => this.props.cont(() => { })(this.state.current_state));
        }
    }
    componentWillMount() {
        this.props.cont(() => { })(this.state.current_state);
    }
    render() {
        return React.createElement(DraftEditor, { initial_state: this.state.current_state ?
                DraftEditor.deserialize_state(this.state.current_state) :
                DraftEditor.empty_state(), set_state: (s, on_success) => {
                let new_state = DraftEditor.serialize_state(s);
                if (this.state.current_state != new_state) {
                    this.setState(Object.assign({}, this.state, { current_state: new_state }), () => this.props.cont(() => { })(this.state.current_state));
                }
            }, editable: this.props.mode == "edit" });
    }
}
function rich_text(mode, key, dbg) {
    return json_state => core_1.make_C(ctxt => cont => (React.createElement(RichText, { kind: "rich text", debug_info: dbg, json_state: json_state, mode: mode, context: ctxt, cont: cont, key: key })));
}
exports.rich_text = rich_text;
//# sourceMappingURL=rich_text.js.map