<template>
    <div v-on:dblclick="operateNode(row)" :class="classes" ref="cell" @mouseenter.self = "showEditIcon(row, column.key)" @mouseleave = "hideEditIcon">
        <template v-if="renderType === 'index'">{{naturalIndex + 1}}</template>
        <template v-if="renderType === 'selection'">
            <Checkbox :value="checked" @on-change="toggleSelect" :disabled="disabled"></Checkbox>
        </template>
        <template v-if="renderType === 'normal'">
            <span v-html="row[column.key]" :contentEditable="editable"></span>
            <a href="javascript:;" @click.prevent="edit(row, column.key)"><Icon type="edit" v-show="editIcon"></Icon></a>
        </template>
        <template v-if="renderType === 'hidden'">
            <span v-html="row[column.key]" style="display: none;"></span>
        </template>
        <template v-if="renderType === 'treetable'">
            <template v-for="le in row.level">
                <span class="ut-table-tree-indent"></span>
            </template>
            <span class="ut-table-tree-swc" @click="operateNode(row)">
                <template v-if="row.hasChild">
                    <Icon type="arrow-right-b" style="cursor: pointer;"></Icon>
                </template>
            </span>
            <img v-if="row.icon && row.icon.indexOf('/') !== -1" :src="row.icon" width="18px" height="18px"/>
            <Icon :type="row.icon" v-if="row.icon && row.icon.indexOf('/') === -1" width="18px" height="18px"/>
            <span v-html="row[column.key]"></span>
        </template>
    </div>
</template>
<script>
    import Vue from 'vue';
    import Checkbox from '../checkbox/checkbox.vue';
    import Icon from '../icon';
    import { trim } from '../../utils/assist';
    import { deepCopy } from '../../utils/assist';

    export default {
        name: 'TableCell',
        components: { Checkbox },
        props: {
            prefixCls: String,
            treeTable:{
                type:Boolean,
                default:false
            },
            row: Object,
            column: Object,
            naturalIndex: Number,    // index of rebuildData
            index: Number,           // _index of data
            level:Number,
            expandLevel:Number,
            checked: Boolean,
            disabled: Boolean,
            fixed: {
                type: [Boolean, String],
                default: false
            },
            hasErrorAlready: {
                type:Boolean,
                default: false
            }
        },
        data () {
            return {
                renderType: '',
                uid: -1,
                context: this.$parent.$parent.currentContext,
                editable: false,
                editIcon: false
            };
        },
        computed: {
            classes () {
                return [
                    `${this.prefixCls}-cell`,
                    {
                        [`${this.prefixCls}-hidden`]: !this.fixed && this.column.fixed && (this.column.fixed === 'left' || this.column.fixed === 'right'),
                        [`${this.prefixCls}-cell-ellipsis`]: this.column.ellipsis || false
                    }
                ];
            }
        },
        methods: {
            foreachNodeClose:function (child,vExpandLevel,level) {
                level=parseInt(level)+1;
                let obj;
                for(let i=0;i<child.length;i++){
                    if(child[i].childNodes!=undefined&&child[i].childNodes.length>0){
                        obj=document.getElementById("tr_"+child[i].pid+"_"+child[i].id+"");
                        this.addClass(obj,"ut-hidden");
                        if(level>vExpandLevel){
                            this.removeClass(obj,"ut-expanded");
                        }
                        this.foreachNodeClose(child[i].childNodes);
                    }else{
                        obj=document.getElementById("tr_"+child[i].pid+"_"+child[i].id+"");
                        this.addClass(obj,"ut-hidden");
                        this.removeClass(obj,"ut-expanded");
                    }
                }
            },
            foreachNodeOpen:function (child,vExpandLevel,level) {
                level=parseInt(level)+1;
                let obj;
                for(let i=0;i<child.length;i++){
                    if(child[i].childNodes!=undefined&&child[i].childNodes.length>0){
                        obj=document.getElementById("tr_"+child[i].pid+"_"+child[i].id+"");
                        this.removeClass(obj,"ut-hidden");
                        if(level<vExpandLevel) {
                            this.addClass(obj,"ut-expanded");
                            this.foreachNodeOpen(child[i].childNodes,vExpandLevel,level);
                        }
                    }else{
                        obj=document.getElementById("tr_"+child[i].pid+"_"+child[i].id+"");
                        this.removeClass(obj,"ut-hidden");
                        this.addClass(obj,"ut-table-tree-leaf")
                    }
                }
            },
            hasClass:function (obj,cls) {
                return obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
            },
            addClass:function (obj,cls) {
                if (!this.hasClass(obj, cls)) obj.className += " " + cls;
            },
            removeClass:function (obj,cls) {
                if (this.hasClass(obj, cls)) {
                    var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
                    obj.className = obj.className.replace(reg, ' ');
                }
            },
            operateNode:function (row) {
                let obj;
                if(row.pid==null||row.pid==""){
                    obj=document.getElementById("tr_Root_"+row.id);
                } else{
                    obj=document.getElementById("tr_"+row.pid+"_"+row.id);
                }
                let vExpandLevel=0;
                vExpandLevel=parseInt(this.expandLevel);
                if(this.hasClass(obj,"ut-expanded")){
                    this.removeClass(obj,"ut-expanded")
                    this.foreachNodeClose(row.childNodes,vExpandLevel,0);
                }else{
                    this.addClass(obj,"ut-expanded")
                    this.foreachNodeOpen(row.childNodes,vExpandLevel,0)
                }
                obj=document.getElementById(row.firstR)
                this.addClass(obj,"rowOperate")
            },
            compile () {
                if (this.column.render) {
                    // 兼容真 Render，后期废弃旧用法
                    let isRealRender = false;
                    try {
                        this.column.render(this.row, this.column, this.index);
                    }
                    catch (err) {
                        isRealRender = true;
                    }
                    if (isRealRender) {
                        const component = new Vue({
                            functional: true,
                            render: (h) => {
                                return this.column.render(h, {
                                    row: this.row,
                                    column: this.column,
                                    index: this.index
                                });
                            }
                        });
                        const Cell = component.$mount();
                        this.$el.innerHTML = '';
                        this.$refs.cell.appendChild(Cell.$el);
                    } else {
                        const $parent = this.context;
                        const template = this.column.render(this.row, this.column, this.index);
                        const cell = document.createElement('div');
                        cell.innerHTML = template;
                        this.$el.innerHTML = '';
                        let methods = {};
                        Object.keys($parent).forEach(key => {
                            const func = $parent[key];
                            if (typeof(func) === 'function' && (func.name  === 'boundFn' || func.name === 'n' || func.name === 'C')) {
                                methods[key] = func;
                            }
                        });
                        const res = Vue.compile(cell.outerHTML);
                        // 获取父组件使用的局部 component
                        const components = {};
                        Object.getOwnPropertyNames($parent.$options.components).forEach(item => {
                            components[item] = $parent.$options.components[item];
                        });
                        const component = new Vue({
                            render: res.render,
                            staticRenderFns: res.staticRenderFns,
                            methods: methods,
                            data () {
                                return $parent._data;
                            },
                            components: components
                        });
                        if ($parent.$store != undefined) {
                            component.$store = $parent.$store;
                        }
                        component.row = this.row;
                        component.column = this.column;
                        const Cell = component.$mount();
                        this.$refs.cell.appendChild(Cell.$el);
                    }
                }
            },
            destroy () {

            },
            toggleSelect () {
                this.$parent.$parent.toggleSelect(this.index);
            },
            edit (row, key) {
                if (this.hasErrorAlready) {
                    return
                }
                let _this = this
                let temp = {}
                this.editIcon = false
                if (row.rowEditable) {
                    this.editable = row.rowEditable
                    temp = row
                } else if (row.cellEditable instanceof Array) {
                    for(let i = 0, len = row.cellEditable.length;i<len;i++){
                        if (row.cellEditable[i].name === key) {
                            temp = row.cellEditable[i]
                            this.editable = true
                            break
                        }
                    }
                }
                if (this.editable) {
                    this.$nextTick(function(){
                        // 获取td下面的div里面装文字的span
                        let contentElement = event.target.parentNode.parentNode.querySelector('span')
                        contentElement.focus()
                        var range = window.getSelection();//创建range
                        range.selectAllChildren(contentElement);//range 选择obj下所有子内容
                        range.collapseToEnd();//光标移至最后
                        contentElement.parentNode.parentNode.classList.add('focus')
                        contentElement.style.width = "90%"
                        contentElement.onblur = function () {
                            let result = true
                            let message = '输入不符合规范，请重新输入'
                            this.classList.remove('focus')
                            let newVal = document.querySelector('span[contentEditable="true"]').innerText
                            newVal = trim(newVal)
                            // 对表格内容进行验证
                            if (temp.validate && temp.validate.length > 0) {
                                let len = newVal.length
                                for(let i = 0; i<temp.validate.length; i++){
                                    let testItem = temp.validate[i]
                                    if (testItem.required && len === 0) {
                                        result = false
                                        message = testItem.message || message
                                        break
                                    } else if ((testItem.maxlength && len > testItem.maxlength) || (testItem.minlength && len < testItem.minength)) {
                                        result = false
                                        message = testItem.message || message
                                        break
                                    } else if (testItem.rules && !testItem.rules.test(newVal)) {
                                        result = false
                                        message = testItem.message || message
                                        break
                                    }
                                }
                            }
                            // 如果新内容验证通过
                            if (result) {
                                contentElement.parentNode.parentNode.classList.remove('error')
                                contentElement.parentNode.parentNode.classList.remove('focus')
                                this.style.width=""
                                newVal = newVal.replace(/\</g,'&lt;')
                                let oldVal = row[key]
                                if (newVal !== oldVal) {
                                    let oldobj = deepCopy(row)
                                    row[key] = newVal
                                    temp.onAfterChange && temp.onAfterChange(row, oldobj)
                                }
                                _this.editable = false
                                _this.$emit('hasError', false)
                            } else {
                                _this.$Message.error(message)
                                contentElement.focus()
                                contentElement.parentNode.parentNode.classList.add('error')
                                _this.$emit('hasError', true)
                            }
                        }
                    })
                }
            },
            showEditIcon (row, key) {
                let editable = false
                let td = event.target.parentNode
                if (td.classList.contains('focus') || td.classList.contains('error')) {
                    this.editIcon = false
                } else if (row.rowEditable === 'true') {
                    editable = true
                } else if (row.cellEditable instanceof Array) {
                    for(let i = 0, len = row.cellEditable.length;i<len;i++){
                        if (row.cellEditable[i].name === key) {
                            editable = true
                            break
                        }
                    }
                }
                this.editIcon = editable
            },
            hideEditIcon () {
                this.editIcon = false
            }
        },
        created () {
            if (this.column.type === 'index') {
                this.renderType = 'index';
            } else if (this.column.type === 'selection') {
                this.renderType = 'selection';
            }else if(this.column.type === 'treetable'){
                this.renderType = 'treetable';
            }
            else if(this.column.type==='hidden'){
                this.renderType='hidden';
            }
            else if (this.column.render) {
                this.renderType = 'render';
            } else {
                this.renderType = 'normal';
            }
        },
        mounted () {
            this.$nextTick(() => {
                this.compile();
            });
        },
        beforeDestroy () {
            this.destroy();
        },
        watch: {
            naturalIndex () {
                this.destroy();
                this.compile();
            }
        }
    };
</script>
<style scoped>
    td span{
        display: inline-block;
        /*width: 90%;*/
        border: none;
        outline: none;
    }
    td span::focus{
        border:none;
        outline: none;
    }
    a{
        display: inline-block;
        float: right;
        margin-right: 10px;
    }
    img{
        vertical-align: middle;
    }
</style>
