| 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> ' + 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 |
|