Ticket #3083: 3083_2.patch
File 3083_2.patch, 28.5 KB (added by , 15 years ago) |
---|
-
_samples/enterkey.html
1 <!-- 2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 --> 5 <html xmlns="http://www.w3.org/1999/xhtml"> 6 <head> 7 <title>ENTER Key Configuration - CKEditor Sample</title> 8 <script type="text/javascript" src="sample.js"></script> 9 <script id="headscript" type="text/javascript"> 10 //<![CDATA[ 11 12 var editor; 13 14 function changeEnter() 15 { 16 // If we already have an editor, let's destroy it first. 17 if ( editor ) 18 editor.destroy(); 19 20 // Create the editor again, with the appropriate settings. 21 editor = CKEDITOR.replace( 'editor1', 22 { 23 enterMode : Number( document.getElementById( 'xEnter' ).value ), 24 shiftEnterMode : Number( document.getElementById( 'xShiftEnter' ).value ) 25 }); 26 } 27 28 window.onload = changeEnter; 29 30 //]]> 31 </script> 32 </head> 33 <body> 34 <!-- 35 The values in the select boxes represent the contants taht can be used 36 to configure the enter key. You can use the constants directly instead 37 of their numeric values: 38 - CKEDITOR.ENTER_P = 1; 39 - CKEDITOR.ENTER_BR = 2; 40 - CKEDITOR.ENTER_DIV = 3; 41 --> 42 <div id="html"> 43 <div style="float: left; margin-right: 20px"> 44 When ENTER is pressed:<br /> 45 <select id="xEnter" onchange="changeEnter();"> 46 <option value="1" selected="selected">Create new <P> (recommended)</option> 47 <option value="3">Create new <DIV></option> 48 <option value="2">Break the line with a <BR></option> 49 </select> 50 </div> 51 <div style="float: left"> 52 When SHIFT + ENTER is pressed:<br /> 53 <select id="xShiftEnter" onchange="changeEnter();"> 54 <option value="1">Create new <P></option> 55 <option value="3">Create new <DIV></option> 56 <option value="2" selected="selected">Break the line with a <BR> (recommended)</option> 57 </select> 58 </div> 59 <br style="clear: both" /> 60 <form action="sample_posteddata.php" method="post"> 61 <p> 62 <br /> 63 <textarea id="editor1" name="editor1" rows="10" cols="80"><p>This is some <strong>sample text</strong>. You are using <a href="http://www.fckeditor.net/">FCKeditor</a>.</p></textarea> 64 </p> 65 <p> 66 <input type="submit" value="Submit" /> 67 </p> 68 </form> 69 </div> 70 <div id="code"> 71 <pre></pre> 72 </div> 73 </body> 74 </html> -
_source/core/config.js
8 8 * default configuration settings. 9 9 */ 10 10 11 CKEDITOR.ENTER_P = 1; 12 CKEDITOR.ENTER_BR = 2; 13 CKEDITOR.ENTER_DIV = 3; 14 11 15 /** 12 16 * Holds the default configuration settings. Changes to this object are 13 17 * reflected in all editor instances, if not specificaly specified for those … … 95 99 */ 96 100 defaultLanguage : 'en', 97 101 98 enterMode : 'p',99 shiftEnterMode : 'br',102 enterMode : CKEDITOR.ENTER_P, 103 shiftEnterMode : CKEDITOR.ENTER_BR, 100 104 101 105 /** 102 106 * A comma separated list of plugins that are not related to editor … … 147 151 * config.plugins = 'basicstyles,button,htmldataprocessor,toolbar,wysiwygarea'; 148 152 */ 149 153 150 plugins : 'basicstyles,blockquote,button,clipboard,colorbutton,contextmenu,elementspath,ent ities,find,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,stylescombo,table,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc',154 plugins : 'basicstyles,blockquote,button,clipboard,colorbutton,contextmenu,elementspath,enterkey,entities,find,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,stylescombo,table,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc', 151 155 152 156 /** 153 157 * The theme to be used to build the UI. -
_source/core/dom/element.js
193 193 append : function( node, toStart ) 194 194 { 195 195 if ( typeof node == 'string' ) 196 node = new CKEDITOR.dom.element( node );196 node = this.getDocument().createElement( node ); 197 197 198 198 if ( toStart ) 199 199 this.$.insertBefore( node.$, this.$.firstChild ); … … 205 205 206 206 appendHtml : function( html ) 207 207 { 208 var temp = new CKEDITOR.dom.element( 'div', this.getDocument() ); 209 temp.setHtml( html ); 210 temp.moveChildren( this ); 208 if ( !this.$.childNodes.length ) 209 this.setHtml( html ); 210 else 211 { 212 var temp = new CKEDITOR.dom.element( 'div', this.getDocument() ); 213 temp.setHtml( html ); 214 temp.moveChildren( this ); 215 } 211 216 }, 212 217 213 218 /** … … 229 234 this.append( new CKEDITOR.dom.text( text ) ); 230 235 }, 231 236 237 appendBogus : function() 238 { 239 var lastChild = this.getLast() ; 240 241 // Ignore empty/spaces text. 242 while ( lastChild && lastChild.type == CKEDITOR.NODE_TEXT && CKEDITOR.tools.rtrim( lastChild.getText() ).length == 0 ) 243 lastChild = lastChild.getPrevious(); 244 245 if ( !lastChild || ( lastChild.is && ( !lastChild.is( 'br' ) || !lastChild.getAttribute( '_cke_bogus' ) ) ) ) 246 { 247 this.append( 248 CKEDITOR.env.opera ? 249 this.getDocument().createText('') : 250 this.getDocument().createElement( 'br', { attributes : { _cke_bogus : 1 } } ) ); 251 } 252 }, 253 232 254 /** 233 255 * Breaks one of the ancestor element in the element position, moving 234 256 * this element between the broken parts. … … 658 680 return false; 659 681 }, 660 682 683 isEditable : function() 684 { 685 // Get the element name. 686 var name = this.getName(); 687 688 // Get the element DTD (defaults to span for unknown elements). 689 var dtd = !CKEDITOR.dtd.$nonEditable[ name ] 690 && ( CKEDITOR.dtd[ name ] || CKEDITOR.dtd.span ); 691 692 // In the DTD # == text node. 693 return ( dtd && dtd['#'] ); 694 }, 695 661 696 isIdentical : function( otherElement ) 662 697 { 663 698 if ( this.getName() != otherElement.getName() ) -
_source/core/dom/node.js
94 94 95 95 clone : function( includeChildren ) 96 96 { 97 return new CKEDITOR.dom.node( this.$.cloneNode( includeChildren ) ); 97 var $clone = this.$.cloneNode( includeChildren ); 98 99 if ( this.type == CKEDITOR.NODE_ELEMENT ) 100 { 101 // The "id" attribute should never be cloned to avoid duplication. 102 $clone.removeAttribute( 'id', false ) ; 103 $clone.removeAttribute( '_cke_expando', false ) ; 104 } 105 106 return new CKEDITOR.dom.node( $clone ); 98 107 }, 99 108 100 109 hasPrevious : function() -
_source/core/dom/range.js
1095 1095 case CKEDITOR.ENLARGE_BLOCK_CONTENTS: 1096 1096 case CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS: 1097 1097 // DFS backward to get the block/list item boundary at or before the start. 1098 var boundaryNodes = this.getBoundaryNodes(), 1099 startNode = boundaryNodes.startNode, 1100 endNode = boundaryNodes.endNode, 1101 guardFunction = ( unit == CKEDITOR.ENLARGE_BLOCK_CONTENTS ? 1102 CKEDITOR.dom.domWalker.blockBoundary() : 1103 CKEDITOR.dom.domWalker.listItemBoundary() ), 1104 walker = new CKEDITOR.dom.domWalker( startNode ), 1105 data = walker.reverse( guardFunction ), 1106 boundaryEvent = data.events.shift(); 1098 1099 // Get the boundaries nodes. 1100 var startNode = this.getTouchedStartNode(), 1101 endNode = this.getTouchedEndNode(); 1107 1102 1108 this.setStartBefore( boundaryEvent.from ); 1103 if ( startNode.isBlockBoundary() ) 1104 { 1105 this.setStartAt( startNode, 1106 CKEDITOR.dtd.$empty[ startNode.getName() ] ? 1107 CKEDITOR.POSITION_AFTER_END : 1108 CKEDITOR.POSITION_AFTER_START ); 1109 } 1110 else 1111 { 1112 // Get the function used to check the enlaarging limits. 1113 var guardFunction = ( unit == CKEDITOR.ENLARGE_BLOCK_CONTENTS ? 1114 CKEDITOR.dom.domWalker.blockBoundary() : 1115 CKEDITOR.dom.domWalker.listItemBoundary() ); 1109 1116 1110 // DFS forward to get the block/list item boundary at or before the end. 1111 walker.setNode( endNode ); 1112 data = walker.forward( guardFunction ); 1113 boundaryEvent = data.events.shift(); 1117 // Create the DOM walker, which will traverse the DOM. 1118 var walker = new CKEDITOR.dom.domWalker( startNode ); 1119 1120 // Go walk in reverse sense. 1121 var data = walker.reverse( guardFunction ); 1122 1123 var boundaryEvent = data.events.shift(); 1114 1124 1115 this.setEndAfter( boundaryEvent.from );1116 break;1125 this.setStartBefore( boundaryEvent.from ); 1126 } 1117 1127 1118 default: 1128 if ( endNode.isBlockBoundary() ) 1129 { 1130 this.setEndAt( endNode, 1131 CKEDITOR.dtd.$empty[ startNode.getName() ] ? 1132 CKEDITOR.POSITION_BEFORE_START : 1133 CKEDITOR.POSITION_BEFORE_END ); 1134 } 1135 else 1136 { 1137 // DFS forward to get the block/list item boundary at or before the end. 1138 walker.setNode( endNode ); 1139 data = walker.forward( guardFunction ); 1140 boundaryEvent = data.events.shift(); 1141 1142 this.setEndAfter( boundaryEvent.from ); 1143 } 1119 1144 } 1120 1145 }, 1121 1146 … … 1281 1306 updateCollapsed( this ); 1282 1307 }, 1283 1308 1284 // TODO: Does not add bogus <br> to empty fixed blocks.1285 1309 fixBlock : function( isStart, blockTag ) 1286 1310 { 1287 1311 var bookmark = this.createBookmark(), 1288 fixedBlock = new CKEDITOR.dom.element( blockTag, this.document ); 1312 fixedBlock = this.document.createElement( blockTag ); 1313 1289 1314 this.collapse( isStart ); 1315 1290 1316 this.enlarge( CKEDITOR.ENLARGE_BLOCK_CONTENTS ); 1317 1291 1318 this.extractContents().appendTo( fixedBlock ); 1292 1319 fixedBlock.trim(); 1320 1321 if ( !CKEDITOR.env.ie ) 1322 fixedBlock.appendBogus(); 1323 1293 1324 this.insertNode( fixedBlock ); 1325 1294 1326 this.moveToBookmark( bookmark ); 1327 1295 1328 return fixedBlock; 1296 1329 }, 1297 1330 1298 1331 splitBlock : function( blockTag ) 1299 1332 { 1300 var startPath = new CKEDITOR.dom.elementPath( this.startContainer ), 1301 endPath = new CKEDITOR.dom.elementPath( this.endContainer ), 1302 startBlockLimit = startPath.blockLimit, 1303 endBlockLimit = endPath.blockLimit, 1304 startBlock = startPath.block, 1305 endBlock = endPath.block, 1306 elementPath = null; 1333 var startPath = new CKEDITOR.dom.elementPath( this.startContainer ), 1334 endPath = new CKEDITOR.dom.elementPath( this.endContainer ); 1307 1335 1336 var startBlockLimit = startPath.blockLimit, 1337 endBlockLimit = endPath.blockLimit; 1338 1339 var startBlock = startPath.block, 1340 endBlock = endPath.block; 1341 1342 var elementPath = null; 1343 1344 // Do nothing if the boundaries are in different block limits. 1308 1345 if ( !startBlockLimit.equals( endBlockLimit ) ) 1309 1346 return null; 1310 1347 … … 1314 1351 if ( !startBlock ) 1315 1352 { 1316 1353 startBlock = this.fixBlock( true, blockTag ); 1317 endBlock = new CKEDITOR.dom.elementPath( this.endContainer ) ;1354 endBlock = new CKEDITOR.dom.elementPath( this.endContainer ).block; 1318 1355 } 1319 1356 1320 1357 if ( !endBlock ) … … 1352 1389 1353 1390 // Duplicate the block element after it. 1354 1391 endBlock = startBlock.clone( false ); 1355 endBlock.removeAttribute( 'id' );1356 1392 1357 1393 // Place the extracted contents into the duplicated block. 1358 1394 documentFragment.appendTo( endBlock ); 1359 1395 endBlock.insertAfter( startBlock ); 1360 1396 this.moveToPosition( startBlock, CKEDITOR.POSITION_AFTER_END ); 1361 1397 1362 // TODO: Append bogus br to startBlock for Gecko 1398 // In Gecko, the last child node must be a bogus <br>. 1399 // Note: bogus <br> added under <ul> or <ol> would cause 1400 // lists to be incorrectly rendered. 1401 if ( !CKEDITOR.env.ie && !startBlock.is( 'ul', 'ol') ) 1402 startBlock.appendBogus() ; 1363 1403 } 1364 1404 } 1365 1405 … … 1418 1458 walker.forward( CKEDITOR.dom.domWalker.blockBoundary() ); 1419 1459 1420 1460 return !walker.checkFailed; 1461 }, 1462 1463 /** 1464 * Moves the range boundaries to the first editing point inside an 1465 * element. For example, in an element tree like 1466 * "<p><b><i></i></b> Text</p>", the start editing point is 1467 * "<p><b><i>^</i></b> Text</p>" (inside <i>). 1468 * @param {CKEDITOR.dom.element} targetElement The element into which 1469 * look for the editing spot. 1470 */ 1471 moveToElementEditStart : function( targetElement ) 1472 { 1473 var editableElement; 1474 1475 while ( targetElement && targetElement.type == CKEDITOR.NODE_ELEMENT ) 1476 { 1477 if ( targetElement.isEditable() ) 1478 editableElement = targetElement; 1479 else if ( editableElement ) 1480 break ; // If we already found an editable element, stop the loop. 1481 1482 targetElement = targetElement.getFirst(); 1483 } 1484 1485 if ( editableElement ) 1486 this.moveToPosition( editableElement, CKEDITOR.POSITION_AFTER_START ); 1487 }, 1488 1489 getTouchedStartNode : function() 1490 { 1491 var container = this.startContainer ; 1492 1493 if ( this.collapsed || container.type != CKEDITOR.NODE_ELEMENT ) 1494 return container ; 1495 1496 return container.getChild( this.startOffset ) || container ; 1497 }, 1498 1499 getTouchedEndNode : function() 1500 { 1501 var container = this.endContainer ; 1502 1503 if ( this.collapsed || container.type != CKEDITOR.NODE_ELEMENT ) 1504 return container ; 1505 1506 return container.getChild[ this.endOffset - 1 ] || container ; 1421 1507 } 1422 1508 }; 1423 1509 })(); -
_source/core/dtd.js
79 79 $listItem : {dd:1,dt:1,li:1}, 80 80 81 81 /** 82 * Elements that accept text nodes, but are not possible to edit into 83 * the browser. 84 * @type Object 85 * @example 86 */ 87 $nonEditable : {applet:1,button:1,embed:1,iframe:1,map:1,object:1,option:1,script:1,textarea:1}, 88 89 /** 82 90 * List of elements that can be ignored if empty, like "b" or "span". 83 91 * @type Object 84 92 * @example 85 93 */ 86 $removeEmpty : {abbr:1,acronym:1,address:1,b:1,bdo:1,big:1,cite:1,code:1,d fn:1,em:1,font:1,i:1,kbd:1,q:1,s:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1},94 $removeEmpty : {abbr:1,acronym:1,address:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,s:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1}, 87 95 88 96 /** 89 97 * List of elements that have tabindex set to zero by default. -
_source/core/plugins.js
18 18 '_source/' + // %REMOVE_LINE% 19 19 'plugins/', 'plugin' ); 20 20 21 // PACKAGER_RENAME( CKEDITOR.plugins ) 22 21 23 CKEDITOR.plugins.load = CKEDITOR.tools.override( CKEDITOR.plugins.load, function( originalLoad ) 22 24 { 23 25 return function( name, callback, scope ) -
_source/plugins/enterkey/plugin.js
1 /* 2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 */ 5 6 (function() 7 { 8 CKEDITOR.plugins.add( 'enterkey', 9 { 10 requires : [ 'keystrokes' ], 11 12 init : function( editor ) 13 { 14 var specialKeys = editor.specialKeys; 15 specialKeys[ 13 ] = enter; 16 specialKeys[ CKEDITOR.SHIFT + 13 ] = shiftEnter; 17 } 18 }); 19 20 var forceMode, 21 headerTagRegex = /^h[1-6]$/; 22 23 function shiftEnter( editor ) 24 { 25 // On SHIFT+ENTER we want to enforce the mode to be respected, instead 26 // of cloning the current block. (#77) 27 forceMode = 1; 28 29 return enter( editor, editor.config.shiftEnterMode ); 30 } 31 32 function enter( editor, mode ) 33 { 34 if ( !mode ) 35 mode = editor.config.enterMode; 36 37 // Use setTimout so the keys get cancelled immediatelly. 38 setTimeout( function() 39 { 40 if ( mode == CKEDITOR.ENTER_BR || editor.getSelection().getStartElement().hasAscendant( 'pre', true ) ) 41 enterBr( editor, mode ); 42 else 43 enterBlock( editor, mode ); 44 45 forceMode = 0; 46 }, 0 ); 47 48 return true; 49 } 50 51 function enterBlock( editor, mode, range ) 52 { 53 // Get the range for the current selection. 54 range = range || getRange( editor ); 55 56 var doc = range.document; 57 58 // Determine the block element to be used. 59 var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' ); 60 61 // Split the range. 62 var splitInfo = range.splitBlock( blockTag ); 63 64 if ( !splitInfo ) 65 return; 66 67 // Get the current blocks. 68 var previousBlock = splitInfo.previousBlock, 69 nextBlock = splitInfo.nextBlock; 70 71 var isStartOfBlock = splitInfo.wasStartOfBlock, 72 isEndOfBlock = splitInfo.wasEndOfBlock; 73 74 var node; 75 76 // If this is a block under a list item, split it as well. (#1647) 77 if ( nextBlock ) 78 { 79 node = nextBlock.getParent(); 80 if ( node.is( 'li' ) ) 81 { 82 nextBlock.breakParent( node ); 83 nextBlock.move( nextBlock.getNext(), true ); 84 } 85 } 86 else if ( previousBlock && ( node = previousBlock.getParent() ) && node.is( 'li' ) ) 87 { 88 previousBlock.breakParent( node ); 89 range.moveToElementEditStart( previousBlock.getNext() ); 90 previousBlock.move( previousBlock.getPrevious() ); 91 } 92 93 // If we have both the previous and next blocks, it means that the 94 // boundaries were on separated blocks, or none of them where on the 95 // block limits (start/end). 96 if ( !isStartOfBlock && !isEndOfBlock ) 97 { 98 // If the next block is an <li> with another list tree as the first 99 // child, we'll need to append a placeholder or the list item 100 // wouldn't be editable. (#1420) 101 if ( nextBlock.is( 'li' ) && ( node = nextBlock.getFirst() ) 102 && node.is && node.is( 'ul', 'ol') ) 103 nextBlock.insertBefore( doc.createText( '\xa0' ), node ); 104 105 // Move the selection to the end block. 106 if ( nextBlock ) 107 range.moveToElementEditStart( nextBlock ); 108 } 109 else 110 { 111 var newBlock; 112 113 if ( previousBlock ) 114 { 115 // Do not enter this block if it's a header tag, or we are in 116 // a Shift+Enter (#77). Create a new block element instead 117 // (later in the code). 118 if ( !forceMode && !headerTagRegex.test( previousBlock.getName() ) ) 119 { 120 // Otherwise, duplicate the previous block. 121 newBlock = previousBlock.clone(); 122 } 123 } 124 else if ( nextBlock ) 125 newBlock = nextBlock.clone(); 126 127 if ( !newBlock ) 128 newBlock = doc.createElement( blockTag ); 129 130 // Recreate the inline elements tree, which was available 131 // before hitting enter, so the same styles will be available in 132 // the new block. 133 var elementPath = splitInfo.elementPath; 134 if ( elementPath ) 135 { 136 for ( var i = 0, len = elementPath.elements.length ; i < len ; i++ ) 137 { 138 var element = elementPath.elements[ i ]; 139 140 if ( element.equals( elementPath.block ) || element.equals( elementPath.blockLimit ) ) 141 break; 142 143 if ( CKEDITOR.dtd.$removeEmpty[ element.getName() ] ) 144 { 145 element = element.clone(); 146 newBlock.moveChildren( element ); 147 newBlock.append( element ); 148 } 149 } 150 } 151 152 if ( !CKEDITOR.env.ie ) 153 newBlock.appendBogus(); 154 155 range.insertNode( newBlock ); 156 157 // This is tricky, but to make the new block visible correctly 158 // we must select it. 159 // The previousBlock check has been included because it may be 160 // empty if we have fixed a block-less space (like ENTER into an 161 // empty table cell). 162 if ( CKEDITOR.env.ie && isStartOfBlock && ( !isEndOfBlock || !previousBlock.getChildCount() ) ) 163 { 164 // Move the selection to the new block. 165 range.moveToElementEditStart( isEndOfBlock ? previousBlock : newBlock ); 166 range.select(); 167 } 168 169 // Move the selection to the new block. 170 range.moveToElementEditStart( isStartOfBlock && !isEndOfBlock ? nextBlock : newBlock ); 171 } 172 173 if ( !CKEDITOR.env.ie ) 174 { 175 if ( nextBlock ) 176 { 177 // If we have split the block, adds a temporary span at the 178 // range position and scroll relatively to it. 179 var tmpNode = doc.createElement( 'span' ); 180 181 // We need some content for Safari. 182 tmpNode.setHtml( ' ' ); 183 184 range.insertNode( tmpNode ); 185 tmpNode.scrollIntoView(); 186 range.deleteContents(); 187 } 188 else 189 { 190 // We may use the above scroll logic for the new block case 191 // too, but it gives some weird result with Opera. 192 newBlock.scrollIntoView(); 193 } 194 } 195 196 range.select(); 197 } 198 199 function enterBr( editor, mode ) 200 { 201 // Get the range for the current selection. 202 var range = getRange( editor ), 203 doc = range.document; 204 205 // Determine the block element to be used. 206 var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' ); 207 208 var isEndOfBlock = range.checkEndOfBlock(); 209 210 var elementPath = new CKEDITOR.dom.elementPath( range.getBoundaryNodes().startNode ); 211 212 var startBlock = elementPath.block, 213 startBlockTag = startBlock && elementPath.block.getName(); 214 215 var isPre = false; 216 217 if ( !forceMode && startBlockTag == 'li' ) 218 return enterBlock( editor, mode, range ); 219 220 // If we are at the end of a header block. 221 if ( !forceMode && isEndOfBlock && headerTagRegex.test( startBlockTag ) ) 222 { 223 // Insert a <br> after the current paragraph. 224 doc.createElement( 'br' ).insertAfter( startBlock ); 225 226 // A text node is required by Gecko only to make the cursor blink. 227 if ( CKEDITOR.env.gecko ) 228 doc.createText( '' ).insertAfter( startBlock ); 229 230 // IE has different behaviors regarding position. 231 range.setStartAt( startBlock.getNext(), CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_START ); 232 } 233 else 234 { 235 var lineBreak; 236 237 isPre = ( startBlockTag == 'pre' ); 238 239 if ( isPre ) 240 lineBreak = doc.createText( CKEDITOR.env.ie ? '\r' : '\n' ); 241 else 242 lineBreak = doc.createElement( 'br' ); 243 244 range.insertNode( lineBreak ); 245 246 // A text node is required by Gecko only to make the cursor blink. 247 if ( CKEDITOR.env.gecko ) 248 doc.createText( '' ).insertAfter( lineBreak ); 249 250 // If we are at the end of a block, we must be sure the bogus node is available in that block. 251 if ( isEndOfBlock && !CKEDITOR.env.ie ) 252 lineBreak.getParent().appendBogus(); 253 254 // IE has different behavior regarding position. 255 if ( CKEDITOR.env.ie ) 256 range.setStartAt( lineBreak, CKEDITOR.POSITION_AFTER_END ); 257 else 258 range.setStartAt( lineBreak.getNext(), CKEDITOR.POSITION_AFTER_START ); 259 260 // Scroll into view, for non IE. 261 if ( !CKEDITOR.env.ie ) 262 { 263 var dummy = null; 264 265 if ( CKEDITOR.env.opera ) 266 dummy = doc.createElement( 'span' ); 267 else 268 dummy = doc.createElement( 'br' ); 269 270 dummy.insertBefore( lineBreak.getNext() ); 271 dummy.scrollIntoView(); 272 dummy.remove(); 273 } 274 } 275 276 // This collapse guarantees the cursor will be blinking. 277 range.collapse( true ); 278 279 range.select( isPre ); 280 } 281 282 function getRange( editor ) 283 { 284 // Get the selection ranges. 285 var ranges = editor.getSelection().getRanges(); 286 287 // Delete the contents of all ranges except the first one. 288 for ( var i = ranges.length - 1 ; i > 0 ; i-- ) 289 { 290 ranges[ i ].deleteContents(); 291 } 292 293 // Return the first range. 294 return ranges[ 0 ]; 295 } 296 })(); -
_source/plugins/keystrokes/plugin.js
15 15 * @example 16 16 */ 17 17 editor.keystrokeHandler = new CKEDITOR.keystrokeHandler( editor ); 18 19 editor.specialKeys = {}; 18 20 }, 19 21 20 22 init : function( editor ) … … 84 86 85 87 var keyCombination = event.getKeystroke(); 86 88 var command = this.keystrokes[ keyCombination ]; 89 var editor = this._.editor; 87 90 88 cancel = ( this._.editor.fire( 'key', { keyCode : keyCombination } ) === true );91 cancel = ( editor.fire( 'key', { keyCode : keyCombination } ) === true ); 89 92 90 93 if ( !cancel ) 91 94 { 92 95 if ( command ) 93 96 { 94 97 var data = { from : 'keystrokeHandler' }; 95 cancel = ( this._.editor.execCommand( command, data ) !== false );98 cancel = ( editor.execCommand( command, data ) !== false ); 96 99 } 97 100 98 if ( !cancel ) 99 cancel = !!this.blockedKeystrokes[ keyCombination ]; 101 if ( !cancel ) 102 { 103 var handler = editor.specialKeys[ keyCombination ], 104 cancel = ( handler && handler( editor ) === true ); 105 106 if ( !cancel ) 107 cancel = !!this.blockedKeystrokes[ keyCombination ]; 108 } 100 109 } 101 110 102 111 if ( cancel ) … … 166 175 [ CKEDITOR.CTRL + 90 /*Z*/, 'undo' ], 167 176 [ CKEDITOR.CTRL + 89 /*Y*/, 'redo' ], 168 177 [ CKEDITOR.CTRL + CKEDITOR.SHIFT + 90 /*Z*/, 'redo' ], 178 169 179 [ CKEDITOR.CTRL + 76 /*L*/, 'link' ], 180 170 181 [ CKEDITOR.CTRL + 66 /*B*/, 'bold' ], 171 182 [ CKEDITOR.CTRL + 73 /*I*/, 'italic' ], 172 [ CKEDITOR.CTRL + 85 /*U*/, 'underline' ], 173 [ CKEDITOR.CTRL + CKEDITOR.ALT + 13 /*ENTER*/, 'fitWindow' ], 174 [ CKEDITOR.SHIFT + 32 /*SPACE*/, 'nbsp' ] 183 [ CKEDITOR.CTRL + 85 /*U*/, 'underline' ] 175 184 ]; -
_source/plugins/selection/plugin.js
698 698 } 699 699 else 700 700 { 701 isStartMakerAlone = ( !startNode.hasPrevious() || ( startNode.getPrevious().is && startNode.getPrevious().is( 'br' ) ) ) 702 && !startNode.hasNext(); 701 // The isStartMakerAlone logic comes from V2. It guarantees that the lines 702 // will expand and that the cursor will be blinking on the right place. 703 // Actually, we are using this flag just to avoid using this hack in all 704 // situations, but just on those needed. 703 705 706 // But, in V3, somehow it is not interested on working whe hitting SHIFT+ENTER 707 // inside text. So, let's jsut leave the hack happen always. 708 709 // I'm still leaving the code here just in case. We may find some other IE 710 // weirdness and uncommenting this stuff may be useful. 711 712 // isStartMakerAlone = ( !startNode.hasPrevious() || ( startNode.getPrevious().is && startNode.getPrevious().is( 'br' ) ) ) 713 // && !startNode.hasNext(); 714 704 715 // Append a temporary <span></span> before the selection. 705 716 // This is needed to avoid IE destroying selections inside empty 706 717 // inline elements, like <b></b> (#253). … … 710 721 dummySpan.setHtml( '' ); // Zero Width No-Break Space (U+FEFF). See #1359. 711 722 dummySpan.insertBefore( startNode ); 712 723 713 if ( isStartMakerAlone )714 {724 // if ( isStartMakerAlone ) 725 // { 715 726 // To expand empty blocks or line spaces after <br>, we need 716 727 // instead to have any char, which will be later deleted using the 717 728 // selection. 718 // \ufeff = Zero Width No-Break Space (U+FEFF). See #1359.729 // \ufeff = Zero Width No-Break Space (U+FEFF). (#1359) 719 730 this.document.createText( '\ufeff' ).insertBefore( startNode ); 720 }731 // } 721 732 } 722 733 723 734 // Remove the markers (reset the position, because of the changes in the DOM tree). … … 726 737 727 738 if ( collapsed ) 728 739 { 729 if ( isStartMakerAlone )730 {731 // Move the selection start to include the temporary .732 //ieRange.moveStart( 'character', -1 );740 // if ( isStartMakerAlone ) 741 // { 742 // Move the selection start to include the temporary \ufeff. 743 ieRange.moveStart( 'character', -1 ); 733 744 734 745 ieRange.select(); 735 746 736 747 // Remove our temporary stuff. 737 //this.document.$.selection.clear();738 }739 else740 ieRange.select();748 this.document.$.selection.clear(); 749 // } 750 // else 751 // ieRange.select(); 741 752 742 753 dummySpan.remove(); 743 754 }