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
|
---|
22 | * object that represents an editor instance.
|
---|
23 | * (Gecko specific implementations)
|
---|
24 | */
|
---|
25 |
|
---|
26 | FCK.Description = "FCKeditor for Gecko Browsers" ;
|
---|
27 |
|
---|
28 | FCK.InitializeBehaviors = function()
|
---|
29 | {
|
---|
30 | // When calling "SetData", the editing area IFRAME gets a fixed height. So we must recalculate it.
|
---|
31 | if ( window.onresize ) // Not for Safari/Opera.
|
---|
32 | window.onresize() ;
|
---|
33 |
|
---|
34 | FCKFocusManager.AddWindow( this.EditorWindow ) ;
|
---|
35 |
|
---|
36 | this.ExecOnSelectionChange = function()
|
---|
37 | {
|
---|
38 | FCK.Events.FireEvent( "OnSelectionChange" ) ;
|
---|
39 | }
|
---|
40 |
|
---|
41 | this._ExecDrop = function( evt )
|
---|
42 | {
|
---|
43 | if ( FCK.MouseDownFlag )
|
---|
44 | {
|
---|
45 | FCK.MouseDownFlag = false ;
|
---|
46 | return ;
|
---|
47 | }
|
---|
48 |
|
---|
49 | if ( FCKConfig.ForcePasteAsPlainText )
|
---|
50 | {
|
---|
51 | if ( evt.dataTransfer )
|
---|
52 | {
|
---|
53 | var text = evt.dataTransfer.getData( 'Text' ) ;
|
---|
54 | text = FCKTools.HTMLEncode( text ) ;
|
---|
55 | text = FCKTools.ProcessLineBreaks( window, FCKConfig, text ) ;
|
---|
56 | FCK.InsertHtml( text ) ;
|
---|
57 | }
|
---|
58 | else if ( FCKConfig.ShowDropDialog )
|
---|
59 | FCK.PasteAsPlainText() ;
|
---|
60 |
|
---|
61 | evt.preventDefault() ;
|
---|
62 | evt.stopPropagation() ;
|
---|
63 | }
|
---|
64 | }
|
---|
65 |
|
---|
66 | this._ExecCheckCaret = function( evt )
|
---|
67 | {
|
---|
68 | if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
|
---|
69 | return ;
|
---|
70 |
|
---|
71 | if ( evt.type == 'keypress' )
|
---|
72 | {
|
---|
73 | var keyCode = evt.keyCode ;
|
---|
74 | // ignore if positioning key is not pressed.
|
---|
75 | // left or up arrow keys need to be processed as well, since <a> links can be expanded in Gecko's editor
|
---|
76 | // when the caret moved left or up from another block element below.
|
---|
77 | if ( keyCode < 33 || keyCode > 40 )
|
---|
78 | return ;
|
---|
79 | }
|
---|
80 |
|
---|
81 | var blockEmptyStop = function( node )
|
---|
82 | {
|
---|
83 | if ( node.nodeType != 1 )
|
---|
84 | return false ;
|
---|
85 | var tag = node.tagName.toLowerCase() ;
|
---|
86 | return ( FCKListsLib.BlockElements[tag] || FCKListsLib.EmptyElements[tag] ) ;
|
---|
87 | }
|
---|
88 |
|
---|
89 | var moveCursor = function()
|
---|
90 | {
|
---|
91 | var selection = FCKSelection.GetSelection() ;
|
---|
92 | var range = selection.getRangeAt(0) ;
|
---|
93 | if ( ! range || ! range.collapsed )
|
---|
94 | return ;
|
---|
95 |
|
---|
96 | var node = range.endContainer ;
|
---|
97 |
|
---|
98 | // only perform the patched behavior if we're at the end of a text node.
|
---|
99 | if ( node.nodeType != 3 )
|
---|
100 | return ;
|
---|
101 |
|
---|
102 | if ( node.nodeValue.length != range.endOffset )
|
---|
103 | return ;
|
---|
104 |
|
---|
105 | // only perform the patched behavior if we're in an <a> tag, or the End key is pressed.
|
---|
106 | var parentTag = node.parentNode.tagName.toLowerCase() ;
|
---|
107 | if ( ! ( parentTag == 'a' || ( !FCKBrowserInfo.IsOpera && String(node.parentNode.contentEditable) == 'false' ) ||
|
---|
108 | ( ! ( FCKListsLib.BlockElements[parentTag] || FCKListsLib.NonEmptyBlockElements[parentTag] )
|
---|
109 | && keyCode == 35 ) ) )
|
---|
110 | return ;
|
---|
111 |
|
---|
112 | // our caret has moved to just after the last character of a text node under an unknown tag, how to proceed?
|
---|
113 | // first, see if there are other text nodes by DFS walking from this text node.
|
---|
114 | // - if the DFS has scanned all nodes under my parent, then go the next step.
|
---|
115 | // - if there is a text node after me but still under my parent, then do nothing and return.
|
---|
116 | var nextTextNode = FCKTools.GetNextTextNode( node, node.parentNode, blockEmptyStop ) ;
|
---|
117 | if ( nextTextNode )
|
---|
118 | return ;
|
---|
119 |
|
---|
120 | // we're pretty sure we need to move the caret forcefully from here.
|
---|
121 | range = FCK.EditorDocument.createRange() ;
|
---|
122 |
|
---|
123 | nextTextNode = FCKTools.GetNextTextNode( node, node.parentNode.parentNode, blockEmptyStop ) ;
|
---|
124 | if ( nextTextNode )
|
---|
125 | {
|
---|
126 | // Opera thinks the dummy empty text node we append beyond the end of <a> nodes occupies a caret
|
---|
127 | // position. So if the user presses the left key and we reset the caret position here, the user
|
---|
128 | // wouldn't be able to go back.
|
---|
129 | if ( FCKBrowserInfo.IsOpera && keyCode == 37 )
|
---|
130 | return ;
|
---|
131 |
|
---|
132 | // now we want to get out of our current parent node, adopt the next parent, and move the caret to
|
---|
133 | // the appropriate text node under our new parent.
|
---|
134 | // our new parent might be our current parent's siblings if we are lucky.
|
---|
135 | range.setStart( nextTextNode, 0 ) ;
|
---|
136 | range.setEnd( nextTextNode, 0 ) ;
|
---|
137 | }
|
---|
138 | else
|
---|
139 | {
|
---|
140 | // no suitable next siblings under our grandparent! what to do next?
|
---|
141 | while ( node.parentNode
|
---|
142 | && node.parentNode != FCK.EditorDocument.body
|
---|
143 | && node.parentNode != FCK.EditorDocument.documentElement
|
---|
144 | && node == node.parentNode.lastChild
|
---|
145 | && ( ! FCKListsLib.BlockElements[node.parentNode.tagName.toLowerCase()]
|
---|
146 | && ! FCKListsLib.NonEmptyBlockElements[node.parentNode.tagName.toLowerCase()] ) )
|
---|
147 | node = node.parentNode ;
|
---|
148 |
|
---|
149 |
|
---|
150 | if ( FCKListsLib.BlockElements[ parentTag ]
|
---|
151 | || FCKListsLib.EmptyElements[ parentTag ]
|
---|
152 | || node == FCK.EditorDocument.body )
|
---|
153 | {
|
---|
154 | // if our parent is a block node, move to the end of our parent.
|
---|
155 | range.setStart( node, node.childNodes.length ) ;
|
---|
156 | range.setEnd( node, node.childNodes.length ) ;
|
---|
157 | }
|
---|
158 | else
|
---|
159 | {
|
---|
160 | // things are a little bit more interesting if our parent is not a block node
|
---|
161 | // due to the weired ways how Gecko's caret acts...
|
---|
162 | var stopNode = node.nextSibling ;
|
---|
163 |
|
---|
164 | // find out the next block/empty element at our grandparent, we'll
|
---|
165 | // move the caret just before it.
|
---|
166 | while ( stopNode )
|
---|
167 | {
|
---|
168 | if ( stopNode.nodeType != 1 )
|
---|
169 | {
|
---|
170 | stopNode = stopNode.nextSibling ;
|
---|
171 | continue ;
|
---|
172 | }
|
---|
173 |
|
---|
174 | var stopTag = stopNode.tagName.toLowerCase() ;
|
---|
175 | if ( FCKListsLib.BlockElements[stopTag] || FCKListsLib.EmptyElements[stopTag]
|
---|
176 | || FCKListsLib.NonEmptyBlockElements[stopTag] )
|
---|
177 | break ;
|
---|
178 | stopNode = stopNode.nextSibling ;
|
---|
179 | }
|
---|
180 |
|
---|
181 | // note that the dummy marker below is NEEDED, otherwise the caret's behavior will
|
---|
182 | // be broken in Gecko.
|
---|
183 | var marker = FCK.EditorDocument.createTextNode( '' ) ;
|
---|
184 | if ( stopNode )
|
---|
185 | node.parentNode.insertBefore( marker, stopNode ) ;
|
---|
186 | else
|
---|
187 | node.parentNode.appendChild( marker ) ;
|
---|
188 | range.setStart( marker, 0 ) ;
|
---|
189 | range.setEnd( marker, 0 ) ;
|
---|
190 | }
|
---|
191 | }
|
---|
192 |
|
---|
193 | selection.removeAllRanges() ;
|
---|
194 | selection.addRange( range ) ;
|
---|
195 | FCK.Events.FireEvent( "OnSelectionChange" ) ;
|
---|
196 | }
|
---|
197 |
|
---|
198 | setTimeout( moveCursor, 1 ) ;
|
---|
199 | }
|
---|
200 |
|
---|
201 | this.ExecOnSelectionChangeTimer = function()
|
---|
202 | {
|
---|
203 | if ( FCK.LastOnChangeTimer )
|
---|
204 | window.clearTimeout( FCK.LastOnChangeTimer ) ;
|
---|
205 |
|
---|
206 | FCK.LastOnChangeTimer = window.setTimeout( FCK.ExecOnSelectionChange, 100 ) ;
|
---|
207 | }
|
---|
208 |
|
---|
209 | this.EditorDocument.addEventListener( 'mouseup', this.ExecOnSelectionChange, false ) ;
|
---|
210 |
|
---|
211 | // On Gecko, firing the "OnSelectionChange" event on every key press started to be too much
|
---|
212 | // slow. So, a timer has been implemented to solve performance issues when typing to quickly.
|
---|
213 | this.EditorDocument.addEventListener( 'keyup', this.ExecOnSelectionChangeTimer, false ) ;
|
---|
214 |
|
---|
215 | this._DblClickListener = function( e )
|
---|
216 | {
|
---|
217 | FCK.OnDoubleClick( e.target ) ;
|
---|
218 | e.stopPropagation() ;
|
---|
219 | }
|
---|
220 | this.EditorDocument.addEventListener( 'dblclick', this._DblClickListener, true ) ;
|
---|
221 |
|
---|
222 | // Record changes for the undo system when there are key down events.
|
---|
223 | this.EditorDocument.addEventListener( 'keydown', this._KeyDownListener, false ) ;
|
---|
224 |
|
---|
225 | // Hooks for data object drops
|
---|
226 | if ( FCKBrowserInfo.IsGecko )
|
---|
227 | {
|
---|
228 | this.EditorWindow.addEventListener( 'dragdrop', this._ExecDrop, true ) ;
|
---|
229 | }
|
---|
230 | else if ( FCKBrowserInfo.IsSafari )
|
---|
231 | {
|
---|
232 | this.EditorDocument.addEventListener( 'dragover', function ( evt )
|
---|
233 | { if ( !FCK.MouseDownFlag && FCK.Config.ForcePasteAsPlainText ) evt.returnValue = false ; }, true ) ;
|
---|
234 | this.EditorDocument.addEventListener( 'drop', this._ExecDrop, true ) ;
|
---|
235 | this.EditorDocument.addEventListener( 'mousedown',
|
---|
236 | function( ev )
|
---|
237 | {
|
---|
238 | var element = ev.srcElement ;
|
---|
239 |
|
---|
240 | if ( element.nodeName.IEquals( 'IMG', 'HR', 'INPUT', 'TEXTAREA', 'SELECT' ) )
|
---|
241 | {
|
---|
242 | FCKSelection.SelectNode( element ) ;
|
---|
243 | }
|
---|
244 | }, true ) ;
|
---|
245 |
|
---|
246 | this.EditorDocument.addEventListener( 'mouseup',
|
---|
247 | function( ev )
|
---|
248 | {
|
---|
249 | if ( ev.srcElement.nodeName.IEquals( 'INPUT', 'TEXTAREA', 'SELECT' ) )
|
---|
250 | ev.preventDefault()
|
---|
251 | }, true ) ;
|
---|
252 |
|
---|
253 | this.EditorDocument.addEventListener( 'click',
|
---|
254 | function( ev )
|
---|
255 | {
|
---|
256 | if ( ev.srcElement.nodeName.IEquals( 'INPUT', 'TEXTAREA', 'SELECT' ) )
|
---|
257 | ev.preventDefault()
|
---|
258 | }, true ) ;
|
---|
259 | }
|
---|
260 |
|
---|
261 | // Kludge for buggy Gecko caret positioning logic (Bug #393 and #1056)
|
---|
262 | if ( FCKBrowserInfo.IsGecko || FCKBrowserInfo.IsOpera )
|
---|
263 | {
|
---|
264 | this.EditorDocument.addEventListener( 'keypress', this._ExecCheckCaret, false ) ;
|
---|
265 | this.EditorDocument.addEventListener( 'click', this._ExecCheckCaret, false ) ;
|
---|
266 | }
|
---|
267 |
|
---|
268 | // Reset the context menu.
|
---|
269 | FCK.ContextMenu._InnerContextMenu.SetMouseClickWindow( FCK.EditorWindow ) ;
|
---|
270 | FCK.ContextMenu._InnerContextMenu.AttachToElement( FCK.EditorDocument ) ;
|
---|
271 | }
|
---|
272 |
|
---|
273 | FCK.MakeEditable = function()
|
---|
274 | {
|
---|
275 | this.EditingArea.MakeEditable() ;
|
---|
276 | }
|
---|
277 |
|
---|
278 | // Disable the context menu in the editor (outside the editing area).
|
---|
279 | function Document_OnContextMenu( e )
|
---|
280 | {
|
---|
281 | if ( !e.target._FCKShowContextMenu )
|
---|
282 | e.preventDefault() ;
|
---|
283 | }
|
---|
284 | document.oncontextmenu = Document_OnContextMenu ;
|
---|
285 |
|
---|
286 | // GetNamedCommandState overload for Gecko.
|
---|
287 | FCK._BaseGetNamedCommandState = FCK.GetNamedCommandState ;
|
---|
288 | FCK.GetNamedCommandState = function( commandName )
|
---|
289 | {
|
---|
290 | switch ( commandName )
|
---|
291 | {
|
---|
292 | case 'Unlink' :
|
---|
293 | return FCKSelection.HasAncestorNode('A') ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
|
---|
294 | default :
|
---|
295 | return FCK._BaseGetNamedCommandState( commandName ) ;
|
---|
296 | }
|
---|
297 | }
|
---|
298 |
|
---|
299 | // Named commands to be handled by this browsers specific implementation.
|
---|
300 | FCK.RedirectNamedCommands =
|
---|
301 | {
|
---|
302 | Print : true,
|
---|
303 | Paste : true
|
---|
304 | } ;
|
---|
305 |
|
---|
306 | // ExecuteNamedCommand overload for Gecko.
|
---|
307 | FCK.ExecuteRedirectedNamedCommand = function( commandName, commandParameter )
|
---|
308 | {
|
---|
309 | switch ( commandName )
|
---|
310 | {
|
---|
311 | case 'Print' :
|
---|
312 | FCK.EditorWindow.print() ;
|
---|
313 | break ;
|
---|
314 | case 'Paste' :
|
---|
315 | try
|
---|
316 | {
|
---|
317 | // Force the paste dialog for Safari (#50).
|
---|
318 | if ( FCKBrowserInfo.IsSafari )
|
---|
319 | throw '' ;
|
---|
320 |
|
---|
321 | if ( FCK.Paste() )
|
---|
322 | FCK.ExecuteNamedCommand( 'Paste', null, true ) ;
|
---|
323 | }
|
---|
324 | catch (e) {
|
---|
325 | if ( FCKConfig.ForcePasteAsPlainText )
|
---|
326 | FCK.PasteAsPlainText() ;
|
---|
327 | else
|
---|
328 | FCKDialog.OpenDialog( 'FCKDialog_Paste', FCKLang.Paste, 'dialog/fck_paste.html', 400, 330, 'Security' ) ;
|
---|
329 | }
|
---|
330 | break ;
|
---|
331 | default :
|
---|
332 | FCK.ExecuteNamedCommand( commandName, commandParameter ) ;
|
---|
333 | }
|
---|
334 | }
|
---|
335 |
|
---|
336 | FCK._ExecPaste = function()
|
---|
337 | {
|
---|
338 | // Save a snapshot for undo before actually paste the text
|
---|
339 | FCKUndo.SaveUndoStep() ;
|
---|
340 |
|
---|
341 | if ( FCKConfig.ForcePasteAsPlainText )
|
---|
342 | {
|
---|
343 | FCK.PasteAsPlainText() ;
|
---|
344 | return false ;
|
---|
345 | }
|
---|
346 |
|
---|
347 | /* For now, the AutoDetectPasteFromWord feature is IE only. */
|
---|
348 | return true ;
|
---|
349 | }
|
---|
350 |
|
---|
351 | //**
|
---|
352 | // FCK.InsertHtml: Inserts HTML at the current cursor location. Deletes the
|
---|
353 | // selected content if any.
|
---|
354 | FCK.InsertHtml = function( html )
|
---|
355 | {
|
---|
356 | var doc = FCK.EditorDocument,
|
---|
357 | range;
|
---|
358 |
|
---|
359 | html = FCKConfig.ProtectedSource.Protect( html ) ;
|
---|
360 | html = FCK.ProtectEvents( html ) ;
|
---|
361 | html = FCK.ProtectUrls( html ) ;
|
---|
362 | html = FCK.ProtectTags( html ) ;
|
---|
363 |
|
---|
364 | // Save an undo snapshot first.
|
---|
365 | FCKUndo.SaveUndoStep() ;
|
---|
366 |
|
---|
367 | if ( FCKBrowserInfo.IsGecko )
|
---|
368 | {
|
---|
369 | html = html.replace( / $/, '$&<span _fcktemp="1"/>' ) ;
|
---|
370 |
|
---|
371 | var docFrag = new FCKDocumentFragment( this.EditorDocument ) ;
|
---|
372 | docFrag.AppendHtml( html ) ;
|
---|
373 |
|
---|
374 | var lastNode = docFrag.RootNode.lastChild ;
|
---|
375 |
|
---|
376 | range = new FCKDomRange( this.EditorWindow ) ;
|
---|
377 | range.MoveToSelection() ;
|
---|
378 |
|
---|
379 | // If the first element (if exists) of the document fragment is a block
|
---|
380 | // element, then split the current block. (#1537)
|
---|
381 | var currentNode = docFrag.RootNode.firstChild ;
|
---|
382 | while ( currentNode && currentNode.nodeType != 1 )
|
---|
383 | currentNode = currentNode.nextSibling ;
|
---|
384 |
|
---|
385 | if ( currentNode && FCKListsLib.BlockElements[ currentNode.nodeName.toLowerCase() ] )
|
---|
386 | range.SplitBlock() ;
|
---|
387 |
|
---|
388 | range.DeleteContents() ;
|
---|
389 | range.InsertNode( docFrag.RootNode ) ;
|
---|
390 |
|
---|
391 | range.MoveToPosition( lastNode, 4 ) ;
|
---|
392 | }
|
---|
393 | else
|
---|
394 | doc.execCommand( 'inserthtml', false, html ) ;
|
---|
395 |
|
---|
396 | this.Focus() ;
|
---|
397 |
|
---|
398 | // Save the caret position before calling document processor.
|
---|
399 | if ( !range )
|
---|
400 | {
|
---|
401 | range = new FCKDomRange( this.EditorWindow ) ;
|
---|
402 | range.MoveToSelection() ;
|
---|
403 | }
|
---|
404 | var bookmark = range.CreateBookmark() ;
|
---|
405 |
|
---|
406 | FCKDocumentProcessor.Process( doc ) ;
|
---|
407 |
|
---|
408 | // Restore caret position, ignore any errors in case the document
|
---|
409 | // processor removed the bookmark <span>s for some reason.
|
---|
410 | try
|
---|
411 | {
|
---|
412 | range.MoveToBookmark( bookmark ) ;
|
---|
413 | range.Select() ;
|
---|
414 | }
|
---|
415 | catch ( e ) {}
|
---|
416 |
|
---|
417 | // For some strange reason the SaveUndoStep() call doesn't activate the undo button at the first InsertHtml() call.
|
---|
418 | this.Events.FireEvent( "OnSelectionChange" ) ;
|
---|
419 | }
|
---|
420 |
|
---|
421 | FCK.PasteAsPlainText = function()
|
---|
422 | {
|
---|
423 | // TODO: Implement the "Paste as Plain Text" code.
|
---|
424 |
|
---|
425 | // If the function is called immediately Firefox 2 does automatically paste the contents as soon as the new dialog is created
|
---|
426 | // so we run it in a Timeout and the paste event can be cancelled
|
---|
427 | FCKTools.RunFunction( FCKDialog.OpenDialog, FCKDialog, ['FCKDialog_Paste', FCKLang.PasteAsText, 'dialog/fck_paste.html', 400, 330, 'PlainText'] ) ;
|
---|
428 |
|
---|
429 | /*
|
---|
430 | var sText = FCKTools.HTMLEncode( clipboardData.getData("Text") ) ;
|
---|
431 | sText = sText.replace( /\n/g, '<BR>' ) ;
|
---|
432 | this.InsertHtml( sText ) ;
|
---|
433 | */
|
---|
434 | }
|
---|
435 | /*
|
---|
436 | FCK.PasteFromWord = function()
|
---|
437 | {
|
---|
438 | // TODO: Implement the "Paste as Plain Text" code.
|
---|
439 |
|
---|
440 | FCKDialog.OpenDialog( 'FCKDialog_Paste', FCKLang.PasteFromWord, 'dialog/fck_paste.html', 400, 330, 'Word' ) ;
|
---|
441 |
|
---|
442 | // FCK.CleanAndPaste( FCK.GetClipboardHTML() ) ;
|
---|
443 | }
|
---|
444 | */
|
---|
445 | FCK.GetClipboardHTML = function()
|
---|
446 | {
|
---|
447 | return '' ;
|
---|
448 | }
|
---|
449 |
|
---|
450 | FCK.CreateLink = function( url, noUndo )
|
---|
451 | {
|
---|
452 | // Creates the array that will be returned. It contains one or more created links (see #220).
|
---|
453 | var aCreatedLinks = new Array() ;
|
---|
454 |
|
---|
455 | // Only for Safari, a collapsed selection may create a link. All other
|
---|
456 | // browser will have no links created. So, we check it here and return
|
---|
457 | // immediatelly, having the same cross browser behavior.
|
---|
458 | if ( FCKSelection.GetSelection().isCollapsed )
|
---|
459 | return aCreatedLinks ;
|
---|
460 |
|
---|
461 | FCK.ExecuteNamedCommand( 'Unlink', null, false, !!noUndo ) ;
|
---|
462 |
|
---|
463 | if ( url.length > 0 )
|
---|
464 | {
|
---|
465 | // Generate a temporary name for the link.
|
---|
466 | var sTempUrl = 'javascript:void(0);/*' + ( new Date().getTime() ) + '*/' ;
|
---|
467 |
|
---|
468 | // Use the internal "CreateLink" command to create the link.
|
---|
469 | FCK.ExecuteNamedCommand( 'CreateLink', sTempUrl, false, !!noUndo ) ;
|
---|
470 |
|
---|
471 | // Retrieve the just created links using XPath.
|
---|
472 | var oLinksInteractor = this.EditorDocument.evaluate("//a[@href='" + sTempUrl + "']", this.EditorDocument.body, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null) ;
|
---|
473 |
|
---|
474 | // Add all links to the returning array.
|
---|
475 | for ( var i = 0 ; i < oLinksInteractor.snapshotLength ; i++ )
|
---|
476 | {
|
---|
477 | var oLink = oLinksInteractor.snapshotItem( i ) ;
|
---|
478 | oLink.href = url ;
|
---|
479 |
|
---|
480 | aCreatedLinks.push( oLink ) ;
|
---|
481 | }
|
---|
482 | }
|
---|
483 |
|
---|
484 | return aCreatedLinks ;
|
---|
485 | }
|
---|
486 |
|
---|
487 | FCK._FillEmptyBlock = function( emptyBlockNode )
|
---|
488 | {
|
---|
489 | if ( ! emptyBlockNode || emptyBlockNode.nodeType != 1 )
|
---|
490 | return ;
|
---|
491 | var nodeTag = emptyBlockNode.tagName.toLowerCase() ;
|
---|
492 | if ( nodeTag != 'p' && nodeTag != 'div' )
|
---|
493 | return ;
|
---|
494 | if ( emptyBlockNode.firstChild )
|
---|
495 | return ;
|
---|
496 | FCKTools.AppendBogusBr( emptyBlockNode ) ;
|
---|
497 | }
|
---|
498 |
|
---|
499 | FCK._ExecCheckEmptyBlock = function()
|
---|
500 | {
|
---|
501 | FCK._FillEmptyBlock( FCK.EditorDocument.body.firstChild ) ;
|
---|
502 | var sel = FCKSelection.GetSelection() ;
|
---|
503 | if ( !sel || sel.rangeCount < 1 )
|
---|
504 | return ;
|
---|
505 | var range = sel.getRangeAt( 0 );
|
---|
506 | FCK._FillEmptyBlock( range.startContainer ) ;
|
---|
507 | }
|
---|