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 * Active selection functions. (Gecko specific implementation) 22 */ 23 24// Get the selection type (like document.select.type in IE). 25FCKSelection.GetType = function() 26{ 27 // By default set the type to "Text". 28 var type = 'Text' ; 29 30 // Check if the actual selection is a Control (IMG, TABLE, HR, etc...). 31 32 var sel ; 33 try { sel = FCK.EditorWindow.getSelection() ; } catch (e) {} 34 35 if ( sel && sel.rangeCount == 1 ) 36 { 37 var range = sel.getRangeAt(0) ; 38 if ( range.startContainer == range.endContainer 39 && ( range.endOffset - range.startOffset ) == 1 40 && range.startContainer.nodeType == 1 41 && FCKListsLib.StyleObjectElements[ range.startContainer.childNodes[ range.startOffset ].nodeName.toLowerCase() ] ) 42 { 43 type = 'Control' ; 44 } 45 } 46 47 return type ; 48} 49 50// Retrieves the selected element (if any), just in the case that a single 51// element (object like and image or a table) is selected. 52FCKSelection.GetSelectedElement = function() 53{ 54 var selectedElement = null ; 55 56 var selection = !!FCK.EditorWindow && FCK.EditorWindow.getSelection() ; 57 58 if ( selection && selection.anchorNode && selection.anchorNode.nodeType == 1 ) 59 { 60 // This one is good for all browsers, expect Safari Mac. 61 selectedElement = selection.anchorNode.childNodes[ selection.anchorOffset ] ; 62 63 // For Safari (Mac only), the anchor node for a control selection is 64 // the control itself, which seams logic. FF and Opera use the parent 65 // as the anchor node, pointing to the control with the offset. 66 // As FF created the selection "standard", Safari would do better by 67 // following their steps. 68 if ( !selectedElement ) 69 selectedElement = selection.anchorNode ; 70 else if ( selectedElement.nodeType != 1 ) 71 return null ; 72 } 73 74 return selectedElement ; 75} 76 77FCKSelection.GetParentElement = function() 78{ 79 if ( this.GetType() == 'Control' ) 80 return FCKSelection.GetSelectedElement().parentNode ; 81 else 82 { 83 var oSel = FCK.EditorWindow.getSelection() ; 84 if ( oSel ) 85 { 86 // make the common case fast - for collapsed/nearly collapsed selections just return anchor.parent. 87 if ( oSel.anchorNode && oSel.anchorNode == oSel.focusNode ) 88 return oSel.anchorNode.parentNode ; 89 90 // looks like we're having a large selection here. To make the behavior same as IE's TextRange.parentElement(), 91 // we need to find the nearest ancestor node which encapsulates both the beginning and the end of the selection. 92 // TODO: A simpler logic can be found. 93 var anchorPath = new FCKElementPath( oSel.anchorNode ) ; 94 var focusPath = new FCKElementPath( oSel.focusNode ) ; 95 var deepPath = null ; 96 var shallowPath = null ; 97 if ( anchorPath.Elements.length > focusPath.Elements.length ) 98 { 99 deepPath = anchorPath.Elements ; 100 shallowPath = focusPath.Elements ; 101 } 102 else 103 { 104 deepPath = focusPath.Elements ; 105 shallowPath = anchorPath.Elements ; 106 } 107 108 var deepPathBase = deepPath.length - shallowPath.length ; 109 for( var i = 0 ; i < shallowPath.length ; i++) 110 { 111 if ( deepPath[deepPathBase + i] == shallowPath[i]) 112 return shallowPath[i]; 113 } 114 return null ; 115 } 116 } 117 return null ; 118} 119 120FCKSelection.GetBoundaryParentElement = function( startBoundary ) 121{ 122 if ( ! FCK.EditorWindow ) 123 return null ; 124 if ( this.GetType() == 'Control' ) 125 return FCKSelection.GetSelectedElement().parentNode ; 126 else 127 { 128 var oSel = FCK.EditorWindow.getSelection() ; 129 if ( oSel && oSel.rangeCount > 0 ) 130 { 131 var range = oSel.getRangeAt( startBoundary ? 0 : ( oSel.rangeCount - 1 ) ) ; 132 133 var element = startBoundary ? range.startContainer : range.endContainer ; 134 135 return ( element.nodeType == 1 ? element : element.parentNode ) ; 136 } 137 } 138 return null ; 139} 140 141FCKSelection.SelectNode = function( element ) 142{ 143 var oRange = FCK.EditorDocument.createRange() ; 144 oRange.selectNode( element ) ; 145 146 var oSel = FCK.EditorWindow.getSelection() ; 147 oSel.removeAllRanges() ; 148 oSel.addRange( oRange ) ; 149} 150 151FCKSelection.Collapse = function( toStart ) 152{ 153 var oSel = FCK.EditorWindow.getSelection() ; 154 155 if ( toStart == null || toStart === true ) 156 oSel.collapseToStart() ; 157 else 158 oSel.collapseToEnd() ; 159} 160 161// The "nodeTagName" parameter must be Upper Case. 162FCKSelection.HasAncestorNode = function( nodeTagName ) 163{ 164 var oContainer = this.GetSelectedElement() ; 165 if ( ! oContainer && FCK.EditorWindow ) 166 { 167 try { oContainer = FCK.EditorWindow.getSelection().getRangeAt(0).startContainer ; } 168 catch(e){} 169 } 170 171 while ( oContainer ) 172 { 173 if ( oContainer.nodeType == 1 && oContainer.tagName == nodeTagName ) return true ; 174 oContainer = oContainer.parentNode ; 175 } 176 177 return false ; 178} 179 180// The "nodeTagName" parameter must be Upper Case. 181FCKSelection.MoveToAncestorNode = function( nodeTagName ) 182{ 183 var oNode ; 184 185 var oContainer = this.GetSelectedElement() ; 186 if ( ! oContainer ) 187 oContainer = FCK.EditorWindow.getSelection().getRangeAt(0).startContainer ; 188 189 while ( oContainer ) 190 { 191 if ( oContainer.nodeName == nodeTagName ) 192 return oContainer ; 193 194 oContainer = oContainer.parentNode ; 195 } 196 return null ; 197} 198 199FCKSelection.Delete = function() 200{ 201 // Gets the actual selection. 202 var oSel = FCK.EditorWindow.getSelection() ; 203 204 // Deletes the actual selection contents. 205 for ( var i = 0 ; i < oSel.rangeCount ; i++ ) 206 { 207 oSel.getRangeAt(i).deleteContents() ; 208 } 209 210 return oSel ; 211} 212