/** * 目录大纲支持插件 * @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 } } } });