1 /** 2 * monitor user's enter and shift enter keydown,modified from ckeditor 3 * @author yiminghe@gmail.com 4 */ 5 KISSY.add("editor/core/enterKey", function (S,Editor,Walker,ElementPath) { 6 var UA = S.UA, 7 headerTagRegex = /^h[1-6]$/, 8 dtd = Editor.XHTML_DTD, 9 Node = S.Node, 10 Event = S.Event; 11 12 13 function getRange(editor) { 14 // Get the selection ranges. 15 var ranges = editor.getSelection().getRanges(); 16 // Delete the contents of all ranges except the first one. 17 for (var i = ranges.length - 1; i > 0; i--) { 18 ranges[ i ].deleteContents(); 19 } 20 // Return the first range. 21 return ranges[ 0 ]; 22 } 23 24 function enterBlock(editor) { 25 // Get the range for the current selection. 26 var range = getRange(editor); 27 var doc = range.document; 28 // Exit the list when we're inside an empty list item block. (#5376) 29 if (range.checkStartOfBlock() && range.checkEndOfBlock()) { 30 var path = new ElementPath(range.startContainer), 31 block = path.block; 32 //只有两层? 33 if (block && 34 ( block.nodeName() == 'li' || block.parent().nodeName() == 'li' ) 35 36 ) { 37 if (editor.hasCommand('outdent')) { 38 editor.execCommand("save"); 39 editor.execCommand('outdent'); 40 editor.execCommand("save"); 41 return true; 42 } else { 43 return false; 44 } 45 } 46 } 47 48 // Determine the block element to be used. 49 var blockTag = "p"; 50 51 // Split the range. 52 var splitInfo = range.splitBlock(blockTag); 53 54 if (!splitInfo) 55 return true; 56 57 // Get the current blocks. 58 var previousBlock = splitInfo.previousBlock, 59 nextBlock = splitInfo.nextBlock; 60 61 var isStartOfBlock = splitInfo.wasStartOfBlock, 62 isEndOfBlock = splitInfo.wasEndOfBlock; 63 64 var node; 65 66 // If this is a block under a list item, split it as well. (#1647) 67 if (nextBlock) { 68 node = nextBlock.parent(); 69 if (node.nodeName() == 'li') { 70 nextBlock._4e_breakParent(node); 71 nextBlock._4e_move(nextBlock.next(), true); 72 } 73 } 74 else if (previousBlock && ( node = previousBlock.parent() ) && node.nodeName() == 'li') { 75 previousBlock._4e_breakParent(node); 76 range.moveToElementEditablePosition(previousBlock.next()); 77 previousBlock._4e_move(previousBlock.prev()); 78 } 79 80 // If we have both the previous and next blocks, it means that the 81 // boundaries were on separated blocks, or none of them where on the 82 // block limits (start/end). 83 if (!isStartOfBlock && !isEndOfBlock) { 84 // If the next block is an <li> with another list tree as the first 85 // child, we'll need to append a filler (<br>/NBSP) or the list item 86 // wouldn't be editable. (#1420) 87 if (nextBlock.nodeName() == 'li' && 88 ( node = nextBlock.first(Walker.invisible(true)) ) && 89 S.inArray(node.nodeName(), ['ul', 'ol'])) 90 (UA['ie'] ? new Node(doc.createTextNode('\xa0')) : 91 new Node(doc.createElement('br'))).insertBefore(node); 92 93 // Move the selection to the end block. 94 if (nextBlock) 95 range.moveToElementEditablePosition(nextBlock); 96 } 97 else { 98 var newBlock; 99 100 if (previousBlock) { 101 // Do not enter this block if it's a header tag, or we are in 102 // a Shift+Enter (#77). Create a new block element instead 103 // (later in the code). 104 if (previousBlock.nodeName() == 'li' || !headerTagRegex.test(previousBlock.nodeName())) { 105 // Otherwise, duplicate the previous block. 106 newBlock = previousBlock.clone(); 107 } 108 } 109 else if (nextBlock) 110 newBlock = nextBlock.clone(); 111 112 if (!newBlock) 113 newBlock = new Node("<" + blockTag + ">", null, doc); 114 115 // Recreate the inline elements tree, which was available 116 // before hitting enter, so the same styles will be available in 117 // the new block. 118 var elementPath = splitInfo.elementPath; 119 if (elementPath) { 120 for (var i = 0, len = elementPath.elements.length; i < len; i++) { 121 var element = elementPath.elements[ i ]; 122 123 if (element.equals(elementPath.block) || element.equals(elementPath.blockLimit)) 124 break; 125 //<li><strong>^</strong></li> 126 if (dtd.$removeEmpty[ element.nodeName() ]) { 127 element = element.clone(); 128 newBlock._4e_moveChildren(element); 129 newBlock.append(element); 130 } 131 } 132 } 133 134 if (!UA['ie']) 135 newBlock._4e_appendBogus(); 136 137 range.insertNode(newBlock); 138 139 // This is tricky, but to make the new block visible correctly 140 // we must select it. 141 // The previousBlock check has been included because it may be 142 // empty if we have fixed a block-less space (like ENTER into an 143 // empty table cell). 144 if (UA['ie'] && isStartOfBlock && ( !isEndOfBlock || !previousBlock[0].childNodes.length )) { 145 // Move the selection to the new block. 146 range.moveToElementEditablePosition(isEndOfBlock ? previousBlock : newBlock); 147 range.select(); 148 } 149 150 // Move the selection to the new block. 151 range.moveToElementEditablePosition(isStartOfBlock && !isEndOfBlock ? nextBlock : newBlock); 152 } 153 154 if (!UA['ie']) { 155 if (nextBlock) { 156 // If we have split the block, adds a temporary span at the 157 // range position and scroll relatively to it. 158 var tmpNode = new Node(doc.createElement('span')); 159 160 // We need some content for Safari. 161 tmpNode.html(' '); 162 163 range.insertNode(tmpNode); 164 tmpNode.scrollIntoView(undefined,false); 165 range.deleteContents(); 166 } 167 else { 168 // We may use the above scroll logic for the new block case 169 // too, but it gives some weird result with Opera. 170 newBlock.scrollIntoView(undefined,false); 171 } 172 } 173 range.select(); 174 return true; 175 } 176 177 function EnterKey(editor) { 178 var doc = editor.get("document")[0]; 179 Event.on(doc, "keydown", function (ev) { 180 var keyCode = ev.keyCode; 181 if (keyCode === 13) { 182 if (ev.shiftKey || ev.ctrlKey || ev.metaKey) { 183 } else { 184 editor.execCommand("save"); 185 var re = editor.execCommand("enterBlock"); 186 editor.execCommand("save"); 187 if (re !== false) { 188 ev.preventDefault(); 189 } 190 } 191 } 192 }); 193 } 194 195 return { 196 init:function (editor) { 197 editor.addCommand("enterBlock", { 198 exec:enterBlock 199 }); 200 editor.docReady(function () { 201 EnterKey(editor); 202 }); 203 } 204 }; 205 }, { 206 requires:['./base','./walker','./elementPath'] 207 }); 208