"use strict";
/**
 *  Copyright (c) Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the license found in the
 *  LICENSE file in the root directory of this source tree.
 */
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
    if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
    return cooked;
};
Object.defineProperty(exports, "__esModule", { value: true });
var React = require("react");
var MD = require("markdown-it");
var react_redux_1 = require("react-redux");
var onHasCompletion_1 = require("./onHasCompletion");
var actions_1 = require("../../state/sessions/actions");
var reselect_1 = require("reselect");
var selectors_1 = require("../../state/sessions/selectors");
var EditorWrapper_1 = require("./EditorWrapper");
var styled_1 = require("../../styled");
var utils_1 = require("../../utils");
var md = new MD();
// const AUTO_COMPLETE_AFTER_KEY = /^[a-zA-Z0-9_@(]$/
var QueryEditor = /** @class */ (function (_super) {
    __extends(QueryEditor, _super);
    function QueryEditor(props) {
        var _this = _super.call(this, props) || this;
        _this.setRef = function (ref) {
            _this.node = ref;
        };
        _this.onKeyUp = function (_, event) {
            var code = event.keyCode;
            if (code === 86) {
                return;
            }
            if ((code >= 65 && code <= 90) || // letters
                (!event.shiftKey && code >= 48 && code <= 57) || // numbers
                (event.shiftKey && code === 189) || // underscore
                (event.shiftKey && code === 50) || // @
                (event.shiftKey && code === 57) // (
            ) {
                _this.editor.execCommand('autocomplete');
            }
        };
        _this.onEdit = function () {
            if (!_this.ignoreChangeEvent && _this.props.onChange) {
                _this.cachedValue = _this.editor.getValue();
                _this.props.onChange(_this.cachedValue);
            }
        };
        /**
         * Render a custom UI for CodeMirror's hint which includes additional info
         * about the type and description for the selected context.
         */
        _this.onHasCompletion = function (cm, data) {
            onHasCompletion_1.default(cm, data, _this.props.onHintInformationRender);
        };
        _this.closeCompletion = function () {
            if (_this.editor.state.completionActive &&
                typeof _this.editor.state.completionActive.close === 'function') {
                _this.editor.state.completionActive.close();
            }
        };
        // Keep a cached version of the value, this cache will be updated when the
        // editor is updated, which can later be used to protect the editor from
        // unnecessary updates during the update lifecycle.
        _this.cachedValue = props.value || '';
        if (_this.props.getRef) {
            _this.props.getRef(_this);
        }
        return _this;
    }
    QueryEditor.prototype.componentDidMount = function () {
        var _this = this;
        // Lazily require to ensure requiring GraphiQL outside of a Browser context
        // does not produce an error.
        var CodeMirror = require('codemirror');
        require('codemirror/addon/hint/show-hint');
        require('codemirror/addon/comment/comment');
        require('codemirror/addon/edit/matchbrackets');
        require('codemirror/addon/edit/closebrackets');
        require('codemirror/addon/fold/foldgutter');
        require('codemirror/addon/fold/brace-fold');
        require('codemirror/addon/search/search');
        require('codemirror/addon/search/searchcursor');
        require('codemirror/addon/search/jump-to-line');
        require('codemirror/addon/dialog/dialog');
        require('codemirror/addon/lint/lint');
        require('codemirror/keymap/sublime');
        require('codemirror/keymap/vim');
        require('codemirror-graphql/hint');
        require('codemirror-graphql/lint');
        require('codemirror-graphql/info');
        require('codemirror-graphql/jump');
        require('codemirror-graphql/mode');
        var gutters = [];
        gutters.push('CodeMirror-linenumbers');
        gutters.push('CodeMirror-foldgutter');
        this.editor = CodeMirror(this.node, {
            autofocus: !utils_1.isIframe() ? true : false,
            value: this.props.value || '',
            lineNumbers: true,
            tabSize: this.props.tabWidth || 2,
            indentWithTabs: this.props.useTabs || false,
            mode: 'graphql',
            theme: 'graphiql',
            keyMap: 'sublime',
            autoCloseBrackets: true,
            matchBrackets: true,
            showCursorWhenSelecting: true,
            readOnly: false,
            foldGutter: {
                minFoldSize: 4,
            },
            lint: {
                schema: this.props.schema,
            },
            hintOptions: {
                schema: this.props.schema,
                closeOnUnfocus: true,
                completeSingle: false,
            },
            info: {
                schema: this.props.schema,
                renderDescription: function (text) { return md.render(text); },
                onClick: this.props.onClickReference,
            },
            jump: {
                schema: this.props.schema,
                onClick: this.props.onClickReference,
            },
            gutters: gutters,
            extraKeys: {
                'Cmd-Space': function () { return _this.editor.showHint({ completeSingle: true }); },
                'Ctrl-Space': function () { return _this.editor.showHint({ completeSingle: true }); },
                'Alt-Space': function () { return _this.editor.showHint({ completeSingle: true }); },
                'Shift-Space': function () { return _this.editor.showHint({ completeSingle: true }); },
                'Cmd-Enter': function () {
                    if (_this.props.onRunQuery) {
                        _this.props.onRunQuery();
                    }
                },
                'Ctrl-Enter': function () {
                    if (_this.props.onRunQuery) {
                        _this.props.onRunQuery();
                    }
                },
                // Editor improvements
                'Ctrl-Left': 'goSubwordLeft',
                'Ctrl-Right': 'goSubwordRight',
                'Alt-Left': 'goGroupLeft',
                'Alt-Right': 'goGroupRight',
                'Cmd-F': 'findPersistent',
                'Ctrl-F': 'findPersistent',
            },
        });
        this.editor.on('change', this.onEdit);
        this.editor.on('keyup', this.onKeyUp);
        this.editor.on('hasCompletion', this.onHasCompletion);
        global.editor = this.editor;
        if (this.props.scrollTop) {
            this.scrollTo(this.props.scrollTop);
        }
    };
    QueryEditor.prototype.componentDidUpdate = function (prevProps) {
        var _this = this;
        var CodeMirror = require('codemirror');
        // Ensure the changes caused by this update are not interpretted as
        // user-input changes which could otherwise result in an infinite
        // event loop.
        this.ignoreChangeEvent = true;
        if (this.props.schema !== prevProps.schema) {
            this.editor.options.lint.schema = this.props.schema;
            this.editor.options.hintOptions.schema = this.props.schema;
            this.editor.options.info.schema = this.props.schema;
            this.editor.options.jump.schema = this.props.schema;
            CodeMirror.signal(this.editor, 'change', this.editor);
        }
        if (this.props.value !== prevProps.value &&
            this.props.value !== this.cachedValue) {
            this.cachedValue = this.props.value;
            this.editor.setValue(this.props.value);
        }
        this.ignoreChangeEvent = false;
        setTimeout(function () {
            if (_this.props.sessionId !== prevProps.sessionId) {
                if (_this.props.scrollTop) {
                    _this.scrollTo(_this.props.scrollTop);
                }
            }
        });
    };
    QueryEditor.prototype.UNSAFE_componentWillReceiveProps = function (nextProps) {
        if (this.props.sessionId !== nextProps.sessionId) {
            this.closeCompletion();
            this.updateSessionScrollTop();
            if (!utils_1.isIframe()) {
                this.editor.focus();
            }
        }
    };
    QueryEditor.prototype.scrollTo = function (y) {
        this.node.querySelector('.CodeMirror-scroll').scrollTop = y;
    };
    QueryEditor.prototype.updateSessionScrollTop = function () {
        if (this.props.setScrollTop && this.props.sessionId) {
            this.props.setScrollTop(this.props.sessionId, this.node.querySelector('.CodeMirror-scroll').scrollTop);
        }
    };
    QueryEditor.prototype.componentWillUnmount = function () {
        this.updateSessionScrollTop();
        this.editor.off('change', this.onEdit);
        this.editor.off('keyup', this.onKeyUp);
        this.editor.off('hasCompletion', this.onHasCompletion);
        this.editor = null;
    };
    QueryEditor.prototype.render = function () {
        return (<EditorWrapper_1.default>
        <Editor ref={this.setRef}/>
      </EditorWrapper_1.default>);
    };
    /**
     * Public API for retrieving the CodeMirror instance from this
     * React component.
     */
    QueryEditor.prototype.getCodeMirror = function () {
        return this.editor;
    };
    /**
     * Public API for retrieving the DOM client height for this component.
     */
    QueryEditor.prototype.getClientHeight = function () {
        return this.node && this.node.clientHeight;
    };
    return QueryEditor;
}(React.PureComponent));
exports.QueryEditor = QueryEditor;
var mapStateToProps = reselect_1.createStructuredSelector({
    value: selectors_1.getQuery,
    sessionId: selectors_1.getSelectedSessionIdFromRoot,
    scrollTop: selectors_1.getScrollTop,
    tabWidth: selectors_1.getTabWidth,
    useTabs: selectors_1.getUseTabs,
});
exports.default = react_redux_1.connect(mapStateToProps, { onChange: actions_1.editQuery, setScrollTop: actions_1.setScrollTop })(QueryEditor);
var Editor = styled_1.styled.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n  flex: 1 1 0%;\n  position: relative;\n\n  .CodeMirror {\n    width: 100%;\n    background: ", ";\n  }\n"], ["\n  flex: 1 1 0%;\n  position: relative;\n\n  .CodeMirror {\n    width: 100%;\n    background: ", ";\n  }\n"])), function (p) { return p.theme.editorColours.editorBackground; });
var templateObject_1;
//# sourceMappingURL=QueryEditor.jsx.map