fckenterkey.js
上传用户:dbstep
上传日期:2022-08-06
资源大小:2803k
文件大小:21k
源码类别:

WEB源码(ASP,PHP,...)

开发平台:

ASP/ASPX

  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.  * Controls the [Enter] keystroke behavior in a document.
  22.  */
  23. /*
  24.  * Constructor.
  25.  * @targetDocument : the target document.
  26.  * @enterMode : the behavior for the <Enter> keystroke.
  27.  * May be "p", "div", "br". Default is "p".
  28.  * @shiftEnterMode : the behavior for the <Shift>+<Enter> keystroke.
  29.  * May be "p", "div", "br". Defaults to "br".
  30.  */
  31. var FCKEnterKey = function( targetWindow, enterMode, shiftEnterMode, tabSpaces )
  32. {
  33. this.Window = targetWindow ;
  34. this.EnterMode = enterMode || 'p' ;
  35. this.ShiftEnterMode = shiftEnterMode || 'br' ;
  36. // Setup the Keystroke Handler.
  37. var oKeystrokeHandler = new FCKKeystrokeHandler( false ) ;
  38. oKeystrokeHandler._EnterKey = this ;
  39. oKeystrokeHandler.OnKeystroke = FCKEnterKey_OnKeystroke ;
  40. oKeystrokeHandler.SetKeystrokes( [
  41. [ 13 , 'Enter' ],
  42. [ SHIFT + 13, 'ShiftEnter' ],
  43. [ 8 , 'Backspace' ],
  44. [ CTRL + 8 , 'CtrlBackspace' ],
  45. [ 46 , 'Delete' ]
  46. ] ) ;
  47. this.TabText = '' ;
  48. // Safari by default inserts 4 spaces on TAB, while others make the editor
  49. // loose focus. So, we need to handle it here to not include those spaces.
  50. if ( tabSpaces > 0 || FCKBrowserInfo.IsSafari )
  51. {
  52. while ( tabSpaces-- )
  53. this.TabText += 'xa0' ;
  54. oKeystrokeHandler.SetKeystrokes( [ 9, 'Tab' ] );
  55. }
  56. oKeystrokeHandler.AttachToElement( targetWindow.document ) ;
  57. }
  58. function FCKEnterKey_OnKeystroke(  keyCombination, keystrokeValue )
  59. {
  60. var oEnterKey = this._EnterKey ;
  61. try
  62. {
  63. switch ( keystrokeValue )
  64. {
  65. case 'Enter' :
  66. return oEnterKey.DoEnter() ;
  67. break ;
  68. case 'ShiftEnter' :
  69. return oEnterKey.DoShiftEnter() ;
  70. break ;
  71. case 'Backspace' :
  72. return oEnterKey.DoBackspace() ;
  73. break ;
  74. case 'Delete' :
  75. return oEnterKey.DoDelete() ;
  76. break ;
  77. case 'Tab' :
  78. return oEnterKey.DoTab() ;
  79. break ;
  80. case 'CtrlBackspace' :
  81. return oEnterKey.DoCtrlBackspace() ;
  82. break ;
  83. }
  84. }
  85. catch (e)
  86. {
  87. // If for any reason we are not able to handle it, go
  88. // ahead with the browser default behavior.
  89. }
  90. return false ;
  91. }
  92. /*
  93.  * Executes the <Enter> key behavior.
  94.  */
  95. FCKEnterKey.prototype.DoEnter = function( mode, hasShift )
  96. {
  97. // Save an undo snapshot before doing anything
  98. FCKUndo.SaveUndoStep() ;
  99. this._HasShift = ( hasShift === true ) ;
  100. var parentElement = FCKSelection.GetParentElement() ;
  101. var parentPath = new FCKElementPath( parentElement ) ;
  102. var sMode = mode || this.EnterMode ;
  103. if ( sMode == 'br' || parentPath.Block && parentPath.Block.tagName.toLowerCase() == 'pre' )
  104. return this._ExecuteEnterBr() ;
  105. else
  106. return this._ExecuteEnterBlock( sMode ) ;
  107. }
  108. /*
  109.  * Executes the <Shift>+<Enter> key behavior.
  110.  */
  111. FCKEnterKey.prototype.DoShiftEnter = function()
  112. {
  113. return this.DoEnter( this.ShiftEnterMode, true ) ;
  114. }
  115. /*
  116.  * Executes the <Backspace> key behavior.
  117.  */
  118. FCKEnterKey.prototype.DoBackspace = function()
  119. {
  120. var bCustom = false ;
  121. // Get the current selection.
  122. var oRange = new FCKDomRange( this.Window ) ;
  123. oRange.MoveToSelection() ;
  124. // Kludge for #247
  125. if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
  126. {
  127. this._FixIESelectAllBug( oRange ) ;
  128. return true ;
  129. }
  130. var isCollapsed = oRange.CheckIsCollapsed() ;
  131. if ( !isCollapsed )
  132. {
  133. // Bug #327, Backspace with an img selection would activate the default action in IE.
  134. // Let's override that with our logic here.
  135. if ( FCKBrowserInfo.IsIE && this.Window.document.selection.type.toLowerCase() == "control" )
  136. {
  137. var controls = this.Window.document.selection.createRange() ;
  138. for ( var i = controls.length - 1 ; i >= 0 ; i-- )
  139. {
  140. var el = controls.item( i ) ;
  141. el.parentNode.removeChild( el ) ;
  142. }
  143. return true ;
  144. }
  145. return false ;
  146. }
  147. // On IE, it is better for us handle the deletion if the caret is preceeded
  148. // by a <br> (#1383).
  149. if ( FCKBrowserInfo.IsIE )
  150. {
  151. var previousElement = FCKDomTools.GetPreviousSourceElement( oRange.StartNode, true ) ;
  152. if ( previousElement && previousElement.nodeName.toLowerCase() == 'br' )
  153. {
  154. // Create a range that starts after the <br> and ends at the
  155. // current range position.
  156. var testRange = oRange.Clone() ;
  157. testRange.SetStart( previousElement, 4 ) ;
  158. // If that range is empty, we can proceed cleaning that <br> manually.
  159. if ( testRange.CheckIsEmpty() )
  160. {
  161. previousElement.parentNode.removeChild( previousElement ) ;
  162. return true ;
  163. }
  164. }
  165. }
  166. var oStartBlock = oRange.StartBlock ;
  167. var oEndBlock = oRange.EndBlock ;
  168. // The selection boundaries must be in the same "block limit" element
  169. if ( oRange.StartBlockLimit == oRange.EndBlockLimit && oStartBlock && oEndBlock )
  170. {
  171. if ( !isCollapsed )
  172. {
  173. var bEndOfBlock = oRange.CheckEndOfBlock() ;
  174. oRange.DeleteContents() ;
  175. if ( oStartBlock != oEndBlock )
  176. {
  177. oRange.SetStart(oEndBlock,1) ;
  178. oRange.SetEnd(oEndBlock,1) ;
  179. // if ( bEndOfBlock )
  180. // oEndBlock.parentNode.removeChild( oEndBlock ) ;
  181. }
  182. oRange.Select() ;
  183. bCustom = ( oStartBlock == oEndBlock ) ;
  184. }
  185. if ( oRange.CheckStartOfBlock() )
  186. {
  187. var oCurrentBlock = oRange.StartBlock ;
  188. var ePrevious = FCKDomTools.GetPreviousSourceElement( oCurrentBlock, true, [ 'BODY', oRange.StartBlockLimit.nodeName ], ['UL','OL'] ) ;
  189. bCustom = this._ExecuteBackspace( oRange, ePrevious, oCurrentBlock ) ;
  190. }
  191. else if ( FCKBrowserInfo.IsGeckoLike )
  192. {
  193. // Firefox and Opera (#1095) loose the selection when executing
  194. // CheckStartOfBlock, so we must reselect.
  195. oRange.Select() ;
  196. }
  197. }
  198. oRange.Release() ;
  199. return bCustom ;
  200. }
  201. FCKEnterKey.prototype.DoCtrlBackspace = function()
  202. {
  203. FCKUndo.SaveUndoStep() ;
  204. var oRange = new FCKDomRange( this.Window ) ;
  205. oRange.MoveToSelection() ;
  206. if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
  207. {
  208. this._FixIESelectAllBug( oRange ) ;
  209. return true ;
  210. }
  211. return false ;
  212. }
  213. FCKEnterKey.prototype._ExecuteBackspace = function( range, previous, currentBlock )
  214. {
  215. var bCustom = false ;
  216. // We could be in a nested LI.
  217. if ( !previous && currentBlock && currentBlock.nodeName.IEquals( 'LI' ) && currentBlock.parentNode.parentNode.nodeName.IEquals( 'LI' ) )
  218. {
  219. this._OutdentWithSelection( currentBlock, range ) ;
  220. return true ;
  221. }
  222. if ( previous && previous.nodeName.IEquals( 'LI' ) )
  223. {
  224. var oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ;
  225. while ( oNestedList )
  226. {
  227. previous = FCKDomTools.GetLastChild( oNestedList, 'LI' ) ;
  228. oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ;
  229. }
  230. }
  231. if ( previous && currentBlock )
  232. {
  233. // If we are in a LI, and the previous block is not an LI, we must outdent it.
  234. if ( currentBlock.nodeName.IEquals( 'LI' ) && !previous.nodeName.IEquals( 'LI' ) )
  235. {
  236. this._OutdentWithSelection( currentBlock, range ) ;
  237. return true ;
  238. }
  239. // Take a reference to the parent for post processing cleanup.
  240. var oCurrentParent = currentBlock.parentNode ;
  241. var sPreviousName = previous.nodeName.toLowerCase() ;
  242. if ( FCKListsLib.EmptyElements[ sPreviousName ] != null || sPreviousName == 'table' )
  243. {
  244. FCKDomTools.RemoveNode( previous ) ;
  245. bCustom = true ;
  246. }
  247. else
  248. {
  249. // Remove the current block.
  250. FCKDomTools.RemoveNode( currentBlock ) ;
  251. // Remove any empty tag left by the block removal.
  252. while ( oCurrentParent.innerHTML.Trim().length == 0 )
  253. {
  254. var oParent = oCurrentParent.parentNode ;
  255. oParent.removeChild( oCurrentParent ) ;
  256. oCurrentParent = oParent ;
  257. }
  258. // Cleanup the previous and the current elements.
  259. FCKDomTools.LTrimNode( currentBlock ) ;
  260. FCKDomTools.RTrimNode( previous ) ;
  261. // Append a space to the previous.
  262. // Maybe it is not always desirable...
  263. // previous.appendChild( this.Window.document.createTextNode( ' ' ) ) ;
  264. // Set the range to the end of the previous element and bookmark it.
  265. range.SetStart( previous, 2, true ) ;
  266. range.Collapse( true ) ;
  267. var oBookmark = range.CreateBookmark( true ) ;
  268. // Move the contents of the block to the previous element and delete it.
  269. // But for some block types (e.g. table), moving the children to the previous block makes no sense.
  270. // So a check is needed. (See #1081)
  271. if ( ! currentBlock.tagName.IEquals( [ 'TABLE' ] ) )
  272. FCKDomTools.MoveChildren( currentBlock, previous ) ;
  273. // Place the selection at the bookmark.
  274. range.SelectBookmark( oBookmark ) ;
  275. bCustom = true ;
  276. }
  277. }
  278. return bCustom ;
  279. }
  280. /*
  281.  * Executes the <Delete> key behavior.
  282.  */
  283. FCKEnterKey.prototype.DoDelete = function()
  284. {
  285. // Save an undo snapshot before doing anything
  286. // This is to conform with the behavior seen in MS Word
  287. FCKUndo.SaveUndoStep() ;
  288. // The <Delete> has the same effect as the <Backspace>, so we have the same
  289. // results if we just move to the next block and apply the same <Backspace> logic.
  290. var bCustom = false ;
  291. // Get the current selection.
  292. var oRange = new FCKDomRange( this.Window ) ;
  293. oRange.MoveToSelection() ;
  294. // Kludge for #247
  295. if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
  296. {
  297. this._FixIESelectAllBug( oRange ) ;
  298. return true ;
  299. }
  300. // There is just one special case for collapsed selections at the end of a block.
  301. if ( oRange.CheckIsCollapsed() && oRange.CheckEndOfBlock( FCKBrowserInfo.IsGeckoLike ) )
  302. {
  303. var oCurrentBlock = oRange.StartBlock ;
  304. var eCurrentCell = FCKTools.GetElementAscensor( oCurrentBlock, 'td' );
  305. var eNext = FCKDomTools.GetNextSourceElement( oCurrentBlock, true, [ oRange.StartBlockLimit.nodeName ],
  306. ['UL','OL','TR'], true ) ;
  307. // Bug #1323 : if we're in a table cell, and the next node belongs to a different cell, then don't
  308. // delete anything.
  309. if ( eCurrentCell )
  310. {
  311. var eNextCell = FCKTools.GetElementAscensor( eNext, 'td' );
  312. if ( eNextCell != eCurrentCell )
  313. return true ;
  314. }
  315. bCustom = this._ExecuteBackspace( oRange, oCurrentBlock, eNext ) ;
  316. }
  317. oRange.Release() ;
  318. return bCustom ;
  319. }
  320. /*
  321.  * Executes the <Tab> key behavior.
  322.  */
  323. FCKEnterKey.prototype.DoTab = function()
  324. {
  325. var oRange = new FCKDomRange( this.Window );
  326. oRange.MoveToSelection() ;
  327. // If the user pressed <tab> inside a table, we should give him the default behavior ( moving between cells )
  328. // instead of giving him more non-breaking spaces. (Bug #973)
  329. var node = oRange._Range.startContainer ;
  330. while ( node )
  331. {
  332. if ( node.nodeType == 1 )
  333. {
  334. var tagName = node.tagName.toLowerCase() ;
  335. if ( tagName == "tr" || tagName == "td" || tagName == "th" || tagName == "tbody" || tagName == "table" )
  336. return false ;
  337. else
  338. break ;
  339. }
  340. node = node.parentNode ;
  341. }
  342. if ( this.TabText )
  343. {
  344. oRange.DeleteContents() ;
  345. oRange.InsertNode( this.Window.document.createTextNode( this.TabText ) ) ;
  346. oRange.Collapse( false ) ;
  347. oRange.Select() ;
  348. }
  349. return true ;
  350. }
  351. FCKEnterKey.prototype._ExecuteEnterBlock = function( blockTag, range )
  352. {
  353. // Get the current selection.
  354. var oRange = range || new FCKDomRange( this.Window ) ;
  355. var oSplitInfo = oRange.SplitBlock( blockTag ) ;
  356. if ( oSplitInfo )
  357. {
  358. // Get the current blocks.
  359. var ePreviousBlock = oSplitInfo.PreviousBlock ;
  360. var eNextBlock = oSplitInfo.NextBlock ;
  361. var bIsStartOfBlock = oSplitInfo.WasStartOfBlock ;
  362. var bIsEndOfBlock = oSplitInfo.WasEndOfBlock ;
  363. // If there is one block under a list item, modify the split so that the list item gets split as well. (Bug #1647)
  364. if ( eNextBlock )
  365. {
  366. if ( eNextBlock.parentNode.nodeName.IEquals( 'li' ) )
  367. {
  368. FCKDomTools.BreakParent( eNextBlock, eNextBlock.parentNode ) ;
  369. FCKDomTools.MoveNode( eNextBlock, eNextBlock.nextSibling, true ) ;
  370. }
  371. }
  372. else if ( ePreviousBlock && ePreviousBlock.parentNode.nodeName.IEquals( 'li' ) )
  373. {
  374. FCKDomTools.BreakParent( ePreviousBlock, ePreviousBlock.parentNode ) ;
  375. oRange.MoveToElementEditStart( ePreviousBlock.nextSibling );
  376. FCKDomTools.MoveNode( ePreviousBlock, ePreviousBlock.previousSibling ) ;
  377. }
  378. // If we have both the previous and next blocks, it means that the
  379. // boundaries were on separated blocks, or none of them where on the
  380. // block limits (start/end).
  381. if ( !bIsStartOfBlock && !bIsEndOfBlock )
  382. {
  383. // If the next block is an <li> with another list tree as the first child
  384. // We'll need to append a placeholder or the list item wouldn't be editable. (Bug #1420)
  385. if ( eNextBlock.nodeName.IEquals( 'li' ) && eNextBlock.firstChild
  386. && eNextBlock.firstChild.nodeName.IEquals( ['ul', 'ol'] ) )
  387. eNextBlock.insertBefore( FCKTools.GetElementDocument( eNextBlock ).createTextNode( 'xa0' ), eNextBlock.firstChild ) ;
  388. // Move the selection to the end block.
  389. if ( eNextBlock )
  390. oRange.MoveToElementEditStart( eNextBlock ) ;
  391. }
  392. else
  393. {
  394. if ( bIsStartOfBlock && bIsEndOfBlock && ePreviousBlock.tagName.toUpperCase() == 'LI' )
  395. {
  396. oRange.MoveToElementStart( ePreviousBlock ) ;
  397. this._OutdentWithSelection( ePreviousBlock, oRange ) ;
  398. oRange.Release() ;
  399. return true ;
  400. }
  401. var eNewBlock ;
  402. if ( ePreviousBlock )
  403. {
  404. var sPreviousBlockTag = ePreviousBlock.tagName.toUpperCase() ;
  405. // If is a header tag, or we are in a Shift+Enter (#77),
  406. // create a new block element (later in the code).
  407. if ( !this._HasShift && !(/^H[1-6]$/).test( sPreviousBlockTag ) )
  408. {
  409. // Otherwise, duplicate the previous block.
  410. eNewBlock = FCKDomTools.CloneElement( ePreviousBlock ) ;
  411. }
  412. }
  413. else if ( eNextBlock )
  414. eNewBlock = FCKDomTools.CloneElement( eNextBlock ) ;
  415. if ( !eNewBlock )
  416. eNewBlock = this.Window.document.createElement( blockTag ) ;
  417. // Recreate the inline elements tree, which was available
  418. // before the hitting enter, so the same styles will be
  419. // available in the new block.
  420. var elementPath = oSplitInfo.ElementPath ;
  421. if ( elementPath )
  422. {
  423. for ( var i = 0, len = elementPath.Elements.length ; i < len ; i++ )
  424. {
  425. var element = elementPath.Elements[i] ;
  426. if ( element == elementPath.Block || element == elementPath.BlockLimit )
  427. break ;
  428. if ( FCKListsLib.InlineChildReqElements[ element.nodeName.toLowerCase() ] )
  429. {
  430. element = FCKDomTools.CloneElement( element ) ;
  431. FCKDomTools.MoveChildren( eNewBlock, element ) ;
  432. eNewBlock.appendChild( element ) ;
  433. }
  434. }
  435. }
  436. if ( FCKBrowserInfo.IsGeckoLike )
  437. FCKTools.AppendBogusBr( eNewBlock ) ;
  438. oRange.InsertNode( eNewBlock ) ;
  439. // This is tricky, but to make the new block visible correctly
  440. // we must select it.
  441. if ( FCKBrowserInfo.IsIE )
  442. {
  443. // Move the selection to the new block.
  444. oRange.MoveToElementEditStart( eNewBlock ) ;
  445. oRange.Select() ;
  446. }
  447. // Move the selection to the new block.
  448. oRange.MoveToElementEditStart( bIsStartOfBlock && !bIsEndOfBlock ? eNextBlock : eNewBlock ) ;
  449. }
  450. if ( FCKBrowserInfo.IsGeckoLike )
  451. {
  452. if ( eNextBlock )
  453. {
  454. // If we have split the block, adds a temporary span at the
  455. // range position and scroll relatively to it.
  456. var tmpNode = this.Window.document.createElement( 'span' ) ;
  457. // We need some content for Safari.
  458. tmpNode.innerHTML = '&nbsp;';
  459. oRange.InsertNode( tmpNode ) ;
  460. FCKDomTools.ScrollIntoView( tmpNode, false ) ;
  461. oRange.DeleteContents() ;
  462. }
  463. else
  464. {
  465. // We may use the above scroll logic for the new block case
  466. // too, but it gives some weird result with Opera.
  467. FCKDomTools.ScrollIntoView( eNextBlock || eNewBlock, false ) ;
  468. }
  469. }
  470. oRange.Select() ;
  471. }
  472. // Release the resources used by the range.
  473. oRange.Release() ;
  474. return true ;
  475. }
  476. FCKEnterKey.prototype._ExecuteEnterBr = function( blockTag )
  477. {
  478. // Get the current selection.
  479. var oRange = new FCKDomRange( this.Window ) ;
  480. oRange.MoveToSelection() ;
  481. // The selection boundaries must be in the same "block limit" element.
  482. if ( oRange.StartBlockLimit == oRange.EndBlockLimit )
  483. {
  484. oRange.DeleteContents() ;
  485. // Get the new selection (it is collapsed at this point).
  486. oRange.MoveToSelection() ;
  487. var bIsStartOfBlock = oRange.CheckStartOfBlock() ;
  488. var bIsEndOfBlock = oRange.CheckEndOfBlock() ;
  489. var sStartBlockTag = oRange.StartBlock ? oRange.StartBlock.tagName.toUpperCase() : '' ;
  490. var bHasShift = this._HasShift ;
  491. var bIsPre = false ;
  492. if ( !bHasShift && sStartBlockTag == 'LI' )
  493. return this._ExecuteEnterBlock( null, oRange ) ;
  494. // If we are at the end of a header block.
  495. if ( !bHasShift && bIsEndOfBlock && (/^H[1-6]$/).test( sStartBlockTag ) )
  496. {
  497. // Insert a BR after the current paragraph.
  498. FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createElement( 'br' ) ) ;
  499. // The space is required by Gecko only to make the cursor blink.
  500. if ( FCKBrowserInfo.IsGecko )
  501. FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createTextNode( '' ) ) ;
  502. // IE and Gecko have different behaviors regarding the position.
  503. oRange.SetStart( oRange.StartBlock.nextSibling, FCKBrowserInfo.IsIE ? 3 : 1 ) ;
  504. }
  505. else
  506. {
  507. var eLineBreak ;
  508. bIsPre = sStartBlockTag.IEquals( 'pre' ) ;
  509. if ( bIsPre )
  510. eLineBreak = this.Window.document.createTextNode( FCKBrowserInfo.IsIE ? 'r' : 'n' ) ;
  511. else
  512. eLineBreak = this.Window.document.createElement( 'br' ) ;
  513. oRange.InsertNode( eLineBreak ) ;
  514. // The space is required by Gecko only to make the cursor blink.
  515. if ( FCKBrowserInfo.IsGecko )
  516. FCKDomTools.InsertAfterNode( eLineBreak, this.Window.document.createTextNode( '' ) ) ;
  517. // If we are at the end of a block, we must be sure the bogus node is available in that block.
  518. if ( bIsEndOfBlock && FCKBrowserInfo.IsGeckoLike )
  519. FCKTools.AppendBogusBr( eLineBreak.parentNode ) ;
  520. if ( FCKBrowserInfo.IsIE )
  521. oRange.SetStart( eLineBreak, 4 ) ;
  522. else
  523. oRange.SetStart( eLineBreak.nextSibling, 1 ) ;
  524. if ( ! FCKBrowserInfo.IsIE )
  525. {
  526. var dummy = null ;
  527. if ( FCKBrowserInfo.IsOpera )
  528. dummy = this.Window.document.createElement( 'span' ) ;
  529. else
  530. dummy = this.Window.document.createElement( 'br' ) ;
  531. eLineBreak.parentNode.insertBefore( dummy, eLineBreak.nextSibling ) ;
  532. FCKDomTools.ScrollIntoView( dummy, false ) ;
  533. dummy.parentNode.removeChild( dummy ) ;
  534. }
  535. }
  536. // This collapse guarantees the cursor will be blinking.
  537. oRange.Collapse( true ) ;
  538. oRange.Select( bIsPre ) ;
  539. }
  540. // Release the resources used by the range.
  541. oRange.Release() ;
  542. return true ;
  543. }
  544. // Outdents a LI, maintaining the selection defined on a range.
  545. FCKEnterKey.prototype._OutdentWithSelection = function( li, range )
  546. {
  547. var oBookmark = range.CreateBookmark() ;
  548. FCKListHandler.OutdentListItem( li ) ;
  549. range.MoveToBookmark( oBookmark ) ;
  550. range.Select() ;
  551. }
  552. // Is all the contents under a node included by a range?
  553. FCKEnterKey.prototype._CheckIsAllContentsIncluded = function( range, node )
  554. {
  555. var startOk = false ;
  556. var endOk = false ;
  557. /*
  558. FCKDebug.Output( 'sc='+range.StartContainer.nodeName+
  559. ',so='+range._Range.startOffset+
  560. ',ec='+range.EndContainer.nodeName+
  561. ',eo='+range._Range.endOffset ) ;
  562. */
  563. if ( range.StartContainer == node || range.StartContainer == node.firstChild )
  564. startOk = ( range._Range.startOffset == 0 ) ;
  565. if ( range.EndContainer == node || range.EndContainer == node.lastChild )
  566. {
  567. var nodeLength = range.EndContainer.nodeType == 3 ? range.EndContainer.length : range.EndContainer.childNodes.length ;
  568. endOk = ( range._Range.endOffset == nodeLength ) ;
  569. }
  570. return startOk && endOk ;
  571. }
  572. // Kludge for #247
  573. FCKEnterKey.prototype._FixIESelectAllBug = function( range )
  574. {
  575. var doc = this.Window.document ;
  576. doc.body.innerHTML = '' ;
  577. var editBlock ;
  578. if ( FCKConfig.EnterMode.IEquals( ['div', 'p'] ) )
  579. {
  580. editBlock = doc.createElement( FCKConfig.EnterMode ) ;
  581. doc.body.appendChild( editBlock ) ;
  582. }
  583. else
  584. editBlock = doc.body ;
  585. range.MoveToNodeContents( editBlock ) ;
  586. range.Collapse( true ) ;
  587. range.Select() ;
  588. range.Release() ;
  589. }