Ticket #1272: 1272_8.patch
File 1272_8.patch, 10.9 KB (added by , 13 years ago) |
---|
-
_source/core/dom/node.js
204 204 while ( node && node != $documentElement ) 205 205 { 206 206 var parentNode = node.parentNode; 207 var currentIndex = -1;208 207 209 208 if ( parentNode ) 210 209 { 211 for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) 212 { 213 var candidate = parentNode.childNodes[i]; 214 215 if ( normalized && 216 candidate.nodeType == 3 && 217 candidate.previousSibling && 218 candidate.previousSibling.nodeType == 3 ) 219 { 220 continue; 221 } 222 223 currentIndex++; 224 225 if ( candidate == node ) 226 break; 227 } 228 229 address.unshift( currentIndex ); 210 // Get the node index. For performance, call getIndex 211 // directly, instead of creating a new node object. 212 address.unshift( this.getIndex.call( { $ : node }, normalized ) ); 230 213 } 231 214 232 215 node = parentNode; … … 247 230 return new CKEDITOR.dom.document( this.$.ownerDocument || this.$.parentNode.ownerDocument ); 248 231 }, 249 232 250 getIndex : function( )233 getIndex : function( normalized ) 251 234 { 252 var $ = this.$;235 // Attention: getAddress depends on this.$ 253 236 254 var current Node = $.parentNode && $.parentNode.firstChild;255 var currentIndex = -1;237 var current = this.$, 238 index = 0; 256 239 257 while ( currentNode)240 while ( ( current = current.previousSibling ) ) 258 241 { 259 currentIndex++; 242 // When normalizing, do not count it if this is an 243 // empty text node or if it's a text node following another one. 244 if ( normalized && current.nodeType == 3 && 245 ( !current.nodeValue.length || 246 ( current.previousSibling && current.previousSibling.nodeType == 3 ) ) ) 247 { 248 continue; 249 } 260 250 261 if ( currentNode == $ ) 262 return currentIndex; 263 264 currentNode = currentNode.nextSibling; 251 index++; 265 252 } 266 253 267 return -1;254 return index; 268 255 }, 269 256 270 257 getNextSourceNode : function( startFromSibling, nodeType, guard ) -
_source/core/dom/range.js
589 589 startContainer = child; 590 590 startOffset = 0; 591 591 } 592 593 // Get the normalized offset. 594 if ( child && child.type == CKEDITOR.NODE_ELEMENT ) 595 startOffset = child.getIndex( 1 ); 592 596 } 593 597 594 598 // Normalize the start. … … 617 621 endContainer = child; 618 622 endOffset = 0; 619 623 } 624 625 // Get the normalized offset. 626 if ( child && child.type == CKEDITOR.NODE_ELEMENT ) 627 endOffset = child.getIndex( 1 ); 620 628 } 621 629 622 630 // Normalize the end. -
_source/core/dom/text.js
67 67 return this.$.nodeValue; 68 68 }, 69 69 70 setText : function( text ) 71 { 72 this.$.nodeValue = text; 73 }, 74 70 75 /** 71 76 * Breaks this text node into two nodes at the specified offset, 72 77 * keeping both in the tree as siblings. This node then only contains -
_source/plugins/editingblock/plugin.js
153 153 */ 154 154 CKEDITOR.editor.prototype.setMode = function( mode ) 155 155 { 156 this.fire( 'beforeSetMode', { newMode : mode } ); 157 156 158 var data, 157 159 holderElement = this.getThemeSpace( 'contents' ), 158 160 isDirty = this.checkDirty(); -
_source/plugins/selection/plugin.js
99 99 canUndo : false 100 100 }; 101 101 102 function createFillingChar( doc ) 103 { 104 removeFillingChar( doc ); 105 106 var fillingChar = doc.createText( '\u200B' ); 107 doc.setCustomData( 'cke-fillingChar', fillingChar ); 108 109 return fillingChar; 110 } 111 112 function getFillingChar( doc ) 113 { 114 return doc && doc.getCustomData( 'cke-fillingChar' ); 115 } 116 117 // Checks if a filling char has been used, eventualy removing it (#1272). 118 function checkFillingChar( doc ) 119 { 120 var fillingChar = doc && getFillingChar( doc ); 121 if ( fillingChar ) 122 { 123 // Use this flag to avoid removing the filling char right after 124 // creating it. 125 if ( fillingChar.getCustomData( 'ready' ) ) 126 removeFillingChar( doc ); 127 else 128 fillingChar.setCustomData( 'ready', 1 ); 129 } 130 } 131 132 function removeFillingChar( doc ) 133 { 134 var fillingChar = doc && doc.removeCustomData( 'cke-fillingChar' ); 135 if ( fillingChar ) 136 { 137 // We can't simply remove the filling node because the user 138 // will actually enlarge it when typing, so we just remove the 139 // invisible char from it. 140 fillingChar.setText( fillingChar.getText().replace( /\u200B/g, '' ) ); 141 fillingChar = 0; 142 } 143 } 144 102 145 CKEDITOR.plugins.add( 'selection', 103 146 { 104 147 init : function( editor ) 105 148 { 149 // On WebKit only, we need a special "filling" char on some situations 150 // (#1272). Here we set the events that should invalidate that char. 151 if ( CKEDITOR.env.webkit ) 152 { 153 editor.on( 'selectionChange', function() { checkFillingChar( editor.document ); } ); 154 editor.on( 'beforeSetMode', function() { removeFillingChar( editor.document ); } ); 155 editor.on( 'key', function( e ) 156 { 157 // Remove the filling char before some keys get 158 // executed, so they'll not get blocked by it. 159 switch ( e.data.keyCode ) 160 { 161 case 37 : // LEFT-ARROW 162 case 39 : // RIGHT-ARROW 163 case 8 : // BACKSPACE 164 removeFillingChar( editor.document ); 165 } 166 }); 167 168 var fillingCharBefore; 169 function beforeData() 170 { 171 var fillingChar = getFillingChar( editor.document ); 172 fillingCharBefore = fillingChar && fillingChar.getText(); 173 fillingCharBefore && fillingChar.setText( fillingCharBefore.replace( /\u200B/g, '' ) ); 174 } 175 function afterData() 176 { 177 var fillingChar = getFillingChar( editor.document ); 178 fillingChar && fillingChar.setText( fillingCharBefore ); 179 } 180 editor.on( 'beforeUndoImage', beforeData ); 181 editor.on( 'afterUndoImage', afterData ); 182 editor.on( 'beforeGetData', beforeData, null, null, 0 ); 183 editor.on( 'getData', afterData ); 184 } 185 106 186 editor.on( 'contentDom', function() 107 187 { 108 188 var doc = editor.document, … … 1146 1226 var sel = this.getNative(); 1147 1227 1148 1228 if ( ranges.length ) 1229 { 1149 1230 sel.removeAllRanges(); 1231 // Remove any existing filling char first. 1232 CKEDITOR.env.webkit && removeFillingChar( this.document ); 1233 } 1150 1234 1151 1235 for ( var i = 0 ; i < ranges.length ; i++ ) 1152 1236 { … … 1196 1280 startContainer.appendText( '' ); 1197 1281 } 1198 1282 1199 nativeRange.setStart( startContainer.$, range.startOffset ); 1200 nativeRange.setEnd( range.endContainer.$, range.endOffset ); 1283 if ( range.collapsed && CKEDITOR.env.webkit ) 1284 { 1285 // Append a zero-width space so WebKit will not try to 1286 // move the selection by itself (#1272). 1287 fillingChar = createFillingChar( this.document ); 1288 range.insertNode( fillingChar ) ; 1201 1289 1290 var next = fillingChar.getNext(); 1291 1292 // If the filling char is followed by a <br>, whithout 1293 // having something before it, it'll not blink. 1294 // Let's remove it in this case. 1295 if ( next && !fillingChar.getPrevious() && next.type == CKEDITOR.NODE_ELEMENT && next.getName() == 'br' ) 1296 { 1297 removeFillingChar( this.document ); 1298 range.moveToPosition( next, CKEDITOR.POSITION_BEFORE_START ); 1299 } 1300 else 1301 range.moveToPosition( fillingChar, CKEDITOR.POSITION_AFTER_END ); 1302 } 1303 1304 nativeRange.setStart( range.startContainer.$, range.startOffset ); 1305 1306 try 1307 { 1308 nativeRange.setEnd( range.endContainer.$, range.endOffset ); 1309 } 1310 catch ( e ) 1311 { 1312 // There is a bug in Firefox implementation (it would be too easy 1313 // otherwise). The new start can't be after the end (W3C says it can). 1314 // So, let's create a new range and collapse it to the desired point. 1315 if ( e.toString().indexOf( 'NS_ERROR_ILLEGAL_VALUE' ) >= 0 ) 1316 { 1317 range.collapse( 1 ); 1318 nativeRange.setEnd( range.endContainer.$, range.endOffset ); 1319 } 1320 else 1321 throw e; 1322 } 1323 1202 1324 // Select the range. 1203 1325 sel.addRange( nativeRange ); 1204 1326 } … … 1384 1506 : 1385 1507 function() 1386 1508 { 1387 var startContainer = this.startContainer; 1388 1389 // If we have a collapsed range, inside an empty element, we must add 1390 // something to it, otherwise the caret will not be visible. 1391 if ( this.collapsed && startContainer.type == CKEDITOR.NODE_ELEMENT && !startContainer.getChildCount() ) 1392 startContainer.append( new CKEDITOR.dom.text( '' ) ); 1393 1394 var nativeRange = this.document.$.createRange(); 1395 nativeRange.setStart( startContainer.$, this.startOffset ); 1396 1397 try 1398 { 1399 nativeRange.setEnd( this.endContainer.$, this.endOffset ); 1400 } 1401 catch ( e ) 1402 { 1403 // There is a bug in Firefox implementation (it would be too easy 1404 // otherwise). The new start can't be after the end (W3C says it can). 1405 // So, let's create a new range and collapse it to the desired point. 1406 if ( e.toString().indexOf( 'NS_ERROR_ILLEGAL_VALUE' ) >= 0 ) 1407 { 1408 this.collapse( true ); 1409 nativeRange.setEnd( this.endContainer.$, this.endOffset ); 1410 } 1411 else 1412 throw( e ); 1413 } 1414 1415 var selection = this.document.getSelection().getNative(); 1416 // getSelection() returns null in case when iframe is "display:none" in FF. (#6577) 1417 if ( selection ) 1418 { 1419 selection.removeAllRanges(); 1420 selection.addRange( nativeRange ); 1421 } 1509 this.document.getSelection().selectRanges( [ this ] ); 1422 1510 }; 1423 1511 } )(); -
_source/plugins/undo/plugin.js
148 148 var Image = CKEDITOR.plugins.undo.Image = function( editor ) 149 149 { 150 150 this.editor = editor; 151 152 editor.fire( 'beforeUndoImage' ); 153 151 154 var contents = editor.getSnapshot(), 152 155 selection = contents && editor.getSelection(); 153 156 … … 156 159 157 160 this.contents = contents; 158 161 this.bookmarks = selection && selection.createBookmarks2( true ); 162 163 editor.fire( 'afterUndoImage' ); 159 164 }; 160 165 161 166 // Attributes that browser may changing them when setting via innerHTML.