import rt 3.8.7
[freeside.git] / rt / share / html / NoAuth / RichText / FCKeditor / editor / _source / internals / fck.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  * Creation and initialization of the "FCK" object. This is the main object\r
22  * that represents an editor instance.\r
23  */\r
24 \r
25 // FCK represents the active editor instance.\r
26 var FCK =\r
27 {\r
28         Name                    : FCKURLParams[ 'InstanceName' ],\r
29         Status                  : FCK_STATUS_NOTLOADED,\r
30         EditMode                : FCK_EDITMODE_WYSIWYG,\r
31         Toolbar                 : null,\r
32         HasFocus                : false,\r
33         DataProcessor   : new FCKDataProcessor(),\r
34 \r
35         GetInstanceObject       : (function()\r
36         {\r
37                 var w = window ;\r
38                 return function( name )\r
39                 {\r
40                         return w[name] ;\r
41                 }\r
42         })(),\r
43 \r
44         AttachToOnSelectionChange : function( functionPointer )\r
45         {\r
46                 this.Events.AttachEvent( 'OnSelectionChange', functionPointer ) ;\r
47         },\r
48 \r
49         GetLinkedFieldValue : function()\r
50         {\r
51                 return this.LinkedField.value ;\r
52         },\r
53 \r
54         GetParentForm : function()\r
55         {\r
56                 return this.LinkedField.form ;\r
57         } ,\r
58 \r
59         // # START : IsDirty implementation\r
60 \r
61         StartupValue : '',\r
62 \r
63         IsDirty : function()\r
64         {\r
65                 if ( this.EditMode == FCK_EDITMODE_SOURCE )\r
66                         return ( this.StartupValue != this.EditingArea.Textarea.value ) ;\r
67                 else\r
68                 {\r
69                         // It can happen switching between design and source mode in Gecko\r
70                         if ( ! this.EditorDocument )\r
71                                 return false ;\r
72 \r
73                         return ( this.StartupValue != this.EditorDocument.body.innerHTML ) ;\r
74                 }\r
75         },\r
76 \r
77         ResetIsDirty : function()\r
78         {\r
79                 if ( this.EditMode == FCK_EDITMODE_SOURCE )\r
80                         this.StartupValue = this.EditingArea.Textarea.value ;\r
81                 else if ( this.EditorDocument.body )\r
82                         this.StartupValue = this.EditorDocument.body.innerHTML ;\r
83         },\r
84 \r
85         // # END : IsDirty implementation\r
86 \r
87         StartEditor : function()\r
88         {\r
89                 this.TempBaseTag = FCKConfig.BaseHref.length > 0 ? '<base href="' + FCKConfig.BaseHref + '" _fcktemp="true"></base>' : '' ;\r
90 \r
91                 // Setup the keystroke handler.\r
92                 var oKeystrokeHandler = FCK.KeystrokeHandler = new FCKKeystrokeHandler() ;\r
93                 oKeystrokeHandler.OnKeystroke = _FCK_KeystrokeHandler_OnKeystroke ;\r
94 \r
95                 // Set the config keystrokes.\r
96                 oKeystrokeHandler.SetKeystrokes( FCKConfig.Keystrokes ) ;\r
97 \r
98                 // In IE7, if the editor tries to access the clipboard by code, a dialog is\r
99                 // shown to the user asking if the application is allowed to access or not.\r
100                 // Due to the IE implementation of it, the KeystrokeHandler will not work\r
101                 //well in this case, so we must leave the pasting keys to have their default behavior.\r
102                 if ( FCKBrowserInfo.IsIE7 )\r
103                 {\r
104                         if ( ( CTRL + 86 /*V*/ ) in oKeystrokeHandler.Keystrokes )\r
105                                 oKeystrokeHandler.SetKeystrokes( [ CTRL + 86, true ] ) ;\r
106 \r
107                         if ( ( SHIFT + 45 /*INS*/ ) in oKeystrokeHandler.Keystrokes )\r
108                                 oKeystrokeHandler.SetKeystrokes( [ SHIFT + 45, true ] ) ;\r
109                 }\r
110 \r
111                 // Retain default behavior for Ctrl-Backspace. (Bug #362)\r
112                 oKeystrokeHandler.SetKeystrokes( [ CTRL + 8, true ] ) ;\r
113 \r
114                 this.EditingArea = new FCKEditingArea( document.getElementById( 'xEditingArea' ) ) ;\r
115                 this.EditingArea.FFSpellChecker = FCKConfig.FirefoxSpellChecker ;\r
116 \r
117                 // Set the editor's startup contents.\r
118                 this.SetData( this.GetLinkedFieldValue(), true ) ;\r
119 \r
120                 // Tab key handling for source mode.\r
121                 FCKTools.AddEventListener( document, "keydown", this._TabKeyHandler ) ;\r
122 \r
123                 // Add selection change listeners. They must be attached only once.\r
124                 this.AttachToOnSelectionChange( _FCK_PaddingNodeListener ) ;\r
125                 if ( FCKBrowserInfo.IsGecko )\r
126                         this.AttachToOnSelectionChange( this._ExecCheckEmptyBlock ) ;\r
127 \r
128         },\r
129 \r
130         Focus : function()\r
131         {\r
132                 FCK.EditingArea.Focus() ;\r
133         },\r
134 \r
135         SetStatus : function( newStatus )\r
136         {\r
137                 this.Status = newStatus ;\r
138 \r
139                 if ( newStatus == FCK_STATUS_ACTIVE )\r
140                 {\r
141                         FCKFocusManager.AddWindow( window, true ) ;\r
142 \r
143                         if ( FCKBrowserInfo.IsIE )\r
144                                 FCKFocusManager.AddWindow( window.frameElement, true ) ;\r
145 \r
146                         // Force the focus in the editor.\r
147                         if ( FCKConfig.StartupFocus )\r
148                                 FCK.Focus() ;\r
149                 }\r
150 \r
151                 this.Events.FireEvent( 'OnStatusChange', newStatus ) ;\r
152 \r
153         },\r
154 \r
155         // Fixes the body by moving all inline and text nodes to appropriate block\r
156         // elements.\r
157         FixBody : function()\r
158         {\r
159                 var sBlockTag = FCKConfig.EnterMode ;\r
160 \r
161                 // In 'br' mode, no fix must be done.\r
162                 if ( sBlockTag != 'p' && sBlockTag != 'div' )\r
163                         return ;\r
164 \r
165                 var oDocument = this.EditorDocument ;\r
166 \r
167                 if ( !oDocument )\r
168                         return ;\r
169 \r
170                 var oBody = oDocument.body ;\r
171 \r
172                 if ( !oBody )\r
173                         return ;\r
174 \r
175                 FCKDomTools.TrimNode( oBody ) ;\r
176 \r
177                 var oNode = oBody.firstChild ;\r
178                 var oNewBlock ;\r
179 \r
180                 while ( oNode )\r
181                 {\r
182                         var bMoveNode = false ;\r
183 \r
184                         switch ( oNode.nodeType )\r
185                         {\r
186                                 // Element Node.\r
187                                 case 1 :\r
188                                         var nodeName = oNode.nodeName.toLowerCase() ;\r
189                                         if ( !FCKListsLib.BlockElements[ nodeName ] &&\r
190                                                         nodeName != 'li' &&\r
191                                                         !oNode.getAttribute('_fckfakelement') &&\r
192                                                         oNode.getAttribute('_moz_dirty') == null )\r
193                                                 bMoveNode = true ;\r
194                                         break ;\r
195 \r
196                                 // Text Node.\r
197                                 case 3 :\r
198                                         // Ignore space only or empty text.\r
199                                         if ( oNewBlock || oNode.nodeValue.Trim().length > 0 )\r
200                                                 bMoveNode = true ;\r
201                                         break;\r
202 \r
203                                 // Comment Node\r
204                                 case 8 :\r
205                                         if ( oNewBlock )\r
206                                                 bMoveNode = true ;\r
207                                         break;\r
208                         }\r
209 \r
210                         if ( bMoveNode )\r
211                         {\r
212                                 var oParent = oNode.parentNode ;\r
213 \r
214                                 if ( !oNewBlock )\r
215                                         oNewBlock = oParent.insertBefore( oDocument.createElement( sBlockTag ), oNode ) ;\r
216 \r
217                                 oNewBlock.appendChild( oParent.removeChild( oNode ) ) ;\r
218 \r
219                                 oNode = oNewBlock.nextSibling ;\r
220                         }\r
221                         else\r
222                         {\r
223                                 if ( oNewBlock )\r
224                                 {\r
225                                         FCKDomTools.TrimNode( oNewBlock ) ;\r
226                                         oNewBlock = null ;\r
227                                 }\r
228                                 oNode = oNode.nextSibling ;\r
229                         }\r
230                 }\r
231 \r
232                 if ( oNewBlock )\r
233                         FCKDomTools.TrimNode( oNewBlock ) ;\r
234         },\r
235 \r
236         GetData : function( format )\r
237         {\r
238                 // We assume that if the user is in source editing, the editor value must\r
239                 // represent the exact contents of the source, as the user wanted it to be.\r
240                 if ( FCK.EditMode == FCK_EDITMODE_SOURCE )\r
241                                 return FCK.EditingArea.Textarea.value ;\r
242 \r
243                 this.FixBody() ;\r
244 \r
245                 var oDoc = FCK.EditorDocument ;\r
246                 if ( !oDoc )\r
247                         return null ;\r
248 \r
249                 var isFullPage = FCKConfig.FullPage ;\r
250 \r
251                 // Call the Data Processor to generate the output data.\r
252                 var data = FCK.DataProcessor.ConvertToDataFormat(\r
253                         isFullPage ? oDoc.documentElement : oDoc.body,\r
254                         !isFullPage,\r
255                         FCKConfig.IgnoreEmptyParagraphValue,\r
256                         format ) ;\r
257 \r
258                 // Restore protected attributes.\r
259                 data = FCK.ProtectEventsRestore( data ) ;\r
260 \r
261                 if ( FCKBrowserInfo.IsIE )\r
262                         data = data.replace( FCKRegexLib.ToReplace, '$1' ) ;\r
263 \r
264                 if ( isFullPage )\r
265                 {\r
266                         if ( FCK.DocTypeDeclaration && FCK.DocTypeDeclaration.length > 0 )\r
267                                 data = FCK.DocTypeDeclaration + '\n' + data ;\r
268 \r
269                         if ( FCK.XmlDeclaration && FCK.XmlDeclaration.length > 0 )\r
270                                 data = FCK.XmlDeclaration + '\n' + data ;\r
271                 }\r
272 \r
273                 return FCKConfig.ProtectedSource.Revert( data ) ;\r
274         },\r
275 \r
276         UpdateLinkedField : function()\r
277         {\r
278                 var value = FCK.GetXHTML( FCKConfig.FormatOutput ) ;\r
279 \r
280                 if ( FCKConfig.HtmlEncodeOutput )\r
281                         value = FCKTools.HTMLEncode( value ) ;\r
282 \r
283                 FCK.LinkedField.value = value ;\r
284                 FCK.Events.FireEvent( 'OnAfterLinkedFieldUpdate' ) ;\r
285         },\r
286 \r
287         RegisteredDoubleClickHandlers : new Object(),\r
288 \r
289         OnDoubleClick : function( element )\r
290         {\r
291                 var oCalls = FCK.RegisteredDoubleClickHandlers[ element.tagName.toUpperCase() ] ;\r
292 \r
293                 if ( oCalls )\r
294                 {\r
295                         for ( var i = 0 ; i < oCalls.length ; i++ )\r
296                                 oCalls[ i ]( element ) ;\r
297                 }\r
298 \r
299                 // Generic handler for any element\r
300                 oCalls = FCK.RegisteredDoubleClickHandlers[ '*' ] ;\r
301 \r
302                 if ( oCalls )\r
303                 {\r
304                         for ( var i = 0 ; i < oCalls.length ; i++ )\r
305                                 oCalls[ i ]( element ) ;\r
306                 }\r
307 \r
308         },\r
309 \r
310         // Register objects that can handle double click operations.\r
311         RegisterDoubleClickHandler : function( handlerFunction, tag )\r
312         {\r
313                 var nodeName = tag || '*' ;\r
314                 nodeName = nodeName.toUpperCase() ;\r
315 \r
316                 var aTargets ;\r
317 \r
318                 if ( !( aTargets = FCK.RegisteredDoubleClickHandlers[ nodeName ] ) )\r
319                         FCK.RegisteredDoubleClickHandlers[ nodeName ] = [ handlerFunction ] ;\r
320                 else\r
321                 {\r
322                         // Check that the event handler isn't already registered with the same listener\r
323                         // It doesn't detect function pointers belonging to an object (at least in Gecko)\r
324                         if ( aTargets.IndexOf( handlerFunction ) == -1 )\r
325                                 aTargets.push( handlerFunction ) ;\r
326                 }\r
327 \r
328         },\r
329 \r
330         OnAfterSetHTML : function()\r
331         {\r
332                 FCKDocumentProcessor.Process( FCK.EditorDocument ) ;\r
333                 FCKUndo.SaveUndoStep() ;\r
334 \r
335                 FCK.Events.FireEvent( 'OnSelectionChange' ) ;\r
336                 FCK.Events.FireEvent( 'OnAfterSetHTML' ) ;\r
337         },\r
338 \r
339         // Saves URLs on links and images on special attributes, so they don't change when\r
340         // moving around.\r
341         ProtectUrls : function( html )\r
342         {\r
343                 // <A> href\r
344                 html = html.replace( FCKRegexLib.ProtectUrlsA   , '$& _fcksavedurl=$1' ) ;\r
345 \r
346                 // <IMG> src\r
347                 html = html.replace( FCKRegexLib.ProtectUrlsImg , '$& _fcksavedurl=$1' ) ;\r
348 \r
349                 // <AREA> href\r
350                 html = html.replace( FCKRegexLib.ProtectUrlsArea        , '$& _fcksavedurl=$1' ) ;\r
351 \r
352                 return html ;\r
353         },\r
354 \r
355         // Saves event attributes (like onclick) so they don't get executed while\r
356         // editing.\r
357         ProtectEvents : function( html )\r
358         {\r
359                 return html.replace( FCKRegexLib.TagsWithEvent, _FCK_ProtectEvents_ReplaceTags ) ;\r
360         },\r
361 \r
362         ProtectEventsRestore : function( html )\r
363         {\r
364                 return html.replace( FCKRegexLib.ProtectedEvents, _FCK_ProtectEvents_RestoreEvents ) ;\r
365         },\r
366 \r
367         ProtectTags : function( html )\r
368         {\r
369                 var sTags = FCKConfig.ProtectedTags ;\r
370 \r
371                 // IE doesn't support <abbr> and it breaks it. Let's protect it.\r
372                 if ( FCKBrowserInfo.IsIE )\r
373                         sTags += sTags.length > 0 ? '|ABBR|XML|EMBED|OBJECT' : 'ABBR|XML|EMBED|OBJECT' ;\r
374 \r
375                 var oRegex ;\r
376                 if ( sTags.length > 0 )\r
377                 {\r
378                         oRegex = new RegExp( '<(' + sTags + ')(?!\w|:)', 'gi' ) ;\r
379                         html = html.replace( oRegex, '<FCK:$1' ) ;\r
380 \r
381                         oRegex = new RegExp( '<\/(' + sTags + ')>', 'gi' ) ;\r
382                         html = html.replace( oRegex, '<\/FCK:$1>' ) ;\r
383                 }\r
384 \r
385                 // Protect some empty elements. We must do it separately because the\r
386                 // original tag may not contain the closing slash, like <hr>:\r
387                 //              - <meta> tags get executed, so if you have a redirect meta, the\r
388                 //                content will move to the target page.\r
389                 //              - <hr> may destroy the document structure if not well\r
390                 //                positioned. The trick is protect it here and restore them in\r
391                 //                the FCKDocumentProcessor.\r
392                 sTags = 'META' ;\r
393                 if ( FCKBrowserInfo.IsIE )\r
394                         sTags += '|HR' ;\r
395 \r
396                 oRegex = new RegExp( '<((' + sTags + ')(?=\\s|>|/)[\\s\\S]*?)/?>', 'gi' ) ;\r
397                 html = html.replace( oRegex, '<FCK:$1 />' ) ;\r
398 \r
399                 return html ;\r
400         },\r
401 \r
402         SetData : function( data, resetIsDirty )\r
403         {\r
404                 this.EditingArea.Mode = FCK.EditMode ;\r
405 \r
406                 // If there was an onSelectionChange listener in IE we must remove it to avoid crashes #1498\r
407                 if ( FCKBrowserInfo.IsIE && FCK.EditorDocument )\r
408                 {\r
409                         FCK.EditorDocument.detachEvent("onselectionchange", Doc_OnSelectionChange ) ;\r
410                 }\r
411 \r
412                 FCKTempBin.Reset() ;\r
413 \r
414                 // Bug #2469: SelectionData.createRange becomes undefined after the editor\r
415                 // iframe is changed by FCK.SetData().\r
416                 FCK.Selection.Release() ;\r
417 \r
418                 if ( FCK.EditMode == FCK_EDITMODE_WYSIWYG )\r
419                 {\r
420                         // Save the resetIsDirty for later use (async)\r
421                         this._ForceResetIsDirty = ( resetIsDirty === true ) ;\r
422 \r
423                         // Protect parts of the code that must remain untouched (and invisible)\r
424                         // during editing.\r
425                         data = FCKConfig.ProtectedSource.Protect( data ) ;\r
426 \r
427                         // Call the Data Processor to transform the data.\r
428                         data = FCK.DataProcessor.ConvertToHtml( data ) ;\r
429 \r
430                         // Fix for invalid self-closing tags (see #152).\r
431                         data = data.replace( FCKRegexLib.InvalidSelfCloseTags, '$1></$2>' ) ;\r
432 \r
433                         // Protect event attributes (they could get fired in the editing area).\r
434                         data = FCK.ProtectEvents( data ) ;\r
435 \r
436                         // Protect some things from the browser itself.\r
437                         data = FCK.ProtectUrls( data ) ;\r
438                         data = FCK.ProtectTags( data ) ;\r
439 \r
440                         // Insert the base tag (FCKConfig.BaseHref), if not exists in the source.\r
441                         // The base must be the first tag in the HEAD, to get relative\r
442                         // links on styles, for example.\r
443                         if ( FCK.TempBaseTag.length > 0 && !FCKRegexLib.HasBaseTag.test( data ) )\r
444                                 data = data.replace( FCKRegexLib.HeadOpener, '$&' + FCK.TempBaseTag ) ;\r
445 \r
446                         // Build the HTML for the additional things we need on <head>.\r
447                         var sHeadExtra = '' ;\r
448 \r
449                         if ( !FCKConfig.FullPage )\r
450                                 sHeadExtra += _FCK_GetEditorAreaStyleTags() ;\r
451 \r
452                         if ( FCKBrowserInfo.IsIE )\r
453                                 sHeadExtra += FCK._GetBehaviorsStyle() ;\r
454                         else if ( FCKConfig.ShowBorders )\r
455                                 sHeadExtra += FCKTools.GetStyleHtml( FCK_ShowTableBordersCSS, true ) ;\r
456 \r
457                         sHeadExtra += FCKTools.GetStyleHtml( FCK_InternalCSS, true ) ;\r
458 \r
459                         // Attention: do not change it before testing it well (sample07)!\r
460                         // This is tricky... if the head ends with <meta ... content type>,\r
461                         // Firefox will break. But, it works if we place our extra stuff as\r
462                         // the last elements in the HEAD.\r
463                         data = data.replace( FCKRegexLib.HeadCloser, sHeadExtra + '$&' ) ;\r
464 \r
465                         // Load the HTML in the editing area.\r
466                         this.EditingArea.OnLoad = _FCK_EditingArea_OnLoad ;\r
467                         this.EditingArea.Start( data ) ;\r
468                 }\r
469                 else\r
470                 {\r
471                         // Remove the references to the following elements, as the editing area\r
472                         // IFRAME will be removed.\r
473                         FCK.EditorWindow        = null ;\r
474                         FCK.EditorDocument      = null ;\r
475                         FCKDomTools.PaddingNode = null ;\r
476 \r
477                         this.EditingArea.OnLoad = null ;\r
478                         this.EditingArea.Start( data ) ;\r
479 \r
480                         // Enables the context menu in the textarea.\r
481                         this.EditingArea.Textarea._FCKShowContextMenu = true ;\r
482 \r
483                         // Removes the enter key handler.\r
484                         FCK.EnterKeyHandler = null ;\r
485 \r
486                         if ( resetIsDirty )\r
487                                 this.ResetIsDirty() ;\r
488 \r
489                         // Listen for keystroke events.\r
490                         FCK.KeystrokeHandler.AttachToElement( this.EditingArea.Textarea ) ;\r
491 \r
492                         this.EditingArea.Textarea.focus() ;\r
493 \r
494                         FCK.Events.FireEvent( 'OnAfterSetHTML' ) ;\r
495                 }\r
496 \r
497                 if ( FCKBrowserInfo.IsGecko )\r
498                         window.onresize() ;\r
499         },\r
500 \r
501         // This collection is used by the browser specific implementations to tell\r
502         // which named commands must be handled separately.\r
503         RedirectNamedCommands : new Object(),\r
504 \r
505         ExecuteNamedCommand : function( commandName, commandParameter, noRedirect, noSaveUndo )\r
506         {\r
507                 if ( !noSaveUndo )\r
508                         FCKUndo.SaveUndoStep() ;\r
509 \r
510                 if ( !noRedirect && FCK.RedirectNamedCommands[ commandName ] != null )\r
511                         FCK.ExecuteRedirectedNamedCommand( commandName, commandParameter ) ;\r
512                 else\r
513                 {\r
514                         FCK.Focus() ;\r
515                         FCK.EditorDocument.execCommand( commandName, false, commandParameter ) ;\r
516                         FCK.Events.FireEvent( 'OnSelectionChange' ) ;\r
517                 }\r
518 \r
519                 if ( !noSaveUndo )\r
520                 FCKUndo.SaveUndoStep() ;\r
521         },\r
522 \r
523         GetNamedCommandState : function( commandName )\r
524         {\r
525                 try\r
526                 {\r
527 \r
528                         // Bug #50 : Safari never returns positive state for the Paste command, override that.\r
529                         if ( FCKBrowserInfo.IsSafari && FCK.EditorWindow && commandName.IEquals( 'Paste' ) )\r
530                                 return FCK_TRISTATE_OFF ;\r
531 \r
532                         if ( !FCK.EditorDocument.queryCommandEnabled( commandName ) )\r
533                                 return FCK_TRISTATE_DISABLED ;\r
534                         else\r
535                         {\r
536                                 return FCK.EditorDocument.queryCommandState( commandName ) ? FCK_TRISTATE_ON : FCK_TRISTATE_OFF ;\r
537                         }\r
538                 }\r
539                 catch ( e )\r
540                 {\r
541                         return FCK_TRISTATE_OFF ;\r
542                 }\r
543         },\r
544 \r
545         GetNamedCommandValue : function( commandName )\r
546         {\r
547                 var sValue = '' ;\r
548                 var eState = FCK.GetNamedCommandState( commandName ) ;\r
549 \r
550                 if ( eState == FCK_TRISTATE_DISABLED )\r
551                         return null ;\r
552 \r
553                 try\r
554                 {\r
555                         sValue = this.EditorDocument.queryCommandValue( commandName ) ;\r
556                 }\r
557                 catch(e) {}\r
558 \r
559                 return sValue ? sValue : '' ;\r
560         },\r
561 \r
562         Paste : function( _callListenersOnly )\r
563         {\r
564                 // First call 'OnPaste' listeners.\r
565                 if ( FCK.Status != FCK_STATUS_COMPLETE || !FCK.Events.FireEvent( 'OnPaste' ) )\r
566                         return false ;\r
567 \r
568                 // Then call the default implementation.\r
569                 return _callListenersOnly || FCK._ExecPaste() ;\r
570         },\r
571 \r
572         PasteFromWord : function()\r
573         {\r
574                 FCKDialog.OpenDialog( 'FCKDialog_Paste', FCKLang.PasteFromWord, 'dialog/fck_paste.html', 400, 330, 'Word' ) ;\r
575         },\r
576 \r
577         Preview : function()\r
578         {\r
579                 var sHTML ;\r
580 \r
581                 if ( FCKConfig.FullPage )\r
582                 {\r
583                         if ( FCK.TempBaseTag.length > 0 )\r
584                                 sHTML = FCK.TempBaseTag + FCK.GetXHTML() ;\r
585                         else\r
586                                 sHTML = FCK.GetXHTML() ;\r
587                 }\r
588                 else\r
589                 {\r
590                         sHTML =\r
591                                 FCKConfig.DocType +\r
592                                 '<html dir="' + FCKConfig.ContentLangDirection + '">' +\r
593                                 '<head>' +\r
594                                 FCK.TempBaseTag +\r
595                                 '<title>' + FCKLang.Preview + '</title>' +\r
596                                 _FCK_GetEditorAreaStyleTags() +\r
597                                 '</head><body' + FCKConfig.GetBodyAttributes() + '>' +\r
598                                 FCK.GetXHTML() +\r
599                                 '</body></html>' ;\r
600                 }\r
601 \r
602                 var iWidth      = FCKConfig.ScreenWidth * 0.8 ;\r
603                 var iHeight     = FCKConfig.ScreenHeight * 0.7 ;\r
604                 var iLeft       = ( FCKConfig.ScreenWidth - iWidth ) / 2 ;\r
605 \r
606                 var sOpenUrl = '' ;\r
607                 if ( FCK_IS_CUSTOM_DOMAIN && FCKBrowserInfo.IsIE)\r
608                 {\r
609                         window._FCKHtmlToLoad = sHTML ;\r
610                         sOpenUrl = 'javascript:void( (function(){' +\r
611                                 'document.open() ;' +\r
612                                 'document.domain="' + document.domain + '" ;' +\r
613                                 'document.write( window.opener._FCKHtmlToLoad );' +\r
614                                 'document.close() ;' +\r
615                                 'window.opener._FCKHtmlToLoad = null ;' +\r
616                                 '})() )' ;\r
617                 }\r
618 \r
619                 var oWindow = window.open( sOpenUrl, null, 'toolbar=yes,location=no,status=yes,menubar=yes,scrollbars=yes,resizable=yes,width=' + iWidth + ',height=' + iHeight + ',left=' + iLeft ) ;\r
620 \r
621                 if ( !FCK_IS_CUSTOM_DOMAIN || !FCKBrowserInfo.IsIE)\r
622                 {\r
623                         oWindow.document.write( sHTML );\r
624                         oWindow.document.close();\r
625                 }\r
626 \r
627         },\r
628 \r
629         SwitchEditMode : function( noUndo )\r
630         {\r
631                 var bIsWysiwyg = ( FCK.EditMode == FCK_EDITMODE_WYSIWYG ) ;\r
632 \r
633                 // Save the current IsDirty state, so we may restore it after the switch.\r
634                 var bIsDirty = FCK.IsDirty() ;\r
635 \r
636                 var sHtml ;\r
637 \r
638                 // Update the HTML in the view output to show, also update\r
639                 // FCKTempBin for IE to avoid #2263.\r
640                 if ( bIsWysiwyg )\r
641                 {\r
642                         FCKCommands.GetCommand( 'ShowBlocks' ).SaveState() ;\r
643                         if ( !noUndo && FCKBrowserInfo.IsIE )\r
644                                 FCKUndo.SaveUndoStep() ;\r
645 \r
646                         sHtml = FCK.GetXHTML( FCKConfig.FormatSource ) ;\r
647 \r
648                         if ( FCKBrowserInfo.IsIE )\r
649                                 FCKTempBin.ToHtml() ;\r
650 \r
651                         if ( sHtml == null )\r
652                                 return false ;\r
653                 }\r
654                 else\r
655                         sHtml = this.EditingArea.Textarea.value ;\r
656 \r
657                 FCK.EditMode = bIsWysiwyg ? FCK_EDITMODE_SOURCE : FCK_EDITMODE_WYSIWYG ;\r
658 \r
659                 FCK.SetData( sHtml, !bIsDirty ) ;\r
660 \r
661                 // Set the Focus.\r
662                 FCK.Focus() ;\r
663 \r
664                 // Update the toolbar (Running it directly causes IE to fail).\r
665                 FCKTools.RunFunction( FCK.ToolbarSet.RefreshModeState, FCK.ToolbarSet ) ;\r
666 \r
667                 return true ;\r
668         },\r
669 \r
670         InsertElement : function( element )\r
671         {\r
672                 // The parameter may be a string (element name), so transform it in an element.\r
673                 if ( typeof element == 'string' )\r
674                         element = this.EditorDocument.createElement( element ) ;\r
675 \r
676                 var elementName = element.nodeName.toLowerCase() ;\r
677 \r
678                 FCKSelection.Restore() ;\r
679 \r
680                 // Create a range for the selection. V3 will have a new selection\r
681                 // object that may internally supply this feature.\r
682                 var range = new FCKDomRange( this.EditorWindow ) ;\r
683 \r
684                 // Move to the selection and delete it.\r
685                 range.MoveToSelection() ;\r
686                 range.DeleteContents() ;\r
687 \r
688                 if ( FCKListsLib.BlockElements[ elementName ] != null )\r
689                 {\r
690                         if ( range.StartBlock )\r
691                         {\r
692                                 if ( range.CheckStartOfBlock() )\r
693                                         range.MoveToPosition( range.StartBlock, 3 ) ;\r
694                                 else if ( range.CheckEndOfBlock() )\r
695                                         range.MoveToPosition( range.StartBlock, 4 ) ;\r
696                                 else\r
697                                         range.SplitBlock() ;\r
698                         }\r
699 \r
700                         range.InsertNode( element ) ;\r
701 \r
702                         var next = FCKDomTools.GetNextSourceElement( element, false, null, [ 'hr','br','param','img','area','input' ], true ) ;\r
703 \r
704                         // Be sure that we have something after the new element, so we can move the cursor there.\r
705                         if ( !next && FCKConfig.EnterMode != 'br')\r
706                         {\r
707                                 next = this.EditorDocument.body.appendChild( this.EditorDocument.createElement( FCKConfig.EnterMode ) ) ;\r
708 \r
709                                 if ( FCKBrowserInfo.IsGeckoLike )\r
710                                         FCKTools.AppendBogusBr( next ) ;\r
711                         }\r
712 \r
713                         if ( FCKListsLib.EmptyElements[ elementName ] == null )\r
714                                 range.MoveToElementEditStart( element ) ;\r
715                         else if ( next )\r
716                                 range.MoveToElementEditStart( next ) ;\r
717                         else\r
718                                 range.MoveToPosition( element, 4 ) ;\r
719 \r
720                         if ( FCKBrowserInfo.IsGeckoLike )\r
721                         {\r
722                                 if ( next )\r
723                                         FCKDomTools.ScrollIntoView( next, false );\r
724                                 FCKDomTools.ScrollIntoView( element, false );\r
725                         }\r
726                 }\r
727                 else\r
728                 {\r
729                         // Insert the node.\r
730                         range.InsertNode( element ) ;\r
731 \r
732                         // Move the selection right after the new element.\r
733                         // DISCUSSION: Should we select the element instead?\r
734                         range.SetStart( element, 4 ) ;\r
735                         range.SetEnd( element, 4 ) ;\r
736                 }\r
737 \r
738                 range.Select() ;\r
739                 range.Release() ;\r
740 \r
741                 // REMOVE IT: The focus should not really be set here. It is up to the\r
742                 // calling code to reset the focus if needed.\r
743                 this.Focus() ;\r
744 \r
745                 return element ;\r
746         },\r
747 \r
748         _InsertBlockElement : function( blockElement )\r
749         {\r
750         },\r
751 \r
752         _IsFunctionKey : function( keyCode )\r
753         {\r
754                 // keys that are captured but do not change editor contents\r
755                 if ( keyCode >= 16 && keyCode <= 20 )\r
756                         // shift, ctrl, alt, pause, capslock\r
757                         return true ;\r
758                 if ( keyCode == 27 || ( keyCode >= 33 && keyCode <= 40 ) )\r
759                         // esc, page up, page down, end, home, left, up, right, down\r
760                         return true ;\r
761                 if ( keyCode == 45 )\r
762                         // insert, no effect on FCKeditor, yet\r
763                         return true ;\r
764                 return false ;\r
765         },\r
766 \r
767         _KeyDownListener : function( evt )\r
768         {\r
769                 if (! evt)\r
770                         evt = FCK.EditorWindow.event ;\r
771                 if ( FCK.EditorWindow )\r
772                 {\r
773                         if ( !FCK._IsFunctionKey(evt.keyCode) // do not capture function key presses, like arrow keys or shift/alt/ctrl\r
774                                         && !(evt.ctrlKey || evt.metaKey) // do not capture Ctrl hotkeys, as they have their snapshot capture logic\r
775                                         && !(evt.keyCode == 46) ) // do not capture Del, it has its own capture logic in fckenterkey.js\r
776                                 FCK._KeyDownUndo() ;\r
777                 }\r
778                 return true ;\r
779         },\r
780 \r
781         _KeyDownUndo : function()\r
782         {\r
783                 if ( !FCKUndo.Typing )\r
784                 {\r
785                         FCKUndo.SaveUndoStep() ;\r
786                         FCKUndo.Typing = true ;\r
787                         FCK.Events.FireEvent( "OnSelectionChange" ) ;\r
788                 }\r
789 \r
790                 FCKUndo.TypesCount++ ;\r
791                 FCKUndo.Changed = 1 ;\r
792 \r
793                 if ( FCKUndo.TypesCount > FCKUndo.MaxTypes )\r
794                 {\r
795                         FCKUndo.TypesCount = 0 ;\r
796                         FCKUndo.SaveUndoStep() ;\r
797                 }\r
798         },\r
799 \r
800         _TabKeyHandler : function( evt )\r
801         {\r
802                 if ( ! evt )\r
803                         evt = window.event ;\r
804 \r
805                 var keystrokeValue = evt.keyCode ;\r
806 \r
807                 // Pressing <Tab> in source mode should produce a tab space in the text area, not\r
808                 // changing the focus to something else.\r
809                 if ( keystrokeValue == 9 && FCK.EditMode != FCK_EDITMODE_WYSIWYG )\r
810                 {\r
811                         if ( FCKBrowserInfo.IsIE )\r
812                         {\r
813                                 var range = document.selection.createRange() ;\r
814                                 if ( range.parentElement() != FCK.EditingArea.Textarea )\r
815                                         return true ;\r
816                                 range.text = '\t' ;\r
817                                 range.select() ;\r
818                         }\r
819                         else\r
820                         {\r
821                                 var a = [] ;\r
822                                 var el = FCK.EditingArea.Textarea ;\r
823                                 var selStart = el.selectionStart ;\r
824                                 var selEnd = el.selectionEnd ;\r
825                                 a.push( el.value.substr(0, selStart ) ) ;\r
826                                 a.push( '\t' ) ;\r
827                                 a.push( el.value.substr( selEnd ) ) ;\r
828                                 el.value = a.join( '' ) ;\r
829                                 el.setSelectionRange( selStart + 1, selStart + 1 ) ;\r
830                         }\r
831 \r
832                         if ( evt.preventDefault )\r
833                                 return evt.preventDefault() ;\r
834 \r
835                         return evt.returnValue = false ;\r
836                 }\r
837 \r
838                 return true ;\r
839         }\r
840 } ;\r
841 \r
842 FCK.Events = new FCKEvents( FCK ) ;\r
843 \r
844 // DEPRECATED in favor or "GetData".\r
845 FCK.GetHTML     = FCK.GetXHTML = FCK.GetData ;\r
846 \r
847 // DEPRECATED in favor of "SetData".\r
848 FCK.SetHTML = FCK.SetData ;\r
849 \r
850 // InsertElementAndGetIt and CreateElement are Deprecated : returns the same value as InsertElement.\r
851 FCK.InsertElementAndGetIt = FCK.CreateElement = FCK.InsertElement ;\r
852 \r
853 // Replace all events attributes (like onclick).\r
854 function _FCK_ProtectEvents_ReplaceTags( tagMatch )\r
855 {\r
856         return tagMatch.replace( FCKRegexLib.EventAttributes, _FCK_ProtectEvents_ReplaceEvents ) ;\r
857 }\r
858 \r
859 // Replace an event attribute with its respective __fckprotectedatt attribute.\r
860 // The original event markup will be encoded and saved as the value of the new\r
861 // attribute.\r
862 function _FCK_ProtectEvents_ReplaceEvents( eventMatch, attName )\r
863 {\r
864         return ' ' + attName + '_fckprotectedatt="' + encodeURIComponent( eventMatch ) + '"' ;\r
865 }\r
866 \r
867 function _FCK_ProtectEvents_RestoreEvents( match, encodedOriginal )\r
868 {\r
869         return decodeURIComponent( encodedOriginal ) ;\r
870 }\r
871 \r
872 function _FCK_MouseEventsListener( evt )\r
873 {\r
874         if ( ! evt )\r
875                 evt = window.event ;\r
876         if ( evt.type == 'mousedown' )\r
877                 FCK.MouseDownFlag = true ;\r
878         else if ( evt.type == 'mouseup' )\r
879                 FCK.MouseDownFlag = false ;\r
880         else if ( evt.type == 'mousemove' )\r
881                 FCK.Events.FireEvent( 'OnMouseMove', evt ) ;\r
882 }\r
883 \r
884 function _FCK_PaddingNodeListener()\r
885 {\r
886         if ( FCKConfig.EnterMode.IEquals( 'br' ) )\r
887                 return ;\r
888         FCKDomTools.EnforcePaddingNode( FCK.EditorDocument, FCKConfig.EnterMode ) ;\r
889 \r
890         if ( ! FCKBrowserInfo.IsIE && FCKDomTools.PaddingNode )\r
891         {\r
892                 // Prevent the caret from going between the body and the padding node in Firefox.\r
893                 // i.e. <body>|<p></p></body>\r
894                 var sel = FCKSelection.GetSelection() ;\r
895                 if ( sel && sel.rangeCount == 1 )\r
896                 {\r
897                         var range = sel.getRangeAt( 0 ) ;\r
898                         if ( range.collapsed && range.startContainer == FCK.EditorDocument.body && range.startOffset == 0 )\r
899                         {\r
900                                 range.selectNodeContents( FCKDomTools.PaddingNode ) ;\r
901                                 range.collapse( true ) ;\r
902                                 sel.removeAllRanges() ;\r
903                                 sel.addRange( range ) ;\r
904                         }\r
905                 }\r
906         }\r
907         else if ( FCKDomTools.PaddingNode )\r
908         {\r
909                 // Prevent the caret from going into an empty body but not into the padding node in IE.\r
910                 // i.e. <body><p></p>|</body>\r
911                 var parentElement = FCKSelection.GetParentElement() ;\r
912                 var paddingNode = FCKDomTools.PaddingNode ;\r
913                 if ( parentElement && parentElement.nodeName.IEquals( 'body' ) )\r
914                 {\r
915                         if ( FCK.EditorDocument.body.childNodes.length == 1\r
916                                         && FCK.EditorDocument.body.firstChild == paddingNode )\r
917                         {\r
918                                 /*\r
919                                  * Bug #1764: Don't move the selection if the\r
920                                  * current selection isn't in the editor\r
921                                  * document.\r
922                                  */\r
923                                 if ( FCKSelection._GetSelectionDocument( FCK.EditorDocument.selection ) != FCK.EditorDocument )\r
924                                         return ;\r
925 \r
926                                 var range = FCK.EditorDocument.body.createTextRange() ;\r
927                                 var clearContents = false ;\r
928                                 if ( !paddingNode.childNodes.firstChild )\r
929                                 {\r
930                                         paddingNode.appendChild( FCKTools.GetElementDocument( paddingNode ).createTextNode( '\ufeff' ) ) ;\r
931                                         clearContents = true ;\r
932                                 }\r
933                                 range.moveToElementText( paddingNode ) ;\r
934                                 range.select() ;\r
935                                 if ( clearContents )\r
936                                         range.pasteHTML( '' ) ;\r
937                         }\r
938                 }\r
939         }\r
940 }\r
941 \r
942 function _FCK_EditingArea_OnLoad()\r
943 {\r
944         // Get the editor's window and document (DOM)\r
945         FCK.EditorWindow        = FCK.EditingArea.Window ;\r
946         FCK.EditorDocument      = FCK.EditingArea.Document ;\r
947 \r
948         if ( FCKBrowserInfo.IsIE )\r
949                 FCKTempBin.ToElements() ;\r
950 \r
951         FCK.InitializeBehaviors() ;\r
952 \r
953         // Listen for mousedown and mouseup events for tracking drag and drops.\r
954         FCK.MouseDownFlag = false ;\r
955         FCKTools.AddEventListener( FCK.EditorDocument, 'mousemove', _FCK_MouseEventsListener ) ;\r
956         FCKTools.AddEventListener( FCK.EditorDocument, 'mousedown', _FCK_MouseEventsListener ) ;\r
957         FCKTools.AddEventListener( FCK.EditorDocument, 'mouseup', _FCK_MouseEventsListener ) ;\r
958 \r
959         // Most of the CTRL key combos do not work under Safari for onkeydown and onkeypress (See #1119)\r
960         // But we can use the keyup event to override some of these...\r
961         if ( FCKBrowserInfo.IsSafari )\r
962         {\r
963                 var undoFunc = function( evt )\r
964                 {\r
965                         if ( ! ( evt.ctrlKey || evt.metaKey ) )\r
966                                 return ;\r
967                         if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )\r
968                                 return ;\r
969                         switch ( evt.keyCode )\r
970                         {\r
971                                 case 89:\r
972                                         FCKUndo.Redo() ;\r
973                                         break ;\r
974                                 case 90:\r
975                                         FCKUndo.Undo() ;\r
976                                         break ;\r
977                         }\r
978                 }\r
979 \r
980                 FCKTools.AddEventListener( FCK.EditorDocument, 'keyup', undoFunc ) ;\r
981         }\r
982 \r
983         // Create the enter key handler\r
984         FCK.EnterKeyHandler = new FCKEnterKey( FCK.EditorWindow, FCKConfig.EnterMode, FCKConfig.ShiftEnterMode, FCKConfig.TabSpaces ) ;\r
985 \r
986         // Listen for keystroke events.\r
987         FCK.KeystrokeHandler.AttachToElement( FCK.EditorDocument ) ;\r
988 \r
989         if ( FCK._ForceResetIsDirty )\r
990                 FCK.ResetIsDirty() ;\r
991 \r
992         // This is a tricky thing for IE. In some cases, even if the cursor is\r
993         // blinking in the editing, the keystroke handler doesn't catch keyboard\r
994         // events. We must activate the editing area to make it work. (#142).\r
995         if ( FCKBrowserInfo.IsIE && FCK.HasFocus )\r
996                 FCK.EditorDocument.body.setActive() ;\r
997 \r
998         FCK.OnAfterSetHTML() ;\r
999 \r
1000         // Restore show blocks status.\r
1001         FCKCommands.GetCommand( 'ShowBlocks' ).RestoreState() ;\r
1002 \r
1003         // Check if it is not a startup call, otherwise complete the startup.\r
1004         if ( FCK.Status != FCK_STATUS_NOTLOADED )\r
1005                 return ;\r
1006 \r
1007         FCK.SetStatus( FCK_STATUS_ACTIVE ) ;\r
1008 }\r
1009 \r
1010 function _FCK_GetEditorAreaStyleTags()\r
1011 {\r
1012         return FCKTools.GetStyleHtml( FCKConfig.EditorAreaCSS ) +\r
1013                 FCKTools.GetStyleHtml( FCKConfig.EditorAreaStyles ) ;\r
1014 }\r
1015 \r
1016 function _FCK_KeystrokeHandler_OnKeystroke( keystroke, keystrokeValue )\r
1017 {\r
1018         if ( FCK.Status != FCK_STATUS_COMPLETE )\r
1019                 return false ;\r
1020 \r
1021         if ( FCK.EditMode == FCK_EDITMODE_WYSIWYG )\r
1022         {\r
1023                 switch ( keystrokeValue )\r
1024                 {\r
1025                         case 'Paste' :\r
1026                                 return !FCK.Paste() ;\r
1027 \r
1028                         case 'Cut' :\r
1029                                 FCKUndo.SaveUndoStep() ;\r
1030                                 return false ;\r
1031                 }\r
1032         }\r
1033         else\r
1034         {\r
1035                 // In source mode, some actions must have their default behavior.\r
1036                 if ( keystrokeValue.Equals( 'Paste', 'Undo', 'Redo', 'SelectAll', 'Cut' ) )\r
1037                         return false ;\r
1038         }\r
1039 \r
1040         // The return value indicates if the default behavior of the keystroke must\r
1041         // be cancelled. Let's do that only if the Execute() call explicitly returns "false".\r
1042         var oCommand = FCK.Commands.GetCommand( keystrokeValue ) ;\r
1043 \r
1044         // If the command is disabled then ignore the keystroke\r
1045         if ( oCommand.GetState() == FCK_TRISTATE_DISABLED )\r
1046                 return false ;\r
1047 \r
1048         return ( oCommand.Execute.apply( oCommand, FCKTools.ArgumentsToArray( arguments, 2 ) ) !== false ) ;\r
1049 }\r
1050 \r
1051 // Set the FCK.LinkedField reference to the field that will be used to post the\r
1052 // editor data.\r
1053 (function()\r
1054 {\r
1055         // There is a bug on IE... getElementById returns any META tag that has the\r
1056         // name set to the ID you are looking for. So the best way in to get the array\r
1057         // by names and look for the correct one.\r
1058         // As ASP.Net generates a ID that is different from the Name, we must also\r
1059         // look for the field based on the ID (the first one is the ID).\r
1060 \r
1061         var oDocument = window.parent.document ;\r
1062 \r
1063         // Try to get the field using the ID.\r
1064         var eLinkedField = oDocument.getElementById( FCK.Name ) ;\r
1065 \r
1066         var i = 0;\r
1067         while ( eLinkedField || i == 0 )\r
1068         {\r
1069                 if ( eLinkedField && eLinkedField.tagName.toLowerCase().Equals( 'input', 'textarea' ) )\r
1070                 {\r
1071                         FCK.LinkedField = eLinkedField ;\r
1072                         break ;\r
1073                 }\r
1074 \r
1075                 eLinkedField = oDocument.getElementsByName( FCK.Name )[i++] ;\r
1076         }\r
1077 })() ;\r
1078 \r
1079 var FCKTempBin =\r
1080 {\r
1081         Elements : new Array(),\r
1082 \r
1083         AddElement : function( element )\r
1084         {\r
1085                 var iIndex = this.Elements.length ;\r
1086                 this.Elements[ iIndex ] = element ;\r
1087                 return iIndex ;\r
1088         },\r
1089 \r
1090         RemoveElement : function( index )\r
1091         {\r
1092                 var e = this.Elements[ index ] ;\r
1093                 this.Elements[ index ] = null ;\r
1094                 return e ;\r
1095         },\r
1096 \r
1097         Reset : function()\r
1098         {\r
1099                 var i = 0 ;\r
1100                 while ( i < this.Elements.length )\r
1101                         this.Elements[ i++ ] = null ;\r
1102                 this.Elements.length = 0 ;\r
1103         },\r
1104 \r
1105         ToHtml : function()\r
1106         {\r
1107                 for ( var i = 0 ; i < this.Elements.length ; i++ )\r
1108                 {\r
1109                         this.Elements[i] = '<div>&nbsp;' + this.Elements[i].outerHTML + '</div>' ;\r
1110                         this.Elements[i].isHtml = true ;\r
1111                 }\r
1112         },\r
1113 \r
1114         ToElements : function()\r
1115         {\r
1116                 var node = FCK.EditorDocument.createElement( 'div' ) ;\r
1117                 for ( var i = 0 ; i < this.Elements.length ; i++ )\r
1118                 {\r
1119                         if ( this.Elements[i].isHtml )\r
1120                         {\r
1121                                 node.innerHTML = this.Elements[i] ;\r
1122                                 this.Elements[i] = node.firstChild.removeChild( node.firstChild.lastChild ) ;\r
1123                         }\r
1124                 }\r
1125         }\r
1126 } ;\r
1127 \r
1128 \r
1129 \r
1130 // # Focus Manager: Manages the focus in the editor.\r
1131 var FCKFocusManager = FCK.FocusManager =\r
1132 {\r
1133         IsLocked : false,\r
1134 \r
1135         AddWindow : function( win, sendToEditingArea )\r
1136         {\r
1137                 var oTarget ;\r
1138 \r
1139                 if ( FCKBrowserInfo.IsIE )\r
1140                         oTarget = win.nodeType == 1 ? win : win.frameElement ? win.frameElement : win.document ;\r
1141                 else if ( FCKBrowserInfo.IsSafari )\r
1142                         oTarget = win ;\r
1143                 else\r
1144                         oTarget = win.document ;\r
1145 \r
1146                 FCKTools.AddEventListener( oTarget, 'blur', FCKFocusManager_Win_OnBlur ) ;\r
1147                 FCKTools.AddEventListener( oTarget, 'focus', sendToEditingArea ? FCKFocusManager_Win_OnFocus_Area : FCKFocusManager_Win_OnFocus ) ;\r
1148         },\r
1149 \r
1150         RemoveWindow : function( win )\r
1151         {\r
1152                 if ( FCKBrowserInfo.IsIE )\r
1153                         oTarget = win.nodeType == 1 ? win : win.frameElement ? win.frameElement : win.document ;\r
1154                 else\r
1155                         oTarget = win.document ;\r
1156 \r
1157                 FCKTools.RemoveEventListener( oTarget, 'blur', FCKFocusManager_Win_OnBlur ) ;\r
1158                 FCKTools.RemoveEventListener( oTarget, 'focus', FCKFocusManager_Win_OnFocus_Area ) ;\r
1159                 FCKTools.RemoveEventListener( oTarget, 'focus', FCKFocusManager_Win_OnFocus ) ;\r
1160         },\r
1161 \r
1162         Lock : function()\r
1163         {\r
1164                 this.IsLocked = true ;\r
1165         },\r
1166 \r
1167         Unlock : function()\r
1168         {\r
1169                 if ( this._HasPendingBlur )\r
1170                         FCKFocusManager._Timer = window.setTimeout( FCKFocusManager_FireOnBlur, 100 ) ;\r
1171 \r
1172                 this.IsLocked = false ;\r
1173         },\r
1174 \r
1175         _ResetTimer : function()\r
1176         {\r
1177                 this._HasPendingBlur = false ;\r
1178 \r
1179                 if ( this._Timer )\r
1180                 {\r
1181                         window.clearTimeout( this._Timer ) ;\r
1182                         delete this._Timer ;\r
1183                 }\r
1184         }\r
1185 } ;\r
1186 \r
1187 function FCKFocusManager_Win_OnBlur()\r
1188 {\r
1189         if ( typeof(FCK) != 'undefined' && FCK.HasFocus )\r
1190         {\r
1191                 FCKFocusManager._ResetTimer() ;\r
1192                 FCKFocusManager._Timer = window.setTimeout( FCKFocusManager_FireOnBlur, 100 ) ;\r
1193         }\r
1194 }\r
1195 \r
1196 function FCKFocusManager_FireOnBlur()\r
1197 {\r
1198         if ( FCKFocusManager.IsLocked )\r
1199                 FCKFocusManager._HasPendingBlur = true ;\r
1200         else\r
1201         {\r
1202                 FCK.HasFocus = false ;\r
1203                 FCK.Events.FireEvent( "OnBlur" ) ;\r
1204         }\r
1205 }\r
1206 \r
1207 function FCKFocusManager_Win_OnFocus_Area()\r
1208 {\r
1209         // Check if we are already focusing the editor (to avoid loops).\r
1210         if ( FCKFocusManager._IsFocusing )\r
1211                 return ;\r
1212 \r
1213         FCKFocusManager._IsFocusing = true ;\r
1214 \r
1215         FCK.Focus() ;\r
1216         FCKFocusManager_Win_OnFocus() ;\r
1217 \r
1218         // The above FCK.Focus() call may trigger other focus related functions.\r
1219         // So, to avoid a loop, we delay the focusing mark removal, so it get\r
1220         // executed after all othre functions have been run.\r
1221         FCKTools.RunFunction( function()\r
1222                 {\r
1223                         delete FCKFocusManager._IsFocusing ;\r
1224                 } ) ;\r
1225 }\r
1226 \r
1227 function FCKFocusManager_Win_OnFocus()\r
1228 {\r
1229         FCKFocusManager._ResetTimer() ;\r
1230 \r
1231         if ( !FCK.HasFocus && !FCKFocusManager.IsLocked )\r
1232         {\r
1233                 FCK.HasFocus = true ;\r
1234                 FCK.Events.FireEvent( "OnFocus" ) ;\r
1235         }\r
1236 }\r
1237 \r
1238 /*\r
1239  * #1633 : Protect the editor iframe from external styles.\r
1240  * Notice that we can't use FCKTools.ResetStyles here since FCKTools isn't\r
1241  * loaded yet.\r
1242  */\r
1243 (function()\r
1244 {\r
1245         var el = window.frameElement ;\r
1246         var width = el.width ;\r
1247         var height = el.height ;\r
1248         if ( /^\d+$/.test( width ) ) width += 'px' ;\r
1249         if ( /^\d+$/.test( height ) ) height += 'px' ;\r
1250         var style = el.style ;\r
1251         style.border = style.padding = style.margin = 0 ;\r
1252         style.backgroundColor = 'transparent';\r
1253         style.backgroundImage = 'none';\r
1254         style.width = width ;\r
1255         style.height = height ;\r
1256 })() ;\r