import rt 3.8.7
[freeside.git] / rt / share / html / NoAuth / RichText / FCKeditor / editor / _source / internals / fckselection_gecko.js
1 /*\r
2  * FCKeditor - The text editor for Internet - http://www.fckeditor.net\r
3  * Copyright (C) 2003-2009 Frederico Caldeira Knabben\r
4  *\r
5  * == BEGIN LICENSE ==\r
6  *\r
7  * Licensed under the terms of any of the following licenses at your\r
8  * choice:\r
9  *\r
10  *  - GNU General Public License Version 2 or later (the "GPL")\r
11  *    http://www.gnu.org/licenses/gpl.html\r
12  *\r
13  *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")\r
14  *    http://www.gnu.org/licenses/lgpl.html\r
15  *\r
16  *  - Mozilla Public License Version 1.1 or later (the "MPL")\r
17  *    http://www.mozilla.org/MPL/MPL-1.1.html\r
18  *\r
19  * == END LICENSE ==\r
20  *\r
21  * Active selection functions. (Gecko specific implementation)\r
22  */\r
23 \r
24 // Get the selection type (like document.select.type in IE).\r
25 FCKSelection.GetType = function()\r
26 {\r
27         // By default set the type to "Text".\r
28         var type = 'Text' ;\r
29 \r
30         // Check if the actual selection is a Control (IMG, TABLE, HR, etc...).\r
31 \r
32         var sel ;\r
33         try { sel = this.GetSelection() ; } catch (e) {}\r
34 \r
35         if ( sel && sel.rangeCount == 1 )\r
36         {\r
37                 var range = sel.getRangeAt(0) ;\r
38                 if ( range.startContainer == range.endContainer\r
39                         && ( range.endOffset - range.startOffset ) == 1\r
40                         && range.startContainer.nodeType == 1\r
41                         && FCKListsLib.StyleObjectElements[ range.startContainer.childNodes[ range.startOffset ].nodeName.toLowerCase() ] )\r
42                 {\r
43                         type = 'Control' ;\r
44                 }\r
45         }\r
46 \r
47         return type ;\r
48 }\r
49 \r
50 // Retrieves the selected element (if any), just in the case that a single\r
51 // element (object like and image or a table) is selected.\r
52 FCKSelection.GetSelectedElement = function()\r
53 {\r
54         var selection = !!FCK.EditorWindow && this.GetSelection() ;\r
55         if ( !selection || selection.rangeCount < 1 )\r
56                 return null ;\r
57 \r
58         var range = selection.getRangeAt( 0 ) ;\r
59         if ( range.startContainer != range.endContainer || range.startContainer.nodeType != 1 || range.startOffset != range.endOffset - 1 )\r
60                 return null ;\r
61 \r
62         var node = range.startContainer.childNodes[ range.startOffset ] ;\r
63         if ( node.nodeType != 1 )\r
64                 return null ;\r
65 \r
66         return node ;\r
67 }\r
68 \r
69 FCKSelection.GetParentElement = function()\r
70 {\r
71         if ( this.GetType() == 'Control' )\r
72                 return FCKSelection.GetSelectedElement().parentNode ;\r
73         else\r
74         {\r
75                 var oSel = this.GetSelection() ;\r
76                 if ( oSel )\r
77                 {\r
78                         // if anchorNode == focusNode, see if the selection is text only or including nodes.\r
79                         // if text only, return the parent node.\r
80                         // if the selection includes DOM nodes, then the anchorNode is the nearest container.\r
81                         if ( oSel.anchorNode && oSel.anchorNode == oSel.focusNode )\r
82                         {\r
83                                 var oRange = oSel.getRangeAt( 0 ) ;\r
84                                 if ( oRange.collapsed || oRange.startContainer.nodeType == 3 )\r
85                                         return oSel.anchorNode.parentNode ;\r
86                                 else\r
87                                         return oSel.anchorNode ;\r
88                         }\r
89 \r
90                         // looks like we're having a large selection here. To make the behavior same as IE's TextRange.parentElement(),\r
91                         // we need to find the nearest ancestor node which encapsulates both the beginning and the end of the selection.\r
92                         // TODO: A simpler logic can be found.\r
93                         var anchorPath = new FCKElementPath( oSel.anchorNode ) ;\r
94                         var focusPath = new FCKElementPath( oSel.focusNode ) ;\r
95                         var deepPath = null ;\r
96                         var shallowPath = null ;\r
97                         if ( anchorPath.Elements.length > focusPath.Elements.length )\r
98                         {\r
99                                 deepPath = anchorPath.Elements ;\r
100                                 shallowPath = focusPath.Elements ;\r
101                         }\r
102                         else\r
103                         {\r
104                                 deepPath = focusPath.Elements ;\r
105                                 shallowPath = anchorPath.Elements ;\r
106                         }\r
107 \r
108                         var deepPathBase = deepPath.length - shallowPath.length ;\r
109                         for( var i = 0 ; i < shallowPath.length ; i++)\r
110                         {\r
111                                 if ( deepPath[deepPathBase + i] == shallowPath[i])\r
112                                         return shallowPath[i];\r
113                         }\r
114                         return null ;\r
115                 }\r
116         }\r
117         return null ;\r
118 }\r
119 \r
120 FCKSelection.GetBoundaryParentElement = function( startBoundary )\r
121 {\r
122         if ( ! FCK.EditorWindow )\r
123                 return null ;\r
124         if ( this.GetType() == 'Control' )\r
125                 return FCKSelection.GetSelectedElement().parentNode ;\r
126         else\r
127         {\r
128                 var oSel = this.GetSelection() ;\r
129                 if ( oSel && oSel.rangeCount > 0 )\r
130                 {\r
131                         var range = oSel.getRangeAt( startBoundary ? 0 : ( oSel.rangeCount - 1 ) ) ;\r
132 \r
133                         var element = startBoundary ? range.startContainer : range.endContainer ;\r
134 \r
135                         return ( element.nodeType == 1 ? element : element.parentNode ) ;\r
136                 }\r
137         }\r
138         return null ;\r
139 }\r
140 \r
141 FCKSelection.SelectNode = function( element )\r
142 {\r
143         var oRange = FCK.EditorDocument.createRange() ;\r
144         oRange.selectNode( element ) ;\r
145 \r
146         var oSel = this.GetSelection() ;\r
147         oSel.removeAllRanges() ;\r
148         oSel.addRange( oRange ) ;\r
149 }\r
150 \r
151 FCKSelection.Collapse = function( toStart )\r
152 {\r
153         var oSel = this.GetSelection() ;\r
154 \r
155         if ( toStart == null || toStart === true )\r
156                 oSel.collapseToStart() ;\r
157         else\r
158                 oSel.collapseToEnd() ;\r
159 }\r
160 \r
161 // The "nodeTagName" parameter must be Upper Case.\r
162 FCKSelection.HasAncestorNode = function( nodeTagName )\r
163 {\r
164         var oContainer = this.GetSelectedElement() ;\r
165         if ( ! oContainer && FCK.EditorWindow )\r
166         {\r
167                 try             { oContainer = this.GetSelection().getRangeAt(0).startContainer ; }\r
168                 catch(e){}\r
169         }\r
170 \r
171         while ( oContainer )\r
172         {\r
173                 if ( oContainer.nodeType == 1 && oContainer.nodeName.IEquals( nodeTagName ) ) return true ;\r
174                 oContainer = oContainer.parentNode ;\r
175         }\r
176 \r
177         return false ;\r
178 }\r
179 \r
180 // The "nodeTagName" parameter must be Upper Case.\r
181 FCKSelection.MoveToAncestorNode = function( nodeTagName )\r
182 {\r
183         var oNode ;\r
184 \r
185         var oContainer = this.GetSelectedElement() ;\r
186         if ( ! oContainer )\r
187                 oContainer = this.GetSelection().getRangeAt(0).startContainer ;\r
188 \r
189         while ( oContainer )\r
190         {\r
191                 if ( oContainer.nodeName.IEquals( nodeTagName ) )\r
192                         return oContainer ;\r
193 \r
194                 oContainer = oContainer.parentNode ;\r
195         }\r
196         return null ;\r
197 }\r
198 \r
199 FCKSelection.Delete = function()\r
200 {\r
201         // Gets the actual selection.\r
202         var oSel = this.GetSelection() ;\r
203 \r
204         // Deletes the actual selection contents.\r
205         for ( var i = 0 ; i < oSel.rangeCount ; i++ )\r
206         {\r
207                 oSel.getRangeAt(i).deleteContents() ;\r
208         }\r
209 \r
210         return oSel ;\r
211 }\r
212 \r
213 /**\r
214  * Returns the native selection object.\r
215  */\r
216 FCKSelection.GetSelection = function()\r
217 {\r
218         return FCK.EditorWindow.getSelection() ;\r
219 }\r
220 \r
221 // The following are IE only features (we don't need then in other browsers\r
222 // currently).\r
223 FCKSelection.Save = function()\r
224 {}\r
225 FCKSelection.Restore = function()\r
226 {}\r
227 FCKSelection.Release = function()\r
228 {}\r