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