import rt 3.8.7
[freeside.git] / rt / share / html / NoAuth / RichText / FCKeditor / editor / _source / classes / fckpanel.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  * Component that creates floating panels. It is used by many\r
22  * other components, like the toolbar items, context menu, etc...\r
23  */\r
24 \r
25 var FCKPanel = function( parentWindow )\r
26 {\r
27         this.IsRTL                      = ( FCKLang.Dir == 'rtl' ) ;\r
28         this.IsContextMenu      = false ;\r
29         this._LockCounter       = 0 ;\r
30 \r
31         this._Window = parentWindow || window ;\r
32 \r
33         var oDocument ;\r
34 \r
35         if ( FCKBrowserInfo.IsIE )\r
36         {\r
37                 // Create the Popup that will hold the panel.\r
38                 // The popup has to be created before playing with domain hacks, see #1666.\r
39                 this._Popup     = this._Window.createPopup() ;\r
40 \r
41                 // this._Window cannot be accessed while playing with domain hacks, but local variable is ok.\r
42                 // See #1666.\r
43                 var pDoc = this._Window.document ;\r
44 \r
45                 // This is a trick to IE6 (not IE7). The original domain must be set\r
46                 // before creating the popup, so we are able to take a refence to the\r
47                 // document inside of it, and the set the proper domain for it. (#123)\r
48                 if ( FCK_IS_CUSTOM_DOMAIN && !FCKBrowserInfo.IsIE7 )\r
49                 {\r
50                         pDoc.domain = FCK_ORIGINAL_DOMAIN ;\r
51                         document.domain = FCK_ORIGINAL_DOMAIN ;\r
52                 }\r
53 \r
54                 oDocument = this.Document = this._Popup.document ;\r
55 \r
56                 // Set the proper domain inside the popup.\r
57                 if ( FCK_IS_CUSTOM_DOMAIN )\r
58                 {\r
59                         oDocument.domain = FCK_RUNTIME_DOMAIN ;\r
60                         pDoc.domain = FCK_RUNTIME_DOMAIN ;\r
61                         document.domain = FCK_RUNTIME_DOMAIN ;\r
62                 }\r
63 \r
64                 FCK.IECleanup.AddItem( this, FCKPanel_Cleanup ) ;\r
65         }\r
66         else\r
67         {\r
68                 var oIFrame = this._IFrame = this._Window.document.createElement('iframe') ;\r
69                 FCKTools.ResetStyles( oIFrame );\r
70                 oIFrame.src                                     = 'javascript:void(0)' ;\r
71                 oIFrame.allowTransparency       = true ;\r
72                 oIFrame.frameBorder                     = '0' ;\r
73                 oIFrame.scrolling                       = 'no' ;\r
74                 oIFrame.style.width = oIFrame.style.height = '0px' ;\r
75                 FCKDomTools.SetElementStyles( oIFrame,\r
76                         {\r
77                                 position        : 'absolute',\r
78                                 zIndex          : FCKConfig.FloatingPanelsZIndex\r
79                         } ) ;\r
80 \r
81                 this._Window.document.body.appendChild( oIFrame ) ;\r
82 \r
83                 var oIFrameWindow = oIFrame.contentWindow ;\r
84 \r
85                 oDocument = this.Document = oIFrameWindow.document ;\r
86 \r
87                 // Workaround for Safari 12256. Ticket #63\r
88                 var sBase = '' ;\r
89                 if ( FCKBrowserInfo.IsSafari )\r
90                         sBase = '<base href="' + window.document.location + '">' ;\r
91 \r
92                 // Initialize the IFRAME document body.\r
93                 oDocument.open() ;\r
94                 oDocument.write( '<html><head>' + sBase + '<\/head><body style="margin:0px;padding:0px;"><\/body><\/html>' ) ;\r
95                 oDocument.close() ;\r
96 \r
97                 if( FCKBrowserInfo.IsAIR )\r
98                         FCKAdobeAIR.Panel_Contructor( oDocument, window.document.location ) ;\r
99 \r
100                 FCKTools.AddEventListenerEx( oIFrameWindow, 'focus', FCKPanel_Window_OnFocus, this ) ;\r
101                 FCKTools.AddEventListenerEx( oIFrameWindow, 'blur', FCKPanel_Window_OnBlur, this ) ;\r
102         }\r
103 \r
104         oDocument.dir = FCKLang.Dir ;\r
105 \r
106         FCKTools.AddEventListener( oDocument, 'contextmenu', FCKTools.CancelEvent ) ;\r
107 \r
108 \r
109         // Create the main DIV that is used as the panel base.\r
110         this.MainNode = oDocument.body.appendChild( oDocument.createElement('DIV') ) ;\r
111 \r
112         // The "float" property must be set so Firefox calculates the size correctly.\r
113         this.MainNode.style.cssFloat = this.IsRTL ? 'right' : 'left' ;\r
114 }\r
115 \r
116 \r
117 FCKPanel.prototype.AppendStyleSheet = function( styleSheet )\r
118 {\r
119         FCKTools.AppendStyleSheet( this.Document, styleSheet ) ;\r
120 }\r
121 \r
122 FCKPanel.prototype.Preload = function( x, y, relElement )\r
123 {\r
124         // The offsetWidth and offsetHeight properties are not available if the\r
125         // element is not visible. So we must "show" the popup with no size to\r
126         // be able to use that values in the second call (IE only).\r
127         if ( this._Popup )\r
128                 this._Popup.show( x, y, 0, 0, relElement ) ;\r
129 }\r
130 \r
131 // Workaround for IE7 problem. See #1982\r
132 // Submenus are restricted to the size of its parent, so we increase it as needed.\r
133 // Returns true if the panel has been repositioned\r
134 FCKPanel.prototype.ResizeForSubpanel = function( panel, width, height )\r
135 {\r
136         if ( !FCKBrowserInfo.IsIE7 )\r
137                 return false ;\r
138 \r
139         if ( !this._Popup.isOpen )\r
140         {\r
141                 this.Subpanel = null ;\r
142                 return false ;\r
143         }\r
144 \r
145         // If we are resetting the extra space\r
146         if ( width == 0 && height == 0 )\r
147         {\r
148                 // Another subpanel is being shown, so we must not shrink back\r
149                 if (this.Subpanel !== panel)\r
150                         return false ;\r
151 \r
152                 // Reset values.\r
153                 // We leave the IncreasedY untouched to avoid vertical movement of the\r
154                 // menu if the submenu is higher than the main menu.\r
155                 this.Subpanel = null ;\r
156                 this.IncreasedX = 0 ;\r
157         }\r
158         else\r
159         {\r
160                 this.Subpanel = panel ;\r
161                 // If the panel has already been increased enough, get out\r
162                 if ( ( this.IncreasedX >= width ) && ( this.IncreasedY >= height ) )\r
163                         return false ;\r
164 \r
165                 this.IncreasedX = Math.max( this.IncreasedX, width ) ;\r
166                 this.IncreasedY = Math.max( this.IncreasedY, height ) ;\r
167         }\r
168 \r
169         var x = this.ShowRect.x ;\r
170         var w = this.IncreasedX ;\r
171         if ( this.IsRTL )\r
172                 x  = x - w ;\r
173 \r
174         // Horizontally increase as needed (sum of widths).\r
175         // Vertically, use only the maximum of this menu or the submenu\r
176         var finalWidth = this.ShowRect.w + w ;\r
177         var finalHeight = Math.max( this.ShowRect.h, this.IncreasedY ) ;\r
178         if ( this.ParentPanel )\r
179                 this.ParentPanel.ResizeForSubpanel( this, finalWidth, finalHeight ) ;\r
180         this._Popup.show( x, this.ShowRect.y, finalWidth, finalHeight, this.RelativeElement ) ;\r
181 \r
182         return this.IsRTL ;\r
183 }\r
184 \r
185 FCKPanel.prototype.Show = function( x, y, relElement, width, height )\r
186 {\r
187         var iMainWidth ;\r
188         var eMainNode = this.MainNode ;\r
189 \r
190         if ( this._Popup )\r
191         {\r
192                 // The offsetWidth and offsetHeight properties are not available if the\r
193                 // element is not visible. So we must "show" the popup with no size to\r
194                 // be able to use that values in the second call.\r
195                 this._Popup.show( x, y, 0, 0, relElement ) ;\r
196 \r
197                 // The following lines must be place after the above "show", otherwise it\r
198                 // doesn't has the desired effect.\r
199                 FCKDomTools.SetElementStyles( eMainNode,\r
200                         {\r
201                                 width   : width ? width + 'px' : '',\r
202                                 height  : height ? height + 'px' : ''\r
203                         } ) ;\r
204 \r
205                 iMainWidth = eMainNode.offsetWidth ;\r
206 \r
207                 if ( FCKBrowserInfo.IsIE7 )\r
208                 {\r
209                         if (this.ParentPanel && this.ParentPanel.ResizeForSubpanel(this, iMainWidth, eMainNode.offsetHeight) )\r
210                         {\r
211                                 // As the parent has moved, allow the browser to update its internal data, so the new position is correct.\r
212                                 FCKTools.RunFunction( this.Show, this, [x, y, relElement] ) ;\r
213                                 return ;\r
214                         }\r
215                 }\r
216 \r
217                 if ( this.IsRTL )\r
218                 {\r
219                         if ( this.IsContextMenu )\r
220                                 x  = x - iMainWidth + 1 ;\r
221                         else if ( relElement )\r
222                                 x  = ( x * -1 ) + relElement.offsetWidth - iMainWidth ;\r
223                 }\r
224 \r
225                 if ( FCKBrowserInfo.IsIE7 )\r
226                 {\r
227                         // Store the values that will be used by the ResizeForSubpanel function\r
228                         this.ShowRect = {x:x, y:y, w:iMainWidth, h:eMainNode.offsetHeight} ;\r
229                         this.IncreasedX = 0 ;\r
230                         this.IncreasedY = 0 ;\r
231                         this.RelativeElement = relElement ;\r
232                 }\r
233 \r
234                 // Second call: Show the Popup at the specified location, with the correct size.\r
235                 this._Popup.show( x, y, iMainWidth, eMainNode.offsetHeight, relElement ) ;\r
236 \r
237                 if ( this.OnHide )\r
238                 {\r
239                         if ( this._Timer )\r
240                                 CheckPopupOnHide.call( this, true ) ;\r
241 \r
242                         this._Timer = FCKTools.SetInterval( CheckPopupOnHide, 100, this ) ;\r
243                 }\r
244         }\r
245         else\r
246         {\r
247                 // Do not fire OnBlur while the panel is opened.\r
248                 if ( typeof( FCK.ToolbarSet.CurrentInstance.FocusManager ) != 'undefined' )\r
249                         FCK.ToolbarSet.CurrentInstance.FocusManager.Lock() ;\r
250 \r
251                 if ( this.ParentPanel )\r
252                 {\r
253                         this.ParentPanel.Lock() ;\r
254 \r
255                         // Due to a bug on FF3, we must ensure that the parent panel will\r
256                         // blur (#1584).\r
257                         FCKPanel_Window_OnBlur( null, this.ParentPanel ) ;\r
258                 }\r
259 \r
260                 // Toggle the iframe scrolling attribute to prevent the panel\r
261                 // scrollbars from disappearing in FF Mac. (#191)\r
262                 if ( FCKBrowserInfo.IsGecko && FCKBrowserInfo.IsMac )\r
263                 {\r
264                         this._IFrame.scrolling = '' ;\r
265                         FCKTools.RunFunction( function(){ this._IFrame.scrolling = 'no'; }, this ) ;\r
266                 }\r
267 \r
268                 // Be sure we'll not have more than one Panel opened at the same time.\r
269                 // Do not unlock focus manager here because we're displaying another floating panel\r
270                 // instead of returning the editor to a "no panel" state (Bug #1514).\r
271                 if ( FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel &&\r
272                                 FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel != this )\r
273                         FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel.Hide( false, true ) ;\r
274 \r
275                 FCKDomTools.SetElementStyles( eMainNode,\r
276                         {\r
277                                 width   : width ? width + 'px' : '',\r
278                                 height  : height ? height + 'px' : ''\r
279                         } ) ;\r
280 \r
281                 iMainWidth = eMainNode.offsetWidth ;\r
282 \r
283                 if ( !width )   this._IFrame.width      = 1 ;\r
284                 if ( !height )  this._IFrame.height     = 1 ;\r
285 \r
286                 // This is weird... but with Firefox, we must get the offsetWidth before\r
287                 // setting the _IFrame size (which returns "0"), and then after that,\r
288                 // to return the correct width. Remove the first step and it will not\r
289                 // work when the editor is in RTL.\r
290                 //\r
291                 // The "|| eMainNode.firstChild.offsetWidth" part has been added\r
292                 // for Opera compatibility (see #570).\r
293                 iMainWidth = eMainNode.offsetWidth || eMainNode.firstChild.offsetWidth ;\r
294 \r
295                 // Base the popup coordinates upon the coordinates of relElement.\r
296                 var oPos = FCKTools.GetDocumentPosition( this._Window,\r
297                         relElement.nodeType == 9 ?\r
298                                 ( FCKTools.IsStrictMode( relElement ) ? relElement.documentElement : relElement.body ) :\r
299                                 relElement ) ;\r
300 \r
301                 // Minus the offsets provided by any positioned parent element of the panel iframe.\r
302                 var positionedAncestor = FCKDomTools.GetPositionedAncestor( this._IFrame.parentNode ) ;\r
303                 if ( positionedAncestor )\r
304                 {\r
305                         var nPos = FCKTools.GetDocumentPosition( FCKTools.GetElementWindow( positionedAncestor ), positionedAncestor ) ;\r
306                         oPos.x -= nPos.x ;\r
307                         oPos.y -= nPos.y ;\r
308                 }\r
309 \r
310                 if ( this.IsRTL && !this.IsContextMenu )\r
311                         x = ( x * -1 ) ;\r
312 \r
313                 x += oPos.x ;\r
314                 y += oPos.y ;\r
315 \r
316                 if ( this.IsRTL )\r
317                 {\r
318                         if ( this.IsContextMenu )\r
319                                 x  = x - iMainWidth + 1 ;\r
320                         else if ( relElement )\r
321                                 x  = x + relElement.offsetWidth - iMainWidth ;\r
322                 }\r
323                 else\r
324                 {\r
325                         var oViewPaneSize = FCKTools.GetViewPaneSize( this._Window ) ;\r
326                         var oScrollPosition = FCKTools.GetScrollPosition( this._Window ) ;\r
327 \r
328                         var iViewPaneHeight     = oViewPaneSize.Height + oScrollPosition.Y ;\r
329                         var iViewPaneWidth      = oViewPaneSize.Width + oScrollPosition.X ;\r
330 \r
331                         if ( ( x + iMainWidth ) > iViewPaneWidth )\r
332                                 x -= x + iMainWidth - iViewPaneWidth ;\r
333 \r
334                         if ( ( y + eMainNode.offsetHeight ) > iViewPaneHeight )\r
335                                 y -= y + eMainNode.offsetHeight - iViewPaneHeight ;\r
336                 }\r
337 \r
338                 // Set the context menu DIV in the specified location.\r
339                 FCKDomTools.SetElementStyles( this._IFrame,\r
340                         {\r
341                                 left    : x + 'px',\r
342                                 top             : y + 'px'\r
343                         } ) ;\r
344 \r
345                 // Move the focus to the IFRAME so we catch the "onblur".\r
346                 this._IFrame.contentWindow.focus() ;\r
347                 this._IsOpened = true ;\r
348 \r
349                 var me = this ;\r
350                 this._resizeTimer = setTimeout( function()\r
351                         {\r
352                                 var iWidth = eMainNode.offsetWidth || eMainNode.firstChild.offsetWidth ;\r
353                                 var iHeight = eMainNode.offsetHeight ;\r
354                                 me._IFrame.style.width = iWidth + 'px' ;\r
355                                 me._IFrame.style.height = iHeight + 'px' ;\r
356 \r
357                         }, 0 ) ;\r
358 \r
359                 FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel = this ;\r
360         }\r
361 \r
362         FCKTools.RunFunction( this.OnShow, this ) ;\r
363 }\r
364 \r
365 FCKPanel.prototype.Hide = function( ignoreOnHide, ignoreFocusManagerUnlock )\r
366 {\r
367         if ( this._Popup )\r
368                 this._Popup.hide() ;\r
369         else\r
370         {\r
371                 if ( !this._IsOpened || this._LockCounter > 0 )\r
372                         return ;\r
373 \r
374                 // Enable the editor to fire the "OnBlur".\r
375                 if ( typeof( FCKFocusManager ) != 'undefined' && !ignoreFocusManagerUnlock )\r
376                         FCKFocusManager.Unlock() ;\r
377 \r
378                 // It is better to set the sizes to 0, otherwise Firefox would have\r
379                 // rendering problems.\r
380                 this._IFrame.style.width = this._IFrame.style.height = '0px' ;\r
381 \r
382                 this._IsOpened = false ;\r
383 \r
384                 if ( this._resizeTimer )\r
385                 {\r
386                         clearTimeout( this._resizeTimer ) ;\r
387                         this._resizeTimer = null ;\r
388                 }\r
389 \r
390                 if ( this.ParentPanel )\r
391                         this.ParentPanel.Unlock() ;\r
392 \r
393                 if ( !ignoreOnHide )\r
394                         FCKTools.RunFunction( this.OnHide, this ) ;\r
395         }\r
396 }\r
397 \r
398 FCKPanel.prototype.CheckIsOpened = function()\r
399 {\r
400         if ( this._Popup )\r
401                 return this._Popup.isOpen ;\r
402         else\r
403                 return this._IsOpened ;\r
404 }\r
405 \r
406 FCKPanel.prototype.CreateChildPanel = function()\r
407 {\r
408         var oWindow = this._Popup ? FCKTools.GetDocumentWindow( this.Document ) : this._Window ;\r
409 \r
410         var oChildPanel = new FCKPanel( oWindow ) ;\r
411         oChildPanel.ParentPanel = this ;\r
412 \r
413         return oChildPanel ;\r
414 }\r
415 \r
416 FCKPanel.prototype.Lock = function()\r
417 {\r
418         this._LockCounter++ ;\r
419 }\r
420 \r
421 FCKPanel.prototype.Unlock = function()\r
422 {\r
423         if ( --this._LockCounter == 0 && !this.HasFocus )\r
424                 this.Hide() ;\r
425 }\r
426 \r
427 /* Events */\r
428 \r
429 function FCKPanel_Window_OnFocus( e, panel )\r
430 {\r
431         panel.HasFocus = true ;\r
432 }\r
433 \r
434 function FCKPanel_Window_OnBlur( e, panel )\r
435 {\r
436         panel.HasFocus = false ;\r
437 \r
438         if ( panel._LockCounter == 0 )\r
439                 FCKTools.RunFunction( panel.Hide, panel ) ;\r
440 }\r
441 \r
442 function CheckPopupOnHide( forceHide )\r
443 {\r
444         if ( forceHide || !this._Popup.isOpen )\r
445         {\r
446                 window.clearInterval( this._Timer ) ;\r
447                 this._Timer = null ;\r
448 \r
449                 if (this._Popup && this.ParentPanel && !forceHide)\r
450                         this.ParentPanel.ResizeForSubpanel(this, 0, 0) ;\r
451 \r
452                 FCKTools.RunFunction( this.OnHide, this ) ;\r
453         }\r
454 }\r
455 \r
456 function FCKPanel_Cleanup()\r
457 {\r
458         this._Popup = null ;\r
459         this._Window = null ;\r
460         this.Document = null ;\r
461         this.MainNode = null ;\r
462         this.RelativeElement = null ;\r
463 }\r