PluginProbe
Wp-Insert / 1.7.2
Wp-Insert v1.7.2
trunk 1.0 1.1 1.2 1.2.1 1.2.2 1.3.0 1.3.1 1.3.3 1.4 1.5.0 1.5.1 1.5.2 1.5.3 1.6.0 1.6.1 1.6.2 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 2.0 All 63 releases
wp-insert / fckeditor / editor / _source / internals / fck.js

fck.js in Wp-Insert 1.7.2, at fckeditor/editor/_source/internals/fck.js

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