1/* 2 * FCKeditor - The text editor for Internet - http://www.fckeditor.net 3 * Copyright (C) 2003-2007 Frederico Caldeira Knabben 4 * 5 * == BEGIN LICENSE == 6 * 7 * Licensed under the terms of any of the following licenses at your 8 * choice: 9 * 10 * - GNU General Public License Version 2 or later (the "GPL") 11 * http://www.gnu.org/licenses/gpl.html 12 * 13 * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") 14 * http://www.gnu.org/licenses/lgpl.html 15 * 16 * - Mozilla Public License Version 1.1 or later (the "MPL") 17 * http://www.mozilla.org/MPL/MPL-1.1.html 18 * 19 * == END LICENSE == 20 * 21 * Class for working with a selection range, much like the W3C DOM Range, but 22 * it is not intended to be an implementation of the W3C interface. 23 * (IE Implementation) 24 */ 25 26FCKDomRange.prototype.MoveToSelection = function() 27{ 28 this.Release( true ) ; 29 30 this._Range = new FCKW3CRange( this.Window.document ) ; 31 32 var oSel = this.Window.document.selection ; 33 34 if ( oSel.type != 'Control' ) 35 { 36 var eMarkerStart = this._GetSelectionMarkerTag( true ) ; 37 var eMarkerEnd = this._GetSelectionMarkerTag( false ) ; 38 39 if ( !eMarkerStart && !eMarkerEnd ) 40 { 41 this._Range.setStart( this.Window.document.body, 0 ) ; 42 this._UpdateElementInfo() ; 43 return ; 44 } 45 46 // Set the start boundary. 47 this._Range.setStart( eMarkerStart.parentNode, FCKDomTools.GetIndexOf( eMarkerStart ) ) ; 48 eMarkerStart.parentNode.removeChild( eMarkerStart ) ; 49 50 // Set the end boundary. 51 this._Range.setEnd( eMarkerEnd.parentNode, FCKDomTools.GetIndexOf( eMarkerEnd ) ) ; 52 eMarkerEnd.parentNode.removeChild( eMarkerEnd ) ; 53 54 this._UpdateElementInfo() ; 55 } 56 else 57 { 58 var oControl = oSel.createRange().item(0) ; 59 60 if ( oControl ) 61 { 62 this._Range.setStartBefore( oControl ) ; 63 this._Range.setEndAfter( oControl ) ; 64 this._UpdateElementInfo() ; 65 } 66 } 67} 68 69FCKDomRange.prototype.Select = function() 70{ 71 if ( this._Range ) 72 this.SelectBookmark( this.CreateBookmark( true ) ) ; 73} 74 75// Not compatible with bookmark created with CreateBookmark2. 76// The bookmark nodes will be deleted from the document. 77FCKDomRange.prototype.SelectBookmark = function( bookmark ) 78{ 79 var bIsCollapsed = this.CheckIsCollapsed() ; 80 var bIsStartMakerAlone ; 81 var dummySpan ; 82 83 // Create marker tags for the start and end boundaries. 84 var eStartMarker = this.GetBookmarkNode( bookmark, true ) ; 85 86 if ( !eStartMarker ) 87 return ; 88 89 var eEndMarker ; 90 if ( !bIsCollapsed ) 91 eEndMarker = this.GetBookmarkNode( bookmark, false ) ; 92 93 // Create the main range which will be used for the selection. 94 var oIERange = this.Window.document.body.createTextRange() ; 95 96 // Position the range at the start boundary. 97 oIERange.moveToElementText( eStartMarker ) ; 98 oIERange.moveStart( 'character', 1 ) ; 99 100 if ( eEndMarker ) 101 { 102 // Create a tool range for the end. 103 var oIERangeEnd = this.Window.document.body.createTextRange() ; 104 105 // Position the tool range at the end. 106 oIERangeEnd.moveToElementText( eEndMarker ) ; 107 108 // Move the end boundary of the main range to match the tool range. 109 oIERange.setEndPoint( 'EndToEnd', oIERangeEnd ) ; 110 oIERange.moveEnd( 'character', -1 ) ; 111 } 112 else 113 { 114 bIsStartMakerAlone = ( !eStartMarker.previousSibling || eStartMarker.previousSibling.nodeName.toLowerCase() == 'br' ) && !eStartMarker.nextSibing ; 115 116 // Append a temporary <span> </span> before the selection. 117 // This is needed to avoid IE destroying selections inside empty 118 // inline elements, like <b></b> (#253). 119 // It is also needed when placing the selection right after an inline 120 // element to avoid the selection moving inside of it. 121 dummySpan = this.Window.document.createElement( 'span' ) ; 122 dummySpan.innerHTML = ' ' ; 123 eStartMarker.parentNode.insertBefore( dummySpan, eStartMarker ) ; 124 125 if ( bIsStartMakerAlone ) 126 { 127 // To expand empty blocks or line spaces after <br>, we need 128 // instead to have a , which will be later deleted using the 129 // selection. 130 eStartMarker.parentNode.insertBefore( this.Window.document.createTextNode( '\u00a0' ), eStartMarker ) ; 131 } 132 } 133 134 if ( !this._Range ) 135 this._Range = this.CreateRange() ; 136 137 // Remove the markers (reset the position, because of the changes in the DOM tree). 138 this._Range.setStartBefore( eStartMarker ) ; 139 eStartMarker.parentNode.removeChild( eStartMarker ) ; 140 141 if ( bIsCollapsed ) 142 { 143 if ( bIsStartMakerAlone ) 144 { 145 // Move the selection start to include the temporary . 146 oIERange.moveStart( 'character', -1 ) ; 147 148 oIERange.select() ; 149 150 // Remove our temporary stuff. 151 this.Window.document.selection.clear() ; 152 } 153 else 154 oIERange.select() ; 155 156 FCKDomTools.RemoveNode( dummySpan ) ; 157 } 158 else 159 { 160 this._Range.setEndBefore( eEndMarker ) ; 161 eEndMarker.parentNode.removeChild( eEndMarker ) ; 162 oIERange.select() ; 163 } 164} 165 166FCKDomRange.prototype._GetSelectionMarkerTag = function( toStart ) 167{ 168 var doc = this.Window.document ; 169 var selection = doc.selection ; 170 171 // Get a range for the start boundary. 172 var oRange ; 173 174 // IE may throw an "unspecified error" on some cases (it happened when 175 // loading _samples/default.html), so try/catch. 176 try 177 { 178 oRange = selection.createRange() ; 179 } 180 catch (e) 181 { 182 return null ; 183 } 184 185 // IE might take the range object to the main window instead of inside the editor iframe window. 186 // This is known to happen when the editor window has not been selected before (See #933). 187 // We need to avoid that. 188 if ( oRange.parentElement().document != doc ) 189 return null ; 190 191 oRange.collapse( toStart === true ) ; 192 193 // Paste a marker element at the collapsed range and get it from the DOM. 194 var sMarkerId = 'fck_dom_range_temp_' + (new Date()).valueOf() + '_' + Math.floor(Math.random()*1000) ; 195 oRange.pasteHTML( '<span id="' + sMarkerId + '"></span>' ) ; 196 197 return doc.getElementById( sMarkerId ) ; 198} 199