[ Index ]
 

Code source de FCKeditor 2.4

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/editor/_source/classes/ -> fckenterkey.js (source)

   1  /*
   2   * FCKeditor - The text editor for Internet - http://www.fckeditor.net
   3   * Copyright (C) 2003-2007 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   * File Name: fckenterkey.js
  22   *     Controls the [Enter] keystroke behavior in a document.
  23   * 
  24   * File Authors:
  25   *         Frederico Caldeira Knabben (www.fckeditor.net)
  26   */
  27  
  28  /*
  29   *    Constructor.
  30   *        @targetDocument : the target document.
  31   *        @enterMode : the behavior for the <Enter> keystroke.
  32   *            May be "p", "div", "br". Default is "p".
  33   *        @shiftEnterMode : the behavior for the <Shift>+<Enter> keystroke. 
  34   *            May be "p", "div", "br". Defaults to "br".
  35   */
  36  var FCKEnterKey = function( targetWindow, enterMode, shiftEnterMode )
  37  {
  38      this.Window            = targetWindow ;
  39      this.EnterMode        = enterMode || 'p' ;
  40      this.ShiftEnterMode    = shiftEnterMode || 'br' ;
  41  
  42      // Setup the Keystroke Handler.
  43      var oKeystrokeHandler = new FCKKeystrokeHandler( false ) ;
  44      oKeystrokeHandler._EnterKey = this ;
  45      oKeystrokeHandler.OnKeystroke = FCKEnterKey_OnKeystroke ;
  46      
  47      oKeystrokeHandler.SetKeystrokes( [
  48          [ 13        , 'Enter' ],
  49          [ SHIFT + 13, 'ShiftEnter' ], 
  50          [ 8            , 'Backspace' ],
  51          [ 46        , 'Delete' ]
  52      ] ) ;
  53  
  54      oKeystrokeHandler.AttachToElement( targetWindow.document ) ;
  55  }
  56  
  57  
  58  function FCKEnterKey_OnKeystroke(  keyCombination, keystrokeValue )
  59  {
  60      var oEnterKey = this._EnterKey ;
  61      
  62      try
  63      {
  64          switch ( keystrokeValue )
  65          {
  66              case 'Enter' :
  67                  return oEnterKey.DoEnter() ;
  68                  break ;
  69  
  70              case 'ShiftEnter' :
  71                  return oEnterKey.DoShiftEnter() ;
  72                  break ;
  73  
  74              case 'Backspace' :
  75                  return oEnterKey.DoBackspace() ;
  76                  break ;
  77  
  78              case 'Delete' :
  79                  return oEnterKey.DoDelete() ;
  80          }
  81      }
  82      catch (e)
  83      {
  84          // If for any reason we are not able to handle it, go 
  85          // ahead with the browser default behavior.
  86      }
  87      
  88      return false ;
  89  }
  90  
  91  /*
  92   * Executes the <Enter> key behavior.
  93   */
  94  FCKEnterKey.prototype.DoEnter = function( mode, hasShift )
  95  {
  96      this._HasShift = ( hasShift === true ) ;
  97      
  98      var sMode = mode || this.EnterMode ;
  99  
 100      if ( sMode == 'br' )
 101          return this._ExecuteEnterBr() ;
 102      else
 103          return this._ExecuteEnterBlock( sMode ) ;
 104  }
 105  
 106  /*
 107   * Executes the <Shift>+<Enter> key behavior.
 108   */
 109  FCKEnterKey.prototype.DoShiftEnter = function()
 110  {
 111      return this.DoEnter( this.ShiftEnterMode, true ) ;
 112  }
 113  
 114  /*
 115   * Executes the <Backspace> key behavior.
 116   */
 117  FCKEnterKey.prototype.DoBackspace = function()
 118  {
 119      var bCustom = false ;
 120  
 121      // Get the current selection.
 122      var oRange = new FCKDomRange( this.Window ) ;
 123      oRange.MoveToSelection() ;
 124      
 125      if ( !oRange.CheckIsCollapsed() )
 126          return false ;
 127  
 128      
 129      var oStartBlock = oRange.StartBlock ;
 130      var oEndBlock = oRange.EndBlock ;
 131  
 132      // The selection boundaries must be in the same "block limit" element
 133      if ( oRange.StartBlockLimit == oRange.EndBlockLimit && oStartBlock && oEndBlock )
 134      {
 135          if ( !oRange.CheckIsCollapsed() )
 136          {
 137              var bEndOfBlock = oRange.CheckEndOfBlock() ;
 138              
 139              oRange.DeleteContents() ;
 140              
 141              if ( oStartBlock != oEndBlock )
 142              {
 143                  oRange.SetStart(oEndBlock,1) ;
 144                  oRange.SetEnd(oEndBlock,1) ;
 145                  
 146  //                if ( bEndOfBlock )
 147  //                    oEndBlock.parentNode.removeChild( oEndBlock ) ;
 148              }
 149          
 150              oRange.Select() ;
 151              
 152              bCustom = ( oStartBlock == oEndBlock ) ;
 153          }
 154          
 155          if ( oRange.CheckStartOfBlock() )
 156          {
 157              var oCurrentBlock = oRange.StartBlock ;
 158              
 159              var ePrevious = FCKDomTools.GetPreviousSourceElement( oCurrentBlock, true, [ 'BODY', oRange.StartBlockLimit.nodeName ], ['UL','OL'] ) ;
 160  
 161              bCustom = this._ExecuteBackspace( oRange, ePrevious, oCurrentBlock ) ;
 162          }
 163          else if ( FCKBrowserInfo.IsGecko )
 164          {
 165              // Firefox looses the selection when executing CheckStartOfBlock, so we must reselect.
 166              oRange.Select() ;
 167          }
 168      }
 169  
 170      oRange.Release() ;
 171      return bCustom ;
 172  }
 173  
 174  FCKEnterKey.prototype._ExecuteBackspace = function( range, previous, currentBlock )
 175  {
 176      var bCustom = false ;
 177  
 178      // We could be in a nested LI.
 179      if ( !previous && currentBlock.nodeName.IEquals( 'LI' ) && currentBlock.parentNode.parentNode.nodeName.IEquals( 'LI' ) )
 180      {
 181          previous = currentBlock.parentNode.parentNode ;
 182          currentBlock = FCKListHandler.OutdentListItem( currentBlock ) ;
 183      }
 184  
 185      if ( previous && previous.nodeName.IEquals( 'LI' ) )
 186      {
 187          var oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ;
 188          
 189          while ( oNestedList )
 190          {
 191              previous = FCKDomTools.GetLastChild( oNestedList, 'LI' ) ;
 192              oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ;
 193          }
 194      }
 195  
 196      if ( previous && currentBlock )
 197      {
 198          // If we are in a LI, and the previous block is not an LI, we must 
 199          if ( currentBlock.nodeName.IEquals( 'LI' ) && !previous.nodeName.IEquals( 'LI' ) )
 200              currentBlock = FCKListHandler.OutdentListItem( currentBlock ) ;
 201  
 202          // Take a reference to the parent for post processing cleanup.
 203          var oCurrentParent = currentBlock.parentNode ;
 204  
 205          if ( previous.nodeName.IEquals( 'TABLE', 'HR' ) ) 
 206          {
 207              FCKDomTools.RemoveNode( previous ) ;
 208              bCustom = true ;
 209          }
 210          else
 211          {
 212              // Remove the current block.
 213              FCKDomTools.RemoveNode( currentBlock ) ;
 214              
 215              // Remove any empty tag left by the block removal.
 216              while ( oCurrentParent.innerHTML.Trim().length == 0 )
 217              {
 218                  var oParent = oCurrentParent.parentNode ;
 219                  oParent.removeChild( oCurrentParent ) ;
 220                  oCurrentParent = oParent ;
 221              }
 222              
 223              // Cleanup the previous and the current elements.
 224              FCKDomTools.TrimNode( currentBlock ) ;
 225              FCKDomTools.TrimNode( previous ) ;
 226              
 227              // Append a space to the previous.
 228              // Maybe it is not always desirable...
 229              // previous.appendChild( this.Window.document.createTextNode( ' ' ) ) ;
 230              
 231              // Set the range to the end of the previous element and bookmark it.
 232              range.SetStart( previous, 2 ) ;
 233              range.Collapse( true ) ;
 234              var oBookmark = range.CreateBookmark() ;
 235  
 236              // Move the contents of the block to the previous element and delete it.
 237              FCKDomTools.MoveChildren( currentBlock, previous ) ;
 238  
 239              // Place the selection at the bookmark.
 240              range.MoveToBookmark( oBookmark ) ;
 241              range.Select() ;
 242  
 243              bCustom = true ;
 244          }
 245      }
 246      
 247      return bCustom ;
 248  }
 249  
 250  /*
 251   * Executes the <Delete> key behavior.
 252   */
 253  FCKEnterKey.prototype.DoDelete = function()
 254  {
 255      // The <Delete> has the same effect as the <Backspace>, so we have the same
 256      // results if we just move to the next block and apply the same <Backspace> logic.
 257  
 258      var bCustom = false ;
 259  
 260      // Get the current selection.
 261      var oRange = new FCKDomRange( this.Window ) ;
 262      oRange.MoveToSelection() ;
 263      
 264      // There is just one special case for collapsed selections at the end of a block.
 265      if ( oRange.CheckIsCollapsed() && oRange.CheckEndOfBlock( FCKBrowserInfo.IsGecko ) )
 266      {
 267          var oCurrentBlock = oRange.StartBlock ;
 268          
 269          var eNext = FCKDomTools.GetNextSourceElement( oCurrentBlock, true, [ oRange.StartBlockLimit.nodeName ], ['UL','OL'] ) ;
 270          
 271          bCustom = this._ExecuteBackspace( oRange, oCurrentBlock, eNext ) ;
 272      }
 273  
 274      oRange.Release() ;
 275      return bCustom ;
 276  }
 277  
 278  FCKEnterKey.prototype._ExecuteEnterBlock = function( blockTag )
 279  {
 280      // Get the current selection.
 281      var oRange = new FCKDomRange( this.Window ) ;
 282      oRange.MoveToSelection() ;
 283      
 284      // The selection boundaries must be in the same "block limit" element.
 285      if ( oRange.StartBlockLimit == oRange.EndBlockLimit )
 286      {
 287          // If the StartBlock or EndBlock are not available (for text without a
 288          // block tag), we must fix them, by moving the text to a block.
 289          if ( !oRange.StartBlock )
 290              this._FixBlock( oRange, true, blockTag ) ;
 291  
 292          if ( !oRange.EndBlock )
 293              this._FixBlock( oRange, false, blockTag ) ;
 294  
 295          // Get the current blocks.
 296          var eStartBlock    = oRange.StartBlock ;
 297          var eEndBlock    = oRange.EndBlock ;
 298              
 299          // Delete the current selection.
 300          if ( !oRange.CheckIsEmpty() )
 301              oRange.DeleteContents() ;
 302  
 303          // If the selection boundaries are in the same block element
 304          if ( eStartBlock == eEndBlock )
 305          {
 306              var eNewBlock ;
 307  
 308              var bIsStartOfBlock    = oRange.CheckStartOfBlock() ;
 309              var bIsEndOfBlock    = oRange.CheckEndOfBlock() ;
 310  
 311              if ( bIsStartOfBlock && !bIsEndOfBlock )
 312              {
 313                  eNewBlock = eStartBlock.cloneNode(false) ;
 314  
 315                  if ( FCKBrowserInfo.IsGeckoLike )
 316                      eNewBlock.innerHTML = GECKO_BOGUS ;
 317                  
 318                  // Place the new block before the current block element.
 319                  eStartBlock.parentNode.insertBefore( eNewBlock, eStartBlock ) ;
 320  
 321                  // This is tricky, but to make the new block visible correctly
 322                  // we must select it.
 323                  if ( FCKBrowserInfo.IsIE )
 324                  {
 325                      // Move the selection to the new block.
 326                      oRange.MoveToNodeContents( eNewBlock ) ;
 327  
 328                      oRange.Select() ;
 329                  }
 330  
 331                  // Move the selection to the new block.
 332                  oRange.MoveToElementStart( eStartBlock ) ;
 333              }
 334              else
 335              {
 336                  // Check if the selection is at the end of the block.
 337                  if ( bIsEndOfBlock )
 338                  {
 339                      var sStartBlockTag = eStartBlock.tagName.toUpperCase() ;
 340  
 341                      // If the entire block is selected, and we are in a LI, let's decrease its indentation.
 342                      if ( bIsStartOfBlock && sStartBlockTag == 'LI' )
 343                      {
 344                          var eOutdented = FCKListHandler.OutdentListItem( eStartBlock ) ;
 345                          oRange.MoveToElementStart( eOutdented ) ;
 346                      }
 347                      else
 348                      {
 349                          // If is a header tag, create a new block element.
 350                          if ( (/^H[1-6]$/).test( sStartBlockTag ) )
 351                              eNewBlock = this.Window.document.createElement( blockTag ) ;
 352                          // Otherwise, duplicate the current block.
 353                          else
 354                              eNewBlock = eStartBlock.cloneNode(false) ;
 355                          
 356                          if ( FCKBrowserInfo.IsGeckoLike )
 357                          {
 358                              eNewBlock.innerHTML = GECKO_BOGUS ;
 359  
 360                              // If the entire block is selected, let's add a bogus in the start block.
 361                              if ( bIsStartOfBlock )
 362                                  eStartBlock.innerHTML = GECKO_BOGUS ;
 363                          }
 364                      }
 365                  }
 366                  else
 367                  {
 368                      // Extract the contents of the block from the selection point to the end of its contents.
 369                      oRange.SetEnd( eStartBlock, 2 ) ;
 370                      var eDocFrag = oRange.ExtractContents() ;
 371                      
 372                      // Duplicate the block element after it.
 373                      eNewBlock = eStartBlock.cloneNode(false) ;
 374  
 375                      // It could be that we are in a LI with a child UL/OL. Insert a bogus to give us space to type.
 376                      FCKDomTools.TrimNode( eDocFrag.RootNode ) ;
 377                      if ( eDocFrag.RootNode.firstChild.nodeType == 1 && eDocFrag.RootNode.firstChild.tagName.toUpperCase().Equals( 'UL', 'OL' ) )
 378                          eNewBlock.innerHTML = GECKO_BOGUS ;
 379                      
 380                      // Place the extracted contents in the duplicated block.
 381                      eDocFrag.AppendTo( eNewBlock ) ;
 382  
 383                      if ( FCKBrowserInfo.IsGecko )
 384                      {
 385                          // In Gecko, the last child node must be a bogus <br>. 
 386                          var eLastChild = FCKDomTools.GetLastChild( eNewBlock ) ;
 387                          
 388                          if ( !eLastChild || eLastChild.nodeName.toLowerCase() != 'br' || eLastChild.getAttribute( 'type', 2 ) != '_moz' )
 389                              eNewBlock.appendChild( FCKTools.CreateBogusBR( this.Window.document ) ) ;
 390                      }
 391                  }
 392  
 393                  if ( eNewBlock )
 394                  {
 395                      FCKDomTools.InsertAfterNode( eStartBlock, eNewBlock ) ;
 396  
 397                      // Move the selection to the new block.
 398                      oRange.MoveToElementStart( eNewBlock ) ;
 399                      
 400                      if ( FCKBrowserInfo.IsGecko )
 401                          eNewBlock.scrollIntoView( false ) ;
 402                  }
 403              }
 404          }
 405          else
 406          {
 407              // Move the selection to the end block.
 408              oRange.MoveToElementStart( eEndBlock ) ;
 409          }
 410  
 411          oRange.Select() ;                
 412      }
 413      
 414      // Release the resources used by the range.
 415      oRange.Release() ;
 416      
 417      return true ;
 418  }
 419  
 420  FCKEnterKey.prototype._ExecuteEnterBr = function( blockTag )
 421  {
 422      // Get the current selection.
 423      var oRange = new FCKDomRange( this.Window ) ;
 424      oRange.MoveToSelection() ;
 425  
 426      // The selection boundaries must be in the same "block limit" element.
 427      if ( oRange.StartBlockLimit == oRange.EndBlockLimit )
 428      {
 429          oRange.DeleteContents() ;
 430          
 431          // Get the new selection (it is collapsed at this point).
 432          oRange.MoveToSelection() ;
 433      
 434          var bIsStartOfBlock    = oRange.CheckStartOfBlock() ;
 435          var bIsEndOfBlock    = oRange.CheckEndOfBlock() ;
 436          
 437          var sStartBlockTag = oRange.StartBlock ? oRange.StartBlock.tagName.toUpperCase() : '' ;
 438          
 439          var bHasShift = this._HasShift ;
 440          
 441          if ( !bHasShift && sStartBlockTag == 'LI' )
 442              return this._ExecuteEnterBlock( null ) ;
 443  
 444          // If we are at the end of a header block.
 445          if ( !bHasShift && bIsEndOfBlock && (/^H[1-6]$/).test( sStartBlockTag ) )
 446          {
 447              FCKDebug.Output( 'BR - Header' ) ;
 448  
 449              // Insert a BR after the current paragraph.
 450              FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createElement( 'br' ) ) ;
 451  
 452              // The space is required by Gecko only to make the cursor blink.
 453              if ( FCKBrowserInfo.IsGecko )
 454                  FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createTextNode( '' ) ) ;
 455  
 456              // IE and Gecko have different behaviors regarding the position.
 457              oRange.SetStart( oRange.StartBlock.nextSibling, FCKBrowserInfo.IsIE ? 3 : 1 ) ;
 458          }
 459          else
 460          {
 461              FCKDebug.Output( 'BR - No Header' ) ;
 462  
 463              var eBr = this.Window.document.createElement( 'br' ) ;
 464  
 465              oRange.InsertNode( eBr ) ;
 466              
 467              // The space is required by Gecko only to make the cursor blink.
 468              if ( FCKBrowserInfo.IsGecko )
 469                  FCKDomTools.InsertAfterNode( eBr, this.Window.document.createTextNode( '' ) ) ;
 470                  
 471              // If we are at the end of a block, we must be sure the bogus node is available in that block.
 472              if ( bIsEndOfBlock && FCKBrowserInfo.IsGecko )
 473              {
 474                  var eLastBr = FCKDomTools.GetLastChild( eBr.parentNode, 'BR' ) ;
 475  
 476                  if ( eLastBr && eLastBr.getAttribute( 'type', 2 ) != '_moz' )
 477                      eBr.parentNode.appendChild( FCKTools.CreateBogusBR( this.Window.document ) ) ;
 478              }
 479  
 480              if ( FCKBrowserInfo.IsIE )
 481                  oRange.SetStart( eBr, 4 ) ;
 482              else
 483                  oRange.SetStart( eBr.nextSibling, 1 ) ;
 484  
 485          }
 486          
 487          // This collapse guarantees the cursor will be blinking.
 488          oRange.Collapse( true ) ;
 489  
 490          oRange.Select() ;
 491      }
 492  
 493      // Release the resources used by the range.
 494      oRange.Release() ;
 495      
 496      return true ;
 497  }
 498  
 499  // Transform a block without a block tag in a valid block (orphan text in the body or td, usually).
 500  FCKEnterKey.prototype._FixBlock = function( range, isStart, blockTag )
 501  {
 502      // Bookmark the range so we can restore it later.
 503      var oBookmark = range.CreateBookmark() ;
 504  
 505      // Collapse the range to the requested ending boundary.
 506      range.Collapse( isStart ) ;
 507  
 508      // Expands it to the block contents.
 509      range.Expand( 'block_contents' ) ;
 510  
 511      // Create the fixed block.
 512      var oFixedBlock = this.Window.document.createElement( blockTag ) ;
 513  
 514      // Move the contents of the temporary range to the fixed block.
 515      range.ExtractContents().AppendTo( oFixedBlock ) ;
 516      FCKDomTools.TrimNode( oFixedBlock ) ;
 517  
 518      // Insert the fixed block into the DOM.
 519      range.InsertNode( oFixedBlock ) ;
 520      
 521      // Move the range back to the bookmarked place.
 522      range.MoveToBookmark( oBookmark ) ;
 523  }


Généré le : Sun Feb 25 15:28:05 2007 par Balluche grâce à PHPXref 0.7