<template>
    <div style="border: 1px solid #ccc;">
        <Toolbar style="border-bottom: 1px solid #ccc" :editor="editor" :defaultConfig="toolbarConfig" :mode="mode" />
        <Editor style="height: 500px; overflow-y: hidden;" v-model="html" :defaultConfig="editorConfig" :mode="mode"
            @onChange="onChange" @onCreated="onCreated" @onFocus="handleFocus" />
        <el-dialog title="添加画像标签字段" :visible.sync="labelshow" width="40%" :before-close="beforeClose">
            <el-cascader-panel :options="labeloptions" @change="panelchange" v-if="labelshow"
                :props="{ value: 'labelFieldId', label: 'fieldName', children: 'labelFieldContentList' }"></el-cascader-panel>
            <div>
                <div style="margin: 20px 0;">结果预览:</div>
                <el-input type="textarea" v-model="addnode.fileSpan" disabled></el-input>
            </div>
            <div slot="footer" class="dialog-footer">
                <el-button @click="labelclick" type="primary">确定</el-button>
            </div>
        </el-dialog>
        <el-dialog title="添加知识库字段" :visible.sync="fieldshow" width="40%" :before-close="beforeClose">
            <el-cascader-panel :options="fieldoptions" @change="panelchange" v-if="fieldshow"
                :props="{ value: 'labelFieldId', label: 'fieldName', children: 'labelFieldContentList' }"></el-cascader-panel>
            <div>
                <div style="margin: 20px 0;">结果预览:</div>
                <el-input type="textarea" v-model="addnode.fileSpan" disabled></el-input>
            </div>
            <div slot="footer" class="dialog-footer">
                <el-button @click="fieldclick" type="primary">确定</el-button>
            </div>
        </el-dialog>
    </div>
</template>

<script>
import { DomEditor, IDomEditor, SlateElement, SlateDescendant, SlateTransforms, SlateEditor, SlateNode } from '@wangeditor/editor'
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { Boot } from '@wangeditor/editor'
import { h, VNode } from 'snabbdom'
import {
    labelFieldList
} from '@/api/system/wangEditor.js'
// import menuConf from "./ModalMenu";
import { getToken } from "@/utils/auth";

var that
export default ({
    props: ['nodeContent'],
    components: { Editor, Toolbar },
    name: 'wangEditor',
    data() {
        return {
            labeloptions: [],
            fieldoptions: [],
            labelshow: false,
            fieldshow: false,
            editor: null,
            menukeys: null,
            toolbarConfig: {
                insertKeys: {
                    index: 61,
                    keys: ['MyButtonMenu3', 'MyButtonMenu4']
                },
                excludeKeys: [
                    'fullScreen',
                    'insertLink',
                    'codeBlock',
                    'todo',
                    'insertVideo',
                    'insertImage'
                ],
            },
            editorConfig: {
                placeholder: '请输入内容...',
                MENU_CONF: {
                    uploadImage: {
                        server: process.env.VUE_APP_BASE_API + '/common/richTextPictureUrl',
                        headers: {
                            Authorization: "Bearer " + getToken()
                        },
                        fieldName: "file", // 这里有个坑，如果返回的响应结果是没有上传文件，跟这里关系很大
                        customInsert(res, insertFn) {
                            if (res.code == 200) {
                                insertFn(res.url, null, null);
                            }
                        },
                    },
                },
            },
            mode: 'simple', // or 'simple'
            timer: '',
            html: `<p></p>`,
            addnode: {
                fileName: '',
                fileSpan: '',
                fieldMark: "",
            },
            modify: false,
        }
    },
    methods: {
        disable() {
            this.editor.disable()
        },
        emit() {
            this.$emit("on-nodeContent", { nodeContent: this.html });
        },
        panelchange(item) {
            if (this.labelshow) {
                this.labeloptions.forEach(e => {
                    e.labelFieldContentList.forEach(el => {
                        if (el.labelFieldId == item[1]) {
                            this.addnode.fileSpan = el.fieldName
                            this.addnode.fileName = e.fieldName
                            this.addnode.fieldMark = el.fieldMark
                        }
                    })
                })
            } else if (this.fieldshow) {
                this.fieldoptions.forEach(e => {
                    e.labelFieldContentList.forEach(el => {
                        if (el.labelFieldId == item[1]) {
                            this.addnode.fileSpan = el.fieldName
                            this.addnode.fileName = e.fieldName
                            this.addnode.fieldMark = el.fieldMark
                        }
                    })
                })
            }
        },
        labelclick() {
            this.labelshow = false
            setTimeout(() => {
                this.editor.focus()
            }, 30);
            setTimeout(() => {
                if (this.modify) {
                    this.modify = false
                    this.editor.deleteBackward();
                }
                const resume = {                    // JS 语法
                    type: 'attachment',
                    link: '',
                    fileName: this.addnode.fileName,
                    fieldMark: this.addnode.fieldMark,
                    fileSpan: this.addnode.fileSpan,
                    children: [{ text: '' }],  // void 元素必须有一个 children ，其中只有一个空字符串，重要！！！
                }
                this.editor.insertNode(resume)
                this.addnode = {
                    fileName: '',
                    fileSpan: '',
                    fieldMark: "",
                }
                this.editor.focus()
            }, 100);
        },
        fieldclick() {
            this.fieldshow = false
            setTimeout(() => {
                this.editor.focus()
            }, 30);
            setTimeout(() => {
                if (this.modify) {
                    this.modify = false
                    this.editor.deleteBackward();
                }
                const resume = {                    // JS 语法
                    type: 'attachmenttwo',
                    link: '',
                    fileName: this.addnode.fileName,
                    fieldMark: this.addnode.fieldMark,
                    fileSpan: this.addnode.fileSpan,
                    children: [{ text: '' }],  // void 元素必须有一个 children ，其中只有一个空字符串，重要！！！
                }
                this.editor.insertNode(resume)
                this.addnode = {
                    fileName: '',
                    fileSpan: '',
                    fieldMark: "",
                }
                this.editor.focus()
            }, 100);
        },
        onCreated(editor) {
            this.editor = Object.seal(editor);
        },
        onChange(editor) {
            // console.log("onChange", editor.getHtml()); // onChange 时获取编辑器最新内容
        },
        handleFocus(editor) {
            // console.log("focus", editor);
        },
        info() {
            labelFieldList('PORTRAIT_LABEL_FIELD').then(res => {
                res.data.data.forEach(e => {
                    e.labelFieldContentList.forEach(el => {
                        el.labelFieldId = el.labelFieldContentId
                    })
                })
                this.labeloptions = res.data.data
            })
            labelFieldList('KNOWLEDGE_FIELD').then(res => {
                res.data.data.forEach(e => {
                    e.labelFieldContentList.forEach(el => {
                        el.labelFieldId = el.labelFieldContentId
                    })
                })
                this.fieldoptions = res.data.data
            })
        },
        beforeClose() {
            this.modify = false
            this.fieldshow = false
            this.labelshow = false
        },
    },
    watch: {
        nodeContent(newValue, oldValue) {
            this.html = newValue;
        }
    },
    mounted() {
        this.html = this.nodeContent
    },
    beforeDestroy() {
        const editor = this.editor
        if (editor == null) return
        editor.destroy() // 组件销毁时，及时销毁编辑器
    },
    created() {
        that = this
        this.info();
    }
})
class MyButtonMenu3 {                       // JS 语法
    constructor(vueInstance) {
        this.vueInstance = vueInstance
        this.title = '添加画像标签字段'
        this.iconSvg = '<svg t="1711951668796" class="icon" viewBox="0 0 1119 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4490" xmlns:xlink="http://www.w3.org/1999/xlink" width="218.5546875" height="200"><path d="M25.415082 562.922053a25.1989 25.1989 0 0 1-17.745705-43.299519L542.347456 7.392772A25.110172 25.110172 0 1 1 577.040308 43.682738L42.894601 555.9125a25.110172 25.110172 0 0 1-17.479519 7.009553z" p-id="4491"></path><path d="M1094.061411 562.922053a25.110172 25.110172 0 0 1-17.745704-7.009553L542.347456 43.682738A25.110172 25.110172 0 1 1 577.040308 7.392772l534.323165 512.229762a25.1989 25.1989 0 0 1-17.745704 43.299519zM559.738247 1023.955458a380.467906 380.467906 0 0 1-380.024264-380.112992 25.1989 25.1989 0 0 1 50.309073 0 330.070105 330.070105 0 0 0 329.715191 329.80392 25.1989 25.1989 0 1 1 0 50.309072z" p-id="4492"></path><path d="M1009.769315 799.472295H618.3878a25.1989 25.1989 0 0 1 0-50.309072h391.381515a25.1989 25.1989 0 0 1 0 50.309072z" fill="#231815" p-id="4493"></path><path d="M814.122922 996.005974a25.1989 25.1989 0 0 1-25.198901-25.198901V579.869201a25.1989 25.1989 0 1 1 50.309073 0v390.937872a25.1989 25.1989 0 0 1-25.110172 25.198901z" fill="#231815" p-id="4494"></path></svg>'
        this.tag = 'button'
        this.showModal = true
    }
    // 菜单是否需要激活（如选中加粗文本，“加粗”菜单会激活），用不到则返回 false
    isActive(editor) {
        return false;
    }
    // 获取菜单执行时的 value ，用不到则返回空 字符串或 false
    getValue(editor) {
        return "";
    }
    // 菜单是否需要禁用（如选中 H1 ，“引用”菜单被禁用），用不到则返回 false
    isDisabled(editor) {
        return false;
    }
    // 点击菜单时触发的函数
    exec(editor, value) {
        this.vueInstance.labelshow = true
    }
}
class MyButtonMenu4 {                       // JS 语法
    constructor(vueInstance) {
        this.vueInstance = vueInstance
        this.title = '添加知识库字段'
        this.iconSvg = '<svg t="1711422779479" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2507" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M831.6 639.6h-63.9v127.9H639.9v63.9h127.8v127.9h63.9V831.4h127.9v-63.9H831.6z" p-id="2508"></path><path d="M564.3 925.2c0-18.5-15-33.6-33.6-33.6H287.3c-86.2 0-156.4-70.2-156.4-156.4V286.9c0-86.2 70.1-156.4 156.4-156.4h448.4c86.2 0 156.4 70.2 156.4 156.4v238.8c0 18.5 15 33.6 33.6 33.6s33.6-15 33.6-33.6V286.9C959.2 163.6 859 63.3 735.7 63.3H287.3C164 63.3 63.7 163.6 63.7 286.8v448.3c0 123.2 100.3 223.5 223.6 223.5h243.4c18.6 0.1 33.6-14.9 33.6-33.4z" p-id="2509"></path></svg>'
        this.tag = 'button'
        this.showModal = true
    }
    // 菜单是否需要激活（如选中加粗文本，“加粗”菜单会激活），用不到则返回 false
    isActive(editor) {
        return false;
    }
    // 获取菜单执行时的 value ，用不到则返回空 字符串或 false
    getValue(editor) {
        return "";
    }
    // 菜单是否需要禁用（如选中 H1 ，“引用”菜单被禁用），用不到则返回 false
    isDisabled(editor) {
        return false;
    }
    // 点击菜单时触发的函数
    exec(editor, value) {
        this.vueInstance.fieldshow = true
    }
}
const menuConf = {
    key: 'MyButtonMenu3', // 定义 menu key ：要保证唯一、不重复（重要）
    factory() {
        return new MyButtonMenu3(that)
    },
};
const menuConftwo = {
    key: 'MyButtonMenu4', // 定义 menu key ：要保证唯一、不重复（重要）
    factory() {
        return new MyButtonMenu4(that)
    },
};
const module = {                      // JS 语法
    menus: [menuConf, menuConftwo],
    // 其他功能，下文讲解...
}
Boot.registerModule(module)
function withAttachment(editor) {                        // JS 语法
    const { isInline, isVoid } = editor
    const newEditor = editor
    newEditor.isInline = elem => {
        const type = DomEditor.getNodeType(elem)
        if (type === 'attachment') return true // 针对 type: attachment ，设置为 inline
        if (type === 'attachmenttwo') return true // 针对 type: attachment ，设置为 inline
        return isInline(elem)
    }
    newEditor.isVoid = elem => {
        const type = DomEditor.getNodeType(elem)
        if (type === 'attachment') return true // 针对 type: attachment ，设置为 void
        if (type === 'attachmenttwo') return true // 针对 type: attachment ，设置为 void
        return isVoid(elem)
    }
    return newEditor // 返回 newEditor ，重要！！！
}
Boot.registerPlugin(withAttachment)
function renderAttachment(elem, children, editor) {                                                // JS 语法
    // 获取“附件”的数据，参考上文 myResume 数据结构
    const { fileName = '', link = '', fileSpan = '', fieldMark = '' } = elem
    // 附件 icon 图标 vnode
    const iconVnode = h(
        // HTML tag
        'span',
        // HTML 属性
        {
            props: {}, // HTML 属性，驼峰式写法
            style: { width: '16px', height: '16px', margin: '0 0 0 6px', display: 'inline-block', transform: 'translateY(20%)', backgroundSize: '100% 100%', backgroundImage: 'url(data:image/png;base64, )',  /* 其他... */ }, // HTML style ，驼峰式写法
            on: {
                click() {
                    editor.deleteBackward();
                } /* 其他... */
            }
        }
        // img 没有子节点，所以第三个参数不用写
    )
    const nameiconVnode = h(
        // HTML tag
        'span',
        // HTML 属性
        {
            props: {}, // HTML 属性，驼峰式写法
            style: { width: '16px', height: '16px', margin: '0 0 0 6px', display: 'inline-block', transform: 'translateY(20%)', backgroundSize: '100% 100%', backgroundImage: 'url(data:image/png;base64, )',  /* 其他... */ }, // HTML style ，驼峰式写法
            on: {
                click() {
                    that.modify = true
                    that.labelshow = true
                } /* 其他... */
            }
        }
        // img 没有子节点，所以第三个参数不用写
    )
    const spanVnode = h(
        // HTML tag
        'span',
        // HTML 属性
        {
            props: { contentEditable: false }, // HTML 属性，驼峰式写法
            style: { color: '#22343C', background: '#E5F5F2', padding: '5px 10px' /* 其他... */ }, // style ，驼峰式写法
            on: { click() { }, /* 其他... */ }
        },
        // img 没有子节点，所以第三个参数不用写
        [fileSpan]
    )
    const nameVnode = h(
        // HTML tag
        'span',
        // HTML 属性
        {
            props: { contentEditable: false }, // HTML 属性，驼峰式写法
            style: { color: '#fff', background: '#009A82', padding: '5px 10px' /* 其他... */ }, // style ，驼峰式写法
            on: { click() { }, /* 其他... */ }
        },
        // img 没有子节点，所以第三个参数不用写
        [fileName]
    )
    // 附件元素 vnode
    const attachVnode = h(
        // HTML tag
        'span',
        // HTML 属性、样式、事件
        {
            props: { contentEditable: false, class: 'text' }, // HTML 属性，驼峰式写法
            style: {}, // style ，驼峰式写法
            on: {
                click() { } /* 其他... */
            }
        },
        // 子节点
        [nameVnode, spanVnode]
    )
    return attachVnode
}
function renderAttachmenttwo(elem, children, editor) {                                                // JS 语法
    // 获取“附件”的数据，参考上文 myResume 数据结构
    const { fileName = '', link = '', fileSpan = '', fieldMark = '' } = elem
    // 附件 icon 图标 vnode
    const iconVnode = h(
        // HTML tag
        'span',
        // HTML 属性
        {
            props: {}, // HTML 属性，驼峰式写法
            style: { width: '16px', height: '16px', margin: '0 0 0 6px', display: 'inline-block', transform: 'translateY(20%)', backgroundSize: '100% 100%', backgroundImage: 'url(data:image/png;base64, )',  /* 其他... */ }, // HTML style ，驼峰式写法
            on: {
                click() {
                    editor.deleteBackward();
                } /* 其他... */
            }
        }
        // img 没有子节点，所以第三个参数不用写
    )
    const nameiconVnode = h(
        // HTML tag
        'span',
        // HTML 属性
        {
            props: {}, // HTML 属性，驼峰式写法
            style: { width: '16px', height: '16px', margin: '0 0 0 6px', display: 'inline-block', transform: 'translateY(20%)', backgroundSize: '100% 100%', backgroundImage: 'url(data:image/png;base64, )',  /* 其他... */ }, // HTML style ，驼峰式写法
            on: {
                click() {
                    that.modify = true
                    that.fieldshow = true
                } /* 其他... */
            }
        }
        // img 没有子节点，所以第三个参数不用写
    )
    const spanVnode = h(
        // HTML tag
        'span',
        // HTML 属性
        {
            props: { contentEditable: false }, // HTML 属性，驼峰式写法
            style: { color: '#22343C', background: '#DAE1FB', padding: '5px 10px' /* 其他... */ }, // style ，驼峰式写法
            on: { click() { }, /* 其他... */ }
        },
        // img 没有子节点，所以第三个参数不用写
        [fileSpan]
    )
    const nameVnode = h(
        // HTML tag
        'span',
        // HTML 属性
        {
            props: { contentEditable: false }, // HTML 属性，驼峰式写法
            style: { color: '#fff', background: '#436AE9', padding: '5px 10px' /* 其他... */ }, // style ，驼峰式写法
            on: { click() { }, /* 其他... */ }
        },
        // img 没有子节点，所以第三个参数不用写
        [fileName]
    )
    // 附件元素 vnode
    const attachVnode = h(
        // HTML tag
        'span',
        // HTML 属性、样式、事件
        {
            props: { contentEditable: false, class: 'text' }, // HTML 属性，驼峰式写法
            style: {}, // style ，驼峰式写法
            on: {
                click() { } /* 其他... */
            }
        },
        // 子节点
        [nameVnode, spanVnode]
    )
    return attachVnode
}
const renderElemConf = {
    type: 'attachment', // 新元素 type ，重要！！！
    renderElem: renderAttachment,
}
const renderElemConftwo = {
    type: 'attachmenttwo', // 新元素 type ，重要！！！
    renderElem: renderAttachmenttwo,
}

const rendermodule = {                      // JS 语法
    // menus: [menu1Conf, menu2Conf, menu3Conf], // 菜单
    // editorPlugin: withBreakAndDelete, // 插件
    renderElems: [renderElemConf, renderElemConftwo/* 其他元素... */] // renderElem

    // 其他功能，下文讲解...
}
Boot.registerModule(rendermodule)
function attachmentToHtml(elem, childrenHtml) {         // JS 语法
    // 获取附件元素的数据
    const { link = '', fileName = '', fileSpan = '', fieldMark = '' } = elem
    // 生成 HTML 代码
    const html = `<span data-w-e-type="attachment"
        data-w-e-is-void
        data-w-e-is-inline
        data-link="${link}"
        data-fileSpan="${fileSpan}"
        data-fieldMark="${fieldMark}"
        data-fileName="${fileName}">
        <span  class="path-tag-wrap">
            <span>${fileName}</span>
            <span>${fileSpan}</span>
        </span>
    </span>`
    return html
}
function attachmentToHtmltwo(elem, childrenHtml) {         // JS 语法
    // 获取附件元素的数据
    const { link = '', fileName = '', fileSpan = '', fieldMark = '' } = elem
    // 生成 HTML 代码
    const html = `<span data-w-e-type="attachmenttwo"
        data-w-e-is-void
        data-w-e-is-inline
        data-link="${link}"
        data-fileSpan="${fileSpan}"
        data-fieldMark="${fieldMark}"
        data-fileName="${fileName}">
        <span  class="path-tag-wrap">
            <span>${fileName}</span>
            <span>${fileSpan}</span>
        </span>
    </span>`
    return html
}
const elemToHtmlConf = {
    type: 'attachment', // 新元素的 type ，重要！！！
    elemToHtml: attachmentToHtml,
}
const elemToHtmlConftwo = {
    type: 'attachmenttwo', // 新元素的 type ，重要！！！
    elemToHtml: attachmentToHtmltwo,
}
const elemToHtmlConfmodule = {                      // JS 语法
    elemsToHtml: [elemToHtmlConf, elemToHtmlConftwo /* 其他元素... */]  // elemToHtml
}
Boot.registerModule(elemToHtmlConfmodule)
function parseAttachmentHtml(domElem, children, editor) {                                                     // JS 语法
    // 从 DOM element 中获取“附件”的信息
    const link = domElem.getAttribute('data-link') || ''
    const fileName = domElem.getAttribute('data-fileName') || ''
    const fileSpan = domElem.getAttribute('data-fileSpan') || ''
    const fieldMark = domElem.getAttribute('data-fieldMark') || ''
    // 生成“附件”元素（按照此前约定的数据结构）
    const myResume = {
        type: 'attachment',
        link,
        fileName,
        fileSpan,
        fieldMark,
        children: [{ text: '' }], // void node 必须有 children ，其中有一个空字符串，重要！！！
    }
    return myResume
}
function parseAttachmentHtmltwo(domElem, children, editor) {                                                     // JS 语法
    // 从 DOM element 中获取“附件”的信息
    const link = domElem.getAttribute('data-link') || ''
    const fileName = domElem.getAttribute('data-fileName') || ''
    const fileSpan = domElem.getAttribute('data-fileSpan') || ''
    const fieldMark = domElem.getAttribute('data-fieldMark') || ''
    // 生成“附件”元素（按照此前约定的数据结构）
    const myResume = {
        type: 'attachmenttwo',
        link,
        fileName,
        fieldMark,
        fileSpan,
        children: [{ text: '' }], // void node 必须有 children ，其中有一个空字符串，重要！！！
    }
    return myResume
}
const parseHtmlConf = {
    selector: 'span[data-w-e-type="attachment"]', // CSS 选择器，匹配特定的 HTML 标签
    parseElemHtml: parseAttachmentHtml,
}
const parseHtmlConftwo = {
    selector: 'span[data-w-e-type="attachmenttwo"]', // CSS 选择器，匹配特定的 HTML 标签
    parseElemHtml: parseAttachmentHtmltwo,
}
const parseHtmlConfmodule = {
    parseElemsHtml: [parseHtmlConf, parseHtmlConftwo]  // parseElemHtml
}
Boot.registerModule(parseHtmlConfmodule)
</script>
<style lang="scss" scoped>
::v-deep .el-textarea__inner {
    color: black !important;
    background-color: #fff !important;
    cursor: default !important
}

.path-tag-wrap {
    font-size: 18px;
    line-height: 32px;
    border-radius: 5px;
}
</style>
<style src="@wangeditor/editor/dist/css/style.css"></style>
