'use strict';

Object.defineProperty(exports, "__esModule", {
    value: true
});

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _draftJs = require('draft-js');

var _immutable = require('immutable');

require('setimmediate');

var _Toolbar = require('../Toolbar');

var _ConfigStore = require('./ConfigStore');

var _ConfigStore2 = _interopRequireDefault(_ConfigStore);

var _getHTML = require('./export/getHTML');

var _getHTML2 = _interopRequireDefault(_getHTML);

var _exportText = require('./export/exportText');

var _exportText2 = _interopRequireDefault(_exportText);

var _customHTML2Content = require('./customHTML2Content');

var _customHTML2Content2 = _interopRequireDefault(_customHTML2Content);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }

function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); }

var hasCommandModifier = _draftJs.KeyBindingUtil.hasCommandModifier;

function noop() {}
;
var defaultPluginConfig = {};
var focusDummyStyle = {
    width: 0,
    opacity: 0,
    border: 0,
    position: 'absolute',
    left: 0,
    top: 0
};
var toolbar = (0, _Toolbar.createToolbar)();
var configStore = new _ConfigStore2["default"]();

var EditorCore = function (_React$Component) {
    _inherits(EditorCore, _React$Component);

    function EditorCore(props) {
        _classCallCheck(this, EditorCore);

        var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));

        _this.cancelForceUpdateImmediate = function () {
            clearImmediate(_this.forceUpdateImmediate);
            _this.forceUpdateImmediate = null;
        };
        _this.handlePastedText = function (text, html) {
            var editorState = _this.state.editorState;

            if (html) {
                var contentState = editorState.getCurrentContent();
                var selection = editorState.getSelection();
                var fragment = (0, _customHTML2Content2["default"])(html, contentState);
                var pastedContent = _draftJs.Modifier.replaceWithFragment(contentState, selection, fragment);
                var newContent = pastedContent.merge({
                    selectionBefore: selection,
                    selectionAfter: pastedContent.getSelectionAfter().set('hasFocus', true)
                });
                _this.setEditorState(_draftJs.EditorState.push(editorState, newContent, 'insert-fragment'), true);
                return 'handled';
            }
            return 'not-handled';
        };
        _this.plugins = (0, _immutable.List)((0, _immutable.List)(props.plugins).flatten(true));
        var editorState = void 0;
        if (props.value !== undefined) {
            if (props.value instanceof _draftJs.EditorState) {
                editorState = props.value || _draftJs.EditorState.createEmpty();
            } else {
                editorState = _draftJs.EditorState.createEmpty();
            }
        } else {
            editorState = _draftJs.EditorState.createEmpty();
        }
        editorState = _this.generatorDefaultValue(editorState);
        _this.state = {
            plugins: _this.reloadPlugins(),
            editorState: editorState,
            customStyleMap: {},
            customBlockStyleMap: {},
            compositeDecorator: null
        };
        if (props.value !== undefined) {
            _this.controlledMode = true;
            console.warn('this component is in controllred mode');
        }
        return _this;
    }

    EditorCore.ToEditorState = function ToEditorState(text) {
        var createEmptyContentState = _draftJs.ContentState.createFromText((0, _exportText.decodeContent)(text) || '');
        var editorState = _draftJs.EditorState.createWithContent(createEmptyContentState);
        return _draftJs.EditorState.forceSelection(editorState, createEmptyContentState.getSelectionAfter());
    };

    EditorCore.prototype.Reset = function Reset() {
        var defaultValue = this.props.defaultValue;

        var contentState = defaultValue ? defaultValue.getCurrentContent() : _draftJs.ContentState.createFromText('');
        var updatedEditorState = _draftJs.EditorState.push(this.state.editorState, contentState, 'remove-range');
        this.setEditorState(_draftJs.EditorState.forceSelection(updatedEditorState, contentState.getSelectionBefore()));
    };

    EditorCore.prototype.SetText = function SetText(text) {
        var createTextContentState = _draftJs.ContentState.createFromText(text || '');
        var editorState = _draftJs.EditorState.push(this.state.editorState, createTextContentState, 'change-block-data');
        this.setEditorState(_draftJs.EditorState.moveFocusToEnd(editorState), true);
    };

    EditorCore.prototype.getChildContext = function getChildContext() {
        return {
            getEditorState: this.getEditorState,
            setEditorState: this.setEditorState
        };
    };

    EditorCore.prototype.reloadPlugins = function reloadPlugins() {
        var _this2 = this;

        return this.plugins && this.plugins.size ? this.plugins.map(function (plugin) {
            //　如果插件有 callbacks 方法,则认为插件已经加载。
            if (plugin.callbacks) {
                return plugin;
            }
            // 如果插件有 constructor 方法,则构造插件
            if (plugin.hasOwnProperty('constructor')) {
                var pluginConfig = _extends(_this2.props.pluginConfig, plugin.config || {}, defaultPluginConfig);
                return plugin.constructor(pluginConfig);
            }
            // else 无效插件
            console.warn('>> 插件: [', plugin.name, '] 无效。插件或许已经过期。');
            return false;
        }).filter(function (plugin) {
            return plugin;
        }).toArray() : [];
    };

    EditorCore.prototype.componentWillMount = function componentWillMount() {
        var plugins = this.initPlugins().concat([toolbar]);
        var customStyleMap = {};
        var customBlockStyleMap = {};
        var customBlockRenderMap = (0, _immutable.Map)(_draftJs.DefaultDraftBlockRenderMap);
        var toHTMLList = (0, _immutable.List)([]);
        // initialize compositeDecorator
        var compositeDecorator = new _draftJs.CompositeDecorator(plugins.filter(function (plugin) {
            return plugin.decorators !== undefined;
        }).map(function (plugin) {
            return plugin.decorators;
        }).reduce(function (prev, curr) {
            return prev.concat(curr);
        }, []));
        // initialize Toolbar
        var toolbarPlugins = (0, _immutable.List)(plugins.filter(function (plugin) {
            return !!plugin.component && plugin.name !== 'toolbar';
        }));
        // load inline styles...
        plugins.forEach(function (plugin) {
            var styleMap = plugin.styleMap,
                blockStyleMap = plugin.blockStyleMap,
                blockRenderMap = plugin.blockRenderMap,
                toHtml = plugin.toHtml;

            if (styleMap) {
                for (var key in styleMap) {
                    if (styleMap.hasOwnProperty(key)) {
                        customStyleMap[key] = styleMap[key];
                    }
                }
            }
            if (blockStyleMap) {
                for (var _key in blockStyleMap) {
                    if (blockStyleMap.hasOwnProperty(_key)) {
                        customBlockStyleMap[_key] = blockStyleMap[_key];
                        customBlockRenderMap = customBlockRenderMap.set(_key, {
                            element: null
                        });
                    }
                }
            }
            if (toHtml) {
                toHTMLList = toHTMLList.push(toHtml);
            }
            if (blockRenderMap) {
                for (var _key2 in blockRenderMap) {
                    if (blockRenderMap.hasOwnProperty(_key2)) {
                        customBlockRenderMap = customBlockRenderMap.set(_key2, blockRenderMap[_key2]);
                    }
                }
            }
        });
        configStore.set('customStyleMap', customStyleMap);
        configStore.set('customBlockStyleMap', customBlockStyleMap);
        configStore.set('blockRenderMap', customBlockRenderMap);
        configStore.set('customStyleFn', this.customStyleFn.bind(this));
        configStore.set('toHTMLList', toHTMLList);
        this.setState({
            toolbarPlugins: toolbarPlugins,
            compositeDecorator: compositeDecorator
        });
        this.setEditorState(_draftJs.EditorState.set(this.state.editorState, { decorator: compositeDecorator }));
    };

    EditorCore.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
        if (this.forceUpdateImmediate) {
            this.cancelForceUpdateImmediate();
        }
        if (this.controlledMode) {
            var decorators = nextProps.value.getDecorator();
            var editorState = decorators ? nextProps.value : _draftJs.EditorState.set(nextProps.value, { decorator: this.state.compositeDecorator });
            this.setState({
                editorState: editorState
            });
        }
    };

    EditorCore.prototype.componentWillUnmount = function componentWillUnmount() {
        this.cancelForceUpdateImmediate();
    };
    //  处理　value　


    EditorCore.prototype.generatorDefaultValue = function generatorDefaultValue(editorState) {
        var defaultValue = this.props.defaultValue;

        if (defaultValue) {
            return defaultValue;
        }
        return editorState;
    };

    EditorCore.prototype.getStyleMap = function getStyleMap() {
        return configStore.get('customStyleMap');
    };

    EditorCore.prototype.setStyleMap = function setStyleMap(customStyleMap) {
        configStore.set('customStyleMap', customStyleMap);
        this.render();
    };

    EditorCore.prototype.initPlugins = function initPlugins() {
        var _this3 = this;

        var enableCallbacks = ['focus', 'getEditorState', 'setEditorState', 'getStyleMap', 'setStyleMap'];
        return this.getPlugins().map(function (plugin) {
            enableCallbacks.forEach(function (callbackName) {
                if (plugin.callbacks.hasOwnProperty(callbackName)) {
                    plugin.callbacks[callbackName] = _this3[callbackName].bind(_this3);
                }
            });
            return plugin;
        });
    };

    EditorCore.prototype.focusEditor = function focusEditor(ev) {
        this.refs.editor.focus(ev);
        if (this.props.readOnly) {
            this._focusDummy.focus();
        }
        if (this.props.onFocus) {
            this.props.onFocus(ev);
        }
    };

    EditorCore.prototype.focus = function focus(ev) {
        var _this4 = this;

        if (ev && ev.target === this._editorWrapper) {
            var editorState = this.state.editorState;

            var selection = editorState.getSelection();
            if (!selection.getHasFocus()) {
                if (selection.isCollapsed()) {
                    return this.setState({
                        editorState: _draftJs.EditorState.moveFocusToEnd(editorState)
                    }, function () {
                        _this4.focusEditor(ev);
                    });
                }
            }
        }
        this.focusEditor(ev);
    };

    EditorCore.prototype.getPlugins = function getPlugins() {
        return this.state.plugins.slice();
    };

    EditorCore.prototype.getEventHandler = function getEventHandler() {
        var _this5 = this;

        var enabledEvents = ['onUpArrow', 'onDownArrow', 'handleReturn', 'onFocus', 'onBlur', 'onTab', 'handlePastedText'];
        var eventHandler = {};
        enabledEvents.forEach(function (event) {
            eventHandler[event] = _this5.generatorEventHandler(event);
        });
        return eventHandler;
    };

    EditorCore.prototype.getEditorState = function getEditorState() {
        var needFocus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;

        if (needFocus) {
            this.refs.editor.focus();
        }
        return this.state.editorState;
    };

    EditorCore.prototype.setEditorState = function setEditorState(editorState) {
        var _this6 = this;

        var focusEditor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

        var newEditorState = editorState;
        this.getPlugins().forEach(function (plugin) {
            if (plugin.onChange) {
                var updatedEditorState = plugin.onChange(newEditorState);
                if (updatedEditorState) {
                    newEditorState = updatedEditorState;
                }
            }
        });
        if (this.props.onChange) {
            this.props.onChange(newEditorState);
            // close this issue https://github.com/ant-design/ant-design/issues/5788
            // when onChange not take any effect
            // `<Editor />` won't rerender cause no props is changed.
            // add an timeout here, 
            // if props.onChange not trigger componentWillReceiveProps,
            // we will force render Editor with previous editorState,
            if (this.controlledMode) {
                this.forceUpdateImmediate = setImmediate(function () {
                    return _this6.setState({
                        editorState: new _draftJs.EditorState(_this6.state.editorState.getImmutable())
                    });
                });
            }
        }
        if (!this.controlledMode) {
            this.setState({ editorState: newEditorState }, focusEditor ? function () {
                return setImmediate(function () {
                    return _this6.refs.editor.focus();
                });
            } : noop);
        }
    };

    EditorCore.prototype.handleKeyBinding = function handleKeyBinding(ev) {
        if (this.props.onKeyDown) {
            ev.ctrlKey = hasCommandModifier(ev);
            var keyDownResult = this.props.onKeyDown(ev);
            if (keyDownResult) {
                return keyDownResult;
            }
            return (0, _draftJs.getDefaultKeyBinding)(ev);
        }
        return (0, _draftJs.getDefaultKeyBinding)(ev);
    };

    EditorCore.prototype.handleKeyCommand = function handleKeyCommand(command) {
        if (this.props.multiLines) {
            return this.eventHandle('handleKeyBinding', command);
        }
        return command === 'split-block' ? 'handled' : 'not-handled';
    };

    EditorCore.prototype.getBlockStyle = function getBlockStyle(contentBlock) {
        var customBlockStyleMap = configStore.get('customBlockStyleMap');
        var type = contentBlock.getType();
        if (customBlockStyleMap.hasOwnProperty(type)) {
            return customBlockStyleMap[type];
        }
    };

    EditorCore.prototype.blockRendererFn = function blockRendererFn(contentBlock) {
        var blockRenderResult = null;
        this.getPlugins().forEach(function (plugin) {
            if (plugin.blockRendererFn) {
                var result = plugin.blockRendererFn(contentBlock);
                if (result) {
                    blockRenderResult = result;
                }
            }
        });
        return blockRenderResult;
    };

    EditorCore.prototype.eventHandle = function eventHandle(eventName) {
        var _props;

        var plugins = this.getPlugins();

        for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key3 = 1; _key3 < _len; _key3++) {
            args[_key3 - 1] = arguments[_key3];
        }

        for (var i = 0; i < plugins.length; i++) {
            var plugin = plugins[i];
            if (plugin.callbacks[eventName] && typeof plugin.callbacks[eventName] === 'function') {
                var _plugin$callbacks;

                var result = (_plugin$callbacks = plugin.callbacks)[eventName].apply(_plugin$callbacks, args);
                if (result === true) {
                    return 'handled';
                }
            }
        }
        return this.props.hasOwnProperty(eventName) && (_props = this.props)[eventName].apply(_props, args) === true ? 'handled' : 'not-handled';
    };

    EditorCore.prototype.generatorEventHandler = function generatorEventHandler(eventName) {
        var _this7 = this;

        return function () {
            for (var _len2 = arguments.length, args = Array(_len2), _key4 = 0; _key4 < _len2; _key4++) {
                args[_key4] = arguments[_key4];
            }

            return _this7.eventHandle.apply(_this7, [eventName].concat(args));
        };
    };

    EditorCore.prototype.customStyleFn = function customStyleFn(styleSet) {
        if (styleSet.size === 0) {
            return {};
        }
        var plugins = this.getPlugins();
        var resultStyle = {};
        for (var i = 0; i < plugins.length; i++) {
            if (plugins[i].customStyleFn) {
                var styled = plugins[i].customStyleFn(styleSet);
                if (styled) {
                    _extends(resultStyle, styled);
                }
            }
        }
        return resultStyle;
    };

    EditorCore.prototype.render = function render() {
        var _this8 = this;

        var _props2 = this.props,
            prefixCls = _props2.prefixCls,
            toolbars = _props2.toolbars,
            style = _props2.style,
            readOnly = _props2.readOnly;
        var _state = this.state,
            editorState = _state.editorState,
            toolbarPlugins = _state.toolbarPlugins;

        var customStyleMap = configStore.get('customStyleMap');
        var blockRenderMap = configStore.get('blockRenderMap');
        var eventHandler = this.getEventHandler();
        var Toolbar = toolbar.component;
        return _react2["default"].createElement(
            'div',
            { style: style, className: prefixCls + '-editor ' + (readOnly ? 'readonly' : ''), onClick: this.focus.bind(this) },
            _react2["default"].createElement(Toolbar, { editorState: editorState, prefixCls: prefixCls, className: prefixCls + '-toolbar', plugins: toolbarPlugins, toolbars: toolbars }),
            _react2["default"].createElement(
                'div',
                { className: prefixCls + '-editor-wrapper', ref: function ref(ele) {
                        return _this8._editorWrapper = ele;
                    }, style: style, onClick: function onClick(ev) {
                        return ev.preventDefault();
                    } },
                _react2["default"].createElement(_draftJs.Editor, _extends({}, this.props, eventHandler, { ref: 'editor', customStyleMap: customStyleMap, customStyleFn: this.customStyleFn.bind(this), editorState: editorState, handleKeyCommand: this.handleKeyCommand.bind(this), keyBindingFn: this.handleKeyBinding.bind(this), onChange: this.setEditorState.bind(this), blockStyleFn: this.getBlockStyle.bind(this), blockRenderMap: blockRenderMap, handlePastedText: this.handlePastedText, blockRendererFn: this.blockRendererFn.bind(this) })),
                readOnly ? _react2["default"].createElement('input', { style: focusDummyStyle, ref: function ref(ele) {
                        return _this8._focusDummy = ele;
                    }, onBlur: eventHandler.onBlur }) : null,
                this.props.children
            )
        );
    };

    return EditorCore;
}(_react2["default"].Component);

EditorCore.GetText = _exportText2["default"];
EditorCore.GetHTML = (0, _getHTML2["default"])(configStore);
EditorCore.defaultProps = {
    multiLines: true,
    plugins: [],
    prefixCls: 'rc-editor-core',
    pluginConfig: {},
    toolbars: [],
    spilitLine: 'enter'
};
EditorCore.childContextTypes = {
    getEditorState: _propTypes2["default"].func,
    setEditorState: _propTypes2["default"].func
};
exports["default"] = EditorCore;
module.exports = exports['default'];