[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/libraries/ckeditor/_source/plugins/enterkey/ -> plugin.js (source)

   1  /*

   2  Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.

   3  For licensing, see LICENSE.html or http://ckeditor.com/license

   4  */
   5  
   6  (function()
   7  {
   8      CKEDITOR.plugins.add( 'enterkey',
   9      {
  10          requires : [ 'keystrokes', 'indent' ],
  11  
  12          init : function( editor )
  13          {
  14              var specialKeys = editor.specialKeys;
  15              specialKeys[ 13 ] = enter;
  16              specialKeys[ CKEDITOR.SHIFT + 13 ] = shiftEnter;
  17          }
  18      });
  19  
  20      CKEDITOR.plugins.enterkey =
  21      {
  22          enterBlock : function( editor, mode, range, forceMode )
  23          {
  24              // Get the range for the current selection.

  25              range = range || getRange( editor );
  26  
  27              // We may not have valid ranges to work on, like when inside a

  28              // contenteditable=false element.

  29              if ( !range )
  30                  return;
  31  
  32              var doc = range.document;
  33  
  34              // Exit the list when we're inside an empty list item block. (#5376)

  35              if ( range.checkStartOfBlock() && range.checkEndOfBlock() )
  36              {
  37                  var path = new CKEDITOR.dom.elementPath( range.startContainer ),
  38                          block = path.block;
  39  
  40                  if ( block && ( block.is( 'li' ) || block.getParent().is( 'li' ) ) )
  41                  {
  42                      editor.execCommand( 'outdent' );
  43                      return;
  44                  }
  45              }
  46  
  47              // Determine the block element to be used.

  48              var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
  49  
  50              // Split the range.

  51              var splitInfo = range.splitBlock( blockTag );
  52  
  53              if ( !splitInfo )
  54                  return;
  55  
  56              // Get the current blocks.

  57              var previousBlock    = splitInfo.previousBlock,
  58                  nextBlock        = splitInfo.nextBlock;
  59  
  60              var isStartOfBlock    = splitInfo.wasStartOfBlock,
  61                  isEndOfBlock    = splitInfo.wasEndOfBlock;
  62  
  63              var node;
  64  
  65              // If this is a block under a list item, split it as well. (#1647)

  66              if ( nextBlock )
  67              {
  68                  node = nextBlock.getParent();
  69                  if ( node.is( 'li' ) )
  70                  {
  71                      nextBlock.breakParent( node );
  72                      nextBlock.move( nextBlock.getNext(), true );
  73                  }
  74              }
  75              else if ( previousBlock && ( node = previousBlock.getParent() ) && node.is( 'li' ) )
  76              {
  77                  previousBlock.breakParent( node );
  78                  range.moveToElementEditStart( previousBlock.getNext() );
  79                  previousBlock.move( previousBlock.getPrevious() );
  80              }
  81  
  82              // If we have both the previous and next blocks, it means that the

  83              // boundaries were on separated blocks, or none of them where on the

  84              // block limits (start/end).

  85              if ( !isStartOfBlock && !isEndOfBlock )
  86              {
  87                  // If the next block is an <li> with another list tree as the first

  88                  // child, we'll need to append a filler (<br>/NBSP) or the list item

  89                  // wouldn't be editable. (#1420)

  90                  if ( nextBlock.is( 'li' )
  91                       && ( node = nextBlock.getFirst( CKEDITOR.dom.walker.invisible( true ) ) )
  92                       && node.is && node.is( 'ul', 'ol' ) )
  93                      ( CKEDITOR.env.ie ? doc.createText( '\xa0' ) : doc.createElement( 'br' ) ).insertBefore( node );
  94  
  95                  // Move the selection to the end block.

  96                  if ( nextBlock )
  97                      range.moveToElementEditStart( nextBlock );
  98              }
  99              else
 100              {
 101                  var newBlock;
 102  
 103                  if ( previousBlock )
 104                  {
 105                      // Do not enter this block if it's a header tag, or we are in

 106                      // a Shift+Enter (#77). Create a new block element instead

 107                      // (later in the code).

 108                      if ( previousBlock.is( 'li' ) || !headerTagRegex.test( previousBlock.getName() ) )
 109                      {
 110                          // Otherwise, duplicate the previous block.

 111                          newBlock = previousBlock.clone();
 112                      }
 113                  }
 114                  else if ( nextBlock )
 115                      newBlock = nextBlock.clone();
 116  
 117                  if ( !newBlock )
 118                      newBlock = doc.createElement( blockTag );
 119                  // Force the enter block unless we're talking of a list item.

 120                  else if ( forceMode && !newBlock.is( 'li' ) )
 121                      newBlock.renameNode( blockTag );
 122  
 123                  // Recreate the inline elements tree, which was available

 124                  // before hitting enter, so the same styles will be available in

 125                  // the new block.

 126                  var elementPath = splitInfo.elementPath;
 127                  if ( elementPath )
 128                  {
 129                      for ( var i = 0, len = elementPath.elements.length ; i < len ; i++ )
 130                      {
 131                          var element = elementPath.elements[ i ];
 132  
 133                          if ( element.equals( elementPath.block ) || element.equals( elementPath.blockLimit ) )
 134                              break;
 135  
 136                          if ( CKEDITOR.dtd.$removeEmpty[ element.getName() ] )
 137                          {
 138                              element = element.clone();
 139                              newBlock.moveChildren( element );
 140                              newBlock.append( element );
 141                          }
 142                      }
 143                  }
 144  
 145                  if ( !CKEDITOR.env.ie )
 146                      newBlock.appendBogus();
 147  
 148                  range.insertNode( newBlock );
 149  
 150                  // This is tricky, but to make the new block visible correctly

 151                  // we must select it.

 152                  // The previousBlock check has been included because it may be

 153                  // empty if we have fixed a block-less space (like ENTER into an

 154                  // empty table cell).

 155                  if ( CKEDITOR.env.ie && isStartOfBlock && ( !isEndOfBlock || !previousBlock.getChildCount() ) )
 156                  {
 157                      // Move the selection to the new block.

 158                      range.moveToElementEditStart( isEndOfBlock ? previousBlock : newBlock );
 159                      range.select();
 160                  }
 161  
 162                  // Move the selection to the new block.

 163                  range.moveToElementEditStart( isStartOfBlock && !isEndOfBlock ? nextBlock : newBlock );
 164          }
 165  
 166              if ( !CKEDITOR.env.ie )
 167              {
 168                  if ( nextBlock )
 169                  {
 170                      // If we have split the block, adds a temporary span at the

 171                      // range position and scroll relatively to it.

 172                      var tmpNode = doc.createElement( 'span' );
 173  
 174                      // We need some content for Safari.

 175                      tmpNode.setHtml( '&nbsp;' );
 176  
 177                      range.insertNode( tmpNode );
 178                      tmpNode.scrollIntoView();
 179                      range.deleteContents();
 180                  }
 181                  else
 182                  {
 183                      // We may use the above scroll logic for the new block case

 184                      // too, but it gives some weird result with Opera.

 185                      newBlock.scrollIntoView();
 186                  }
 187              }
 188  
 189              range.select();
 190          },
 191  
 192          enterBr : function( editor, mode, range, forceMode )
 193          {
 194              // Get the range for the current selection.

 195              range = range || getRange( editor );
 196  
 197              // We may not have valid ranges to work on, like when inside a

 198              // contenteditable=false element.

 199              if ( !range )
 200                  return;
 201  
 202              var doc = range.document;
 203  
 204              // Determine the block element to be used.

 205              var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
 206  
 207              var isEndOfBlock = range.checkEndOfBlock();
 208  
 209              var elementPath = new CKEDITOR.dom.elementPath( editor.getSelection().getStartElement() );
 210  
 211              var startBlock = elementPath.block,
 212                  startBlockTag = startBlock && elementPath.block.getName();
 213  
 214              var isPre = false;
 215  
 216              if ( !forceMode && startBlockTag == 'li' )
 217              {
 218                  enterBlock( editor, mode, range, forceMode );
 219                  return;
 220              }
 221  
 222              // If we are at the end of a header block.

 223              if ( !forceMode && isEndOfBlock && headerTagRegex.test( startBlockTag ) )
 224              {
 225                  // Insert a <br> after the current paragraph.

 226                  doc.createElement( 'br' ).insertAfter( startBlock );
 227  
 228                  // A text node is required by Gecko only to make the cursor blink.

 229                  if ( CKEDITOR.env.gecko )
 230                      doc.createText( '' ).insertAfter( startBlock );
 231  
 232                  // IE has different behaviors regarding position.

 233                  range.setStartAt( startBlock.getNext(), CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_START );
 234              }
 235              else
 236              {
 237                  var lineBreak;
 238  
 239                  isPre = ( startBlockTag == 'pre' );
 240  
 241                  // Gecko prefers <br> as line-break inside <pre> (#4711).

 242                  if ( isPre && !CKEDITOR.env.gecko )
 243                      lineBreak = doc.createText( CKEDITOR.env.ie ? '\r' : '\n' );
 244                  else
 245                      lineBreak = doc.createElement( 'br' );
 246  
 247                  range.deleteContents();
 248                  range.insertNode( lineBreak );
 249  
 250                  // A text node is required by Gecko only to make the cursor blink.

 251                  // We need some text inside of it, so the bogus <br> is properly

 252                  // created.

 253                  if ( !CKEDITOR.env.ie )
 254                      doc.createText( '\ufeff' ).insertAfter( lineBreak );
 255  
 256                  // If we are at the end of a block, we must be sure the bogus node is available in that block.

 257                  if ( isEndOfBlock && !CKEDITOR.env.ie )
 258                      lineBreak.getParent().appendBogus();
 259  
 260                  // Now we can remove the text node contents, so the caret doesn't

 261                  // stop on it.

 262                  if ( !CKEDITOR.env.ie )
 263                      lineBreak.getNext().$.nodeValue = '';
 264                  // IE has different behavior regarding position.

 265                  if ( CKEDITOR.env.ie )
 266                      range.setStartAt( lineBreak, CKEDITOR.POSITION_AFTER_END );
 267                  else
 268                      range.setStartAt( lineBreak.getNext(), CKEDITOR.POSITION_AFTER_START );
 269  
 270                  // Scroll into view, for non IE.

 271                  if ( !CKEDITOR.env.ie )
 272                  {
 273                      var dummy = null;
 274  
 275                      // BR is not positioned in Opera and Webkit.

 276                      if ( !CKEDITOR.env.gecko )
 277                      {
 278                          dummy = doc.createElement( 'span' );
 279                          // We need have some contents for Webkit to position it

 280                          // under parent node. ( #3681)

 281                          dummy.setHtml('&nbsp;');
 282                      }
 283                      else
 284                          dummy = doc.createElement( 'br' );
 285  
 286                      dummy.insertBefore( lineBreak.getNext() );
 287                      dummy.scrollIntoView();
 288                      dummy.remove();
 289                  }
 290              }
 291  
 292              // This collapse guarantees the cursor will be blinking.

 293              range.collapse( true );
 294  
 295              range.select( isPre );
 296          }
 297      };
 298  
 299      var plugin = CKEDITOR.plugins.enterkey,
 300          enterBr = plugin.enterBr,
 301          enterBlock = plugin.enterBlock,
 302          headerTagRegex = /^h[1-6]$/;
 303  
 304  	function shiftEnter( editor )
 305      {
 306          // Only effective within document.

 307          if ( editor.mode != 'wysiwyg' )
 308              return false;
 309  
 310          // On SHIFT+ENTER:

 311          // 1. We want to enforce the mode to be respected, instead

 312          // of cloning the current block. (#77)

 313          // 2. Always perform a block break when inside <pre> (#5402).

 314          if ( editor.getSelection().getStartElement().hasAscendant( 'pre', true ) )
 315          {
 316              setTimeout( function() { enterBlock( editor, editor.config.enterMode, null, true ); }, 0 );
 317              return true;
 318          }
 319          else
 320              return enter( editor, editor.config.shiftEnterMode, true );
 321      }
 322  
 323  	function enter( editor, mode, forceMode )
 324      {
 325          forceMode = editor.config.forceEnterMode || forceMode;
 326  
 327          // Only effective within document.

 328          if ( editor.mode != 'wysiwyg' )
 329              return false;
 330  
 331          if ( !mode )
 332              mode = editor.config.enterMode;
 333  
 334          // Use setTimout so the keys get cancelled immediatelly.

 335          setTimeout( function()
 336              {
 337                  editor.fire( 'saveSnapshot' );    // Save undo step.

 338                  if ( mode == CKEDITOR.ENTER_BR || editor.getSelection().getStartElement().hasAscendant( 'pre', true ) )
 339                      enterBr( editor, mode, null, forceMode );
 340                  else
 341                      enterBlock( editor, mode, null, forceMode );
 342  
 343              }, 0 );
 344  
 345          return true;
 346      }
 347  
 348  
 349  	function getRange( editor )
 350      {
 351          // Get the selection ranges.

 352          var ranges = editor.getSelection().getRanges( true );
 353  
 354          // Delete the contents of all ranges except the first one.

 355          for ( var i = ranges.length - 1 ; i > 0 ; i-- )
 356          {
 357              ranges[ i ].deleteContents();
 358          }
 359  
 360          // Return the first range.

 361          return ranges[ 0 ];
 362      }
 363  })();


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7