<template >
    <div>
        <div v-if="!isPreview" :class="`markdown ${fullscreen ? 'fullscreen' : ''} ${bordered ? 'border' : ''}`" ref="markdown" :style="{ width: width + 'px', height: height + 'px' }">
            <!-- 工具栏组件 -->
            <wk_tools @on-upload-image="upload_image" :fullscreen="fullscreen" :vm="this" :split='split' :scrolling="scrolling" ref="tools" :preview="preview" :toolbars="toolbars" :editor="editor"  @change_data="change_data" :lastPos="lastPos" :currentValue="currentValue" :exportFileName="exportFileName"></wk_tools>
            <!-- 关闭预览按钮 -->
            <div
                    class="close-preview"
                    v-show="preview && !isPreview"
                    @click="preview = false"
            >
                <span class="iconfont icon-close"></span>
            </div>
            <!-- 编辑器 -->
            <div
                    class="markdown-content"
                    :style="{ background: preview ? '#fff' : '' }"
            >
                <!-- codemirror 编辑器 -->
                <div
                        class="codemirror"
                        ref="codemirror"
                        id="edit"
                        v-show="!preview"
                        @mouseenter="mousescrollSide('left')"
                ></div>
                <!--  预览效果 -->
                <div
                        v-show="preview ? preview : split"
                        :class="`markdown-preview ${'markdown-theme-' + themeName}`"
                        ref="preview"
                        @scroll="previewScroll"
                        id="pdf"
                        @mouseenter="mousescrollSide('right')"
                >
                    <div v-html="html" ref="previewInner"></div>
                </div>
            </div>
            <!-- 弹窗 -->
            <alert  ref="dialog" :editor="editor" :vm="this" />
       </div>
        <!-- 设置时isPreview只显示预览-->
        <div v-else
                :class="`markdown-preview ${'markdown-theme-' + themeName}`"
        >
            <div v-html="html" ref="previewInner"></div>
        </div>
    </div>
</template>

<script>
    import './assets/css/reset.css'
    import Codemirror from 'codemirror';
    import codemirrorConfig from './assets/js/codemirror/config';

    import 'codemirror/lib/codemirror.css';
    import 'codemirror/addon/dialog/dialog.css';
    import 'codemirror/addon/search/matchesonscrollbar.css';

    import './assets/js/codemirror/mode/xml';
    import './assets/js/codemirror/mode/css';
    import './assets/js/codemirror/mode/javascript';
    import './assets/js/codemirror/mode/markdown';

    import './assets/js/codemirror/styles/codemirror.css';

    import marked from './config/marked';
    import alert from './components/alert';
    import wk_tools from './components/tools';
    import eventConfig from "./config/event";

    import  "codemirror/addon/fold/foldgutter.css"
    import  "codemirror/addon/dialog/dialog.css"
    import  "codemirror/theme/monokai.css"
    import "codemirror/addon/search/searchcursor.js"
    import "codemirror/addon/search/search.js"
    import "codemirror/addon/dialog/dialog.js"
    import "codemirror/addon/edit/matchbrackets.js"
    import "codemirror/addon/edit/closebrackets.js"
    import "codemirror/addon/comment/comment.js"
    import "codemirror/addon/wrap/hardwrap.js"
    import "codemirror/addon/fold/foldcode.js"
    import "codemirror/addon/fold/brace-fold.js"
    import "codemirror/mode/javascript/javascript.js"
    import "codemirror/keymap/sublime.js"

    export default {
        name: 'markdown_index',
        components:{
            alert,
            wk_tools
        },
        props: {
            value: {
                type: [String, Number],
                default: ''
            },
            themeName: {// 默认主题
                type: String,
                default: 'dark'
            },
            width: {// 初始化宽度
                type: [Number, String],
                default: 'auto'
            },
            height: {// 初始化高度
                type: Number,
                default: 600
            },
            toolbars: {// 工具栏
                type: Object,
                default() {
                    return {};
                }
            },
            bordered: {//是否有边框
                type: Boolean,
                default: true
            },
            autoSave: {// 是否自动保存
                type: Boolean,
                default: false
            },
            interval: {// 自动保存间隔 mm
                type: Number,
                default: 10000
            },
            exportFileName: {// 默认导出文件名称
                type: String,
                default: '我的文档'
            },
            markedOptions: {//marked.js配置项
                type: Object,
                default() {
                    return {};
                }
            },
            isPreview: {//是否是预览模式
                type: Boolean,
                default: false
            }
        },

        data() {
            return {
                editor: null, // 编辑器实例
                lastPos: '' ,// 光标最后所在位置,
                currentValue: '', // 输入框内容
                timeoutId: null,
                indexLenth: 1,
                html: '',// 预览的html
                preview: false, // 是否是预览状态
                split: true, //分屏显示
                fullscreen: false, // 是否是全屏
                scrollSide: '', // 哪个半栏在滑动
                timerId: null, // 定时器id
                scrolling: true, // 同步滚动
                editorScrollHeight: 0,
                eventConfig
            };
        },

        mounted() {
            this.init(); //初始化配置
            this.createEditor(); //实例化编辑器
        },
        computed:{
            instance(){
                return this.$refs.tools
            },
            alert(){
                return this.$refs.dialog
            },
        },
        methods: {
            upload_image(data){
                //让事件冒泡给
                this.$emit(eventConfig.imageUpload, data);
            },
            change_data(key,value){
                //动态设置值
                this[key]=value
            },
            init() {// 初始化
                this.currentValue = this.value; //这个属性在 common里配置 设置当前编辑器内容
                setTimeout(() => {
                    if (this.autoSave) { //如果配置了autoSave则定时保存
                        this.timerId = setInterval(() => {
                            this.handleSave();
                        }, this.interval);
                    }
                }, 20);
            },
            createEditor() {// 初始化左侧编辑器
                this.editor = new Codemirror(this.$refs.codemirror, {
                    value: this.currentValue,
                    onload: (data) => {
                        const {doc: {height = 0}} = data;
                        this.editorScrollHeight = height;
                    },
                    ...codemirrorConfig
                });

                this.addEditorLintener(); //设置监听器 当编辑器内容改变时触发操作
                //初始化完成
                this.$emit(eventConfig.ready, {
                    vm: this,
                })
            },
            addEditorLintener() {//绑定监听事件
                const editor = this.editor;
                editor.on('change', data => {
                    this.lastPos = editor.getCursor(); //保存编辑器游标
                    this.currentValue = editor.getValue(); //更新值
                    const {
                        doc: {height} //取得高度
                    } = data;
                    this.editorScrollHeight = height; //设置高度
                });

                editor.on('scroll', this.markdownScroll); //2个视窗都滚动
                editor.on('paste', this.handlePaste); //监听复制
                editor.on('keydown', (data, e) => {
                    if (e.keyCode === 83) {
                        if (e.metaKey || e.ctrlKey) {  //ctrl +s 保存
                            e.preventDefault();
                            this.handleSave();
                        }
                    } else if (e.keyCode === 13) {
                        this.listerenKeyupEnter(e); //回车事件 加入换行
                    } else if (e.keyCode === 8) {
                        this.listerenDelete(data); //删除事件  删除字符
                    }
                });
                editor.on('focus', () => {
                    this.lastPos = editor.getCursor(); //当失去焦点 再点击编辑器 更新此时点击的位置，更新游标
                });
            },

            setCursor(line = 0, ch = 0) {// 设置焦点
                const {editor} = this;  //设置游标 line是行 ch此行第几个字符
                editor.setCursor(line, ch); //游标更新
                editor.focus(); //触发focus 将更新的游标保存到lastPos中
            },
            handlePaste(_, e) {// 粘贴图片

                const {clipboardData = {}} = e;
                const {types = [], items} = clipboardData;
                let item = null;
                for (let i = 0; i < types.length; i++) {
                    if (types[i] === 'Files') {
                        item = items[i];
                        break;
                    }
                }
                if (item) {
                    const file = item.getAsFile();

                    if (/image/gi.test(file.type)) {

                        this.$emit(eventConfig.imageUpload, file);
                        e.preventDefault();
                    }
                }
            },

            listerenKeyupEnter(e) {// 回车事件
                const {lastInsert} = this.instance;
                if (lastInsert) {   //通过对比lastInsert的值 是否属于list内 然后处理 或者数字递增
                    const list = ['-', '- [ ]', '- [x]'];
                    if (list.includes(lastInsert.trim())) {
                        e.preventDefault();
                        this.instance.insertContent('\n' + lastInsert);
                    } else if (/^\d+\.$/.test(lastInsert.trim())) {
                        e.preventDefault();  //数字递增
                        this.instance.insertContent(
                            '\n' + (parseInt(lastInsert, 0) + 1) + '.  '
                        );
                    }
                }
            },
            listerenDelete() {// 删除 backup
                setTimeout(() => { //删除lastInsert的值
                    const {editor} = this;
                    if (!editor.isClean()) {
                        const value = editor.getValue();
                        if (value.split('\n').pop() === '') {
                            this.instance.lastInsert = '';
                        }
                    }
                }, 20);
            },
            markdownScroll(data = {}) {//编辑器区域滚动
                if (this.scrolling && this.scrollSide === 'left') {
                    const {
                        doc: {height, scrollTop}
                    } = data;
                    const preview = this.$refs.preview;
                    const contentHeight = preview.offsetHeight;
                    const previewScrollHeight = preview.scrollHeight;
                    preview.scrollTop = parseInt(
                        (scrollTop * (previewScrollHeight - contentHeight)) /
                        (height - contentHeight),
                        0
                    );
                }
            },
            previewScroll() {//预览内容区域滚动
                if (this.scrolling && this.scrollSide === 'right') {
                    const preview = this.$refs.preview;
                    const contentHeight = preview.offsetHeight;
                    const previewScrollHeight = preview.scrollHeight;
                    const previewScrollTop = preview.scrollTop;
                    const scrollTop = parseInt((previewScrollTop * (this.editorScrollHeight - contentHeight)) / (previewScrollHeight - contentHeight), 0);
                    this.editor.scrollTo(0, scrollTop);
                }
            },
            mousescrollSide(side) {// 设置究竟是哪个半边在主动滑动
                this.scrollSide = side;
            },
        },
        watch: {
            currentValue() {
                clearTimeout(this.timeoutId);
                this.timeoutId = setTimeout(() => {
                    const {currentValue} = this;
                    let html = marked(currentValue, {
                        sanitize: false,
                        ...this.markedOptions
                    }).replace(/href="/gi, 'target="_blank" href="');
                    if (this.copyCode && html !== '') {
                        html = html.replace(/<pre>/g, '<div class="code-block"><span class="copy-code">' + this.copyBtnText + '</span><pre>').replace(/<\/pre>/g, '</pre></div>')
                    }
                    this.html = html;
                    this.$emit('input', currentValue);
                }, 30);
            },
            value() {
                const {value, currentValue} = this;
                if (currentValue !== value) {// 由于用户输入而造成的value变化，不对editor设置值
                    this.currentValue = value;
                    this.editor.setOption('value', value);
                }
            },

        },
        destroyed() {// 销毁时清除定时器
            clearInterval(this.timerId);
        }
    };

</script>

<style scoped  lang="less">
    @import "./assets/font/iconfont.css";
    @import "./assets/css/theme";
    @import "./assets/css/light";
    @import "./assets/css/index";
    .editormd-code-toolbar {
        color: #999;
        font-size: 14px;
        margin: 10px;
        select {
            color: #999;
            padding: 3px 8px;
            border: 1px solid #ddd;
        }
        span{margin-right:10px}
    }
    .code_dialog_content{
        width: 100%;
        height: 450px;
        margin-bottom: 6px;
        overflow: auto;
        border: 1px solid #eee;
        background: #fff;
        padding: 15px;
        resize: none;
    }

    .href_dialog_item,.table_dialog_item{
        overflow: hidden;
        margin:20px;
        label{
            float: left;
            display: block;
            width: 75px;
            text-align: left;
            padding: 7px 0 15px 5px;
            margin: 0 0 2px;
            font-weight: normal;
            vertical-align: middle;
        }
        input{    color: #999;
            padding: 8px;
            border: 1px solid #ddd;
            display: inline-block;
            width: 264px;
        }
    }
    .table_dialog_item{
        input[type=number]{width:60px;text-align: center;margin:0 10px}
        label{float: right;vertical-align: baseline}
        input[type=radio]{width:auto;text-align: center;margin:0px 3px;vertical-align:middle;margin-top:-8px }
        .algin{
            float:left;
            margin-left:20px;
            vertical-align: baseline;
            strong{vertical-align: middle;font-weight: bold;margin-top:10px;display: inline-block;margin-right:10px}
        }
    }
    .table_dialog_table{
        h4{margin:10px;font-weight: bold}
       .table_header{
           width:100%;
           display: flex;
           .td{
               border:1px solid #ccc;
               text-align: left;
               flex:1;
               overflow: auto;
               input{width:100%;}
           }
       }
        .table_body_item{
            margin:5px 0;
            display: flex;
            .td{
                border:1px solid #ccc;
                text-align: left;
                flex:1;
                overflow: auto;
                textarea{width:100%;height: 40px;overflow: auto}
            }
        }

    }
    .common_dialog{
        pre{background:#eee;margin:5px 20px;padding:20px}
        .markdown-content{
            textarea{
                border: 1px solid #ccc;
                padding:10px;
                box-sizing: border-box;
                width:100%;
                height:280px;
            }
        }
        h5{margin:10px 0px;font-weight: bold}
    }
</style>
