| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 | /** * 目录大纲支持插件 * @file * @since 1.3.0 */UE.plugin.register('section', function (){    /* 目录节点对象 */    function Section(option){        this.tag = '';        this.level = -1,            this.dom = null;        this.nextSection = null;        this.previousSection = null;        this.parentSection = null;        this.startAddress = [];        this.endAddress = [];        this.children = [];    }    function getSection(option) {        var section = new Section();        return utils.extend(section, option);    }    function getNodeFromAddress(startAddress, root) {        var current = root;        for(var i = 0;i < startAddress.length; i++) {            if(!current.childNodes) return null;            current = current.childNodes[startAddress[i]];        }        return current;    }    var me = this;    return {        bindMultiEvents:{            type: 'aftersetcontent afterscencerestore',            handler: function(){                me.fireEvent('updateSections');            }        },        bindEvents:{            /* 初始化、拖拽、粘贴、执行setcontent之后 */            'ready': function (){                me.fireEvent('updateSections');                domUtils.on(me.body, 'drop paste', function(){                    me.fireEvent('updateSections');                });            },            /* 执行paragraph命令之后 */            'afterexeccommand': function (type, cmd) {                if(cmd == 'paragraph') {                    me.fireEvent('updateSections');                }            },            /* 部分键盘操作,触发updateSections事件 */            'keyup': function (type, e) {                var me = this,                    range = me.selection.getRange();                if(range.collapsed != true) {                    me.fireEvent('updateSections');                } else {                    var keyCode = e.keyCode || e.which;                    if(keyCode == 13 || keyCode == 8 || keyCode == 46) {                        me.fireEvent('updateSections');                    }                }            }        },        commands:{            'getsections': {                execCommand: function (cmd, levels) {                    var levelFn = levels || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];                    for (var i = 0; i < levelFn.length; i++) {                        if (typeof levelFn[i] == 'string') {                            levelFn[i] = function(fn){                                return function(node){                                    return node.tagName == fn.toUpperCase()                                };                            }(levelFn[i]);                        } else if (typeof levelFn[i] != 'function') {                            levelFn[i] = function (node) {                                return null;                            }                        }                    }                    function getSectionLevel(node) {                        for (var i = 0; i < levelFn.length; i++) {                            if (levelFn[i](node)) return i;                        }                        return -1;                    }                    var me = this,                        Directory = getSection({'level':-1, 'title':'root'}),                        previous = Directory;                    function traversal(node, Directory) {                        var level,                            tmpSection = null,                            parent,                            child,                            children = node.childNodes;                        for (var i = 0, len = children.length; i < len; i++) {                            child = children[i];                            level = getSectionLevel(child);                            if (level >= 0) {                                var address = me.selection.getRange().selectNode(child).createAddress(true).startAddress,                                    current = getSection({                                        'tag': child.tagName,                                        'title': child.innerText || child.textContent || '',                                        'level': level,                                        'dom': child,                                        'startAddress': utils.clone(address, []),                                        'endAddress': utils.clone(address, []),                                        'children': []                                    });                                previous.nextSection = current;                                current.previousSection = previous;                                parent = previous;                                while(level <= parent.level){                                    parent = parent.parentSection;                                }                                current.parentSection = parent;                                parent.children.push(current);                                tmpSection = previous = current;                            } else {                                child.nodeType === 1 && traversal(child, Directory);                                tmpSection && tmpSection.endAddress[tmpSection.endAddress.length - 1] ++;                            }                        }                    }                    traversal(me.body, Directory);                    return Directory;                },                notNeedUndo: true            },            'movesection': {                execCommand: function (cmd, sourceSection, targetSection, isAfter) {                    var me = this,                        targetAddress,                        target;                    if(!sourceSection || !targetSection || targetSection.level == -1) return;                    targetAddress = isAfter ? targetSection.endAddress:targetSection.startAddress;                    target = getNodeFromAddress(targetAddress, me.body);                    /* 判断目标地址是否被源章节包含 */                    if(!targetAddress || !target || isContainsAddress(sourceSection.startAddress, sourceSection.endAddress, targetAddress)) return;                    var startNode = getNodeFromAddress(sourceSection.startAddress, me.body),                        endNode = getNodeFromAddress(sourceSection.endAddress, me.body),                        current,                        nextNode;                    if(isAfter) {                        current = endNode;                        while ( current && !(domUtils.getPosition( startNode, current ) & domUtils.POSITION_FOLLOWING) ) {                            nextNode = current.previousSibling;                            domUtils.insertAfter(target, current);                            if(current == startNode) break;                            current = nextNode;                        }                    } else {                        current = startNode;                        while ( current && !(domUtils.getPosition( current, endNode ) & domUtils.POSITION_FOLLOWING) ) {                            nextNode = current.nextSibling;                            target.parentNode.insertBefore(current, target);                            if(current == endNode) break;                            current = nextNode;                        }                    }                    me.fireEvent('updateSections');                    /* 获取地址的包含关系 */                    function isContainsAddress(startAddress, endAddress, addressTarget){                        var isAfterStartAddress = false,                            isBeforeEndAddress = false;                        for(var i = 0; i< startAddress.length; i++){                            if(i >= addressTarget.length) break;                            if(addressTarget[i] > startAddress[i]) {                                isAfterStartAddress = true;                                break;                            } else if(addressTarget[i] < startAddress[i]) {                                break;                            }                        }                        for(var i = 0; i< endAddress.length; i++){                            if(i >= addressTarget.length) break;                            if(addressTarget[i] < startAddress[i]) {                                isBeforeEndAddress = true;                                break;                            } else if(addressTarget[i] > startAddress[i]) {                                break;                            }                        }                        return isAfterStartAddress && isBeforeEndAddress;                    }                }            },            'deletesection': {                execCommand: function (cmd, section, keepChildren) {                    var me = this;                    if(!section) return;                    function getNodeFromAddress(startAddress) {                        var current = me.body;                        for(var i = 0;i < startAddress.length; i++) {                            if(!current.childNodes) return null;                            current = current.childNodes[startAddress[i]];                        }                        return current;                    }                    var startNode = getNodeFromAddress(section.startAddress),                        endNode = getNodeFromAddress(section.endAddress),                        current = startNode,                        nextNode;                    if(!keepChildren) {                        while ( current && domUtils.inDoc(endNode, me.document) && !(domUtils.getPosition( current, endNode ) & domUtils.POSITION_FOLLOWING) ) {                            nextNode = current.nextSibling;                            domUtils.remove(current);                            current = nextNode;                        }                    } else {                        domUtils.remove(current);                    }                    me.fireEvent('updateSections');                }            },            'selectsection': {                execCommand: function (cmd, section) {                    if(!section && !section.dom) return false;                    var me = this,                        range = me.selection.getRange(),                        address = {                            'startAddress':utils.clone(section.startAddress, []),                            'endAddress':utils.clone(section.endAddress, [])                        };                    address.endAddress[address.endAddress.length - 1]++;                    range.moveToAddress(address).select().scrollToView();                    return true;                },                notNeedUndo: true            },            'scrolltosection': {                execCommand: function (cmd, section) {                    if(!section && !section.dom) return false;                    var me = this,                        range = me.selection.getRange(),                        address = {                            'startAddress':section.startAddress,                            'endAddress':section.endAddress                        };                    address.endAddress[address.endAddress.length - 1]++;                    range.moveToAddress(address).scrollToView();                    return true;                },                notNeedUndo: true            }        }    }});
 |