[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/libraries/ckeditor/_source/plugins/tabletools/ -> 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  	function removeRawAttribute( $node, attr )
   9      {
  10          if ( CKEDITOR.env.ie )
  11              $node.removeAttribute( attr );
  12          else
  13              delete $node[ attr ];
  14      }
  15  
  16      var cellNodeRegex = /^(?:td|th)$/;
  17  
  18  	function getSelectedCells( selection )
  19      {
  20          // Walker will try to split text nodes, which will make the current selection

  21          // invalid. So save bookmarks before doing anything.

  22          var bookmarks = selection.createBookmarks();
  23  
  24          var ranges = selection.getRanges();
  25          var retval = [];
  26          var database = {};
  27  
  28  		function moveOutOfCellGuard( node )
  29          {
  30              // Apply to the first cell only.

  31              if ( retval.length > 0 )
  32                  return;
  33  
  34              // If we are exiting from the first </td>, then the td should definitely be

  35              // included.

  36              if ( node.type == CKEDITOR.NODE_ELEMENT && cellNodeRegex.test( node.getName() )
  37                      && !node.getCustomData( 'selected_cell' ) )
  38              {
  39                  CKEDITOR.dom.element.setMarker( database, node, 'selected_cell', true );
  40                  retval.push( node );
  41              }
  42          }
  43  
  44          for ( var i = 0 ; i < ranges.length ; i++ )
  45          {
  46              var range = ranges[ i ];
  47  
  48              if ( range.collapsed )
  49              {
  50                  // Walker does not handle collapsed ranges yet - fall back to old API.

  51                  var startNode = range.getCommonAncestor();
  52                  var nearestCell = startNode.getAscendant( 'td', true ) || startNode.getAscendant( 'th', true );
  53                  if ( nearestCell )
  54                      retval.push( nearestCell );
  55              }
  56              else
  57              {
  58                  var walker = new CKEDITOR.dom.walker( range );
  59                  var node;
  60                  walker.guard = moveOutOfCellGuard;
  61  
  62                  while ( ( node = walker.next() ) )
  63                  {
  64                      // If may be possible for us to have a range like this:

  65                      // <td>^1</td><td>^2</td>

  66                      // The 2nd td shouldn't be included.

  67                      //

  68                      // So we have to take care to include a td we've entered only when we've

  69                      // walked into its children.

  70  
  71                      var parent = node.getParent();
  72                      if ( parent && cellNodeRegex.test( parent.getName() ) && !parent.getCustomData( 'selected_cell' ) )
  73                      {
  74                          CKEDITOR.dom.element.setMarker( database, parent, 'selected_cell', true );
  75                          retval.push( parent );
  76                      }
  77                  }
  78              }
  79          }
  80  
  81          CKEDITOR.dom.element.clearAllMarkers( database );
  82  
  83          // Restore selection position.

  84          selection.selectBookmarks( bookmarks );
  85  
  86          return retval;
  87      }
  88  
  89  	function getFocusElementAfterDelCells( cellsToDelete ) {
  90          var i = 0,
  91              last = cellsToDelete.length - 1,
  92              database = {},
  93              cell,focusedCell,
  94              tr;
  95  
  96          while ( ( cell = cellsToDelete[ i++ ] ) )
  97              CKEDITOR.dom.element.setMarker( database, cell, 'delete_cell', true );
  98  
  99          // 1.first we check left or right side focusable cell row by row;

 100          i = 0;
 101          while ( ( cell = cellsToDelete[ i++ ] ) )
 102          {
 103              if ( ( focusedCell = cell.getPrevious() ) && !focusedCell.getCustomData( 'delete_cell' )
 104                || ( focusedCell = cell.getNext()     ) && !focusedCell.getCustomData( 'delete_cell' ) )
 105              {
 106                  CKEDITOR.dom.element.clearAllMarkers( database );
 107                  return focusedCell;
 108              }
 109          }
 110  
 111          CKEDITOR.dom.element.clearAllMarkers( database );
 112  
 113          // 2. then we check the toppest row (outside the selection area square) focusable cell

 114          tr = cellsToDelete[ 0 ].getParent();
 115          if ( ( tr = tr.getPrevious() ) )
 116              return tr.getLast();
 117  
 118          // 3. last we check the lowerest  row focusable cell

 119          tr = cellsToDelete[ last ].getParent();
 120          if ( ( tr = tr.getNext() ) )
 121              return tr.getChild( 0 );
 122  
 123          return null;
 124      }
 125  
 126  	function clearRow( $tr )
 127      {
 128          // Get the array of row's cells.

 129          var $cells = $tr.cells;
 130  
 131          // Empty all cells.

 132          for ( var i = 0 ; i < $cells.length ; i++ )
 133          {
 134              $cells[ i ].innerHTML = '';
 135  
 136              if ( !CKEDITOR.env.ie )
 137                  ( new CKEDITOR.dom.element( $cells[ i ] ) ).appendBogus();
 138          }
 139      }
 140  
 141  	function insertRow( selection, insertBefore )
 142      {
 143          // Get the row where the selection is placed in.

 144          var row = selection.getStartElement().getAscendant( 'tr' );
 145          if ( !row )
 146              return;
 147  
 148          // Create a clone of the row.

 149          var newRow = row.clone( true );
 150  
 151          // Insert the new row before of it.

 152          newRow.insertBefore( row );
 153  
 154          // Clean one of the rows to produce the illusion of inserting an empty row

 155          // before or after.

 156          clearRow( insertBefore ? newRow.$ : row.$ );
 157      }
 158  
 159  	function deleteRows( selectionOrRow )
 160      {
 161          if ( selectionOrRow instanceof CKEDITOR.dom.selection )
 162          {
 163              var cells = getSelectedCells( selectionOrRow ),
 164                  cellsCount = cells.length,
 165                  rowsToDelete = [],
 166                  cursorPosition,
 167                  previousRowIndex,
 168                  nextRowIndex;
 169  
 170              // Queue up the rows - it's possible and likely that we have duplicates.

 171              for ( var i = 0 ; i < cellsCount ; i++ )
 172              {
 173                  var row = cells[ i ].getParent(),
 174                          rowIndex = row.$.rowIndex;
 175  
 176                  !i && ( previousRowIndex = rowIndex - 1 );
 177                  rowsToDelete[ rowIndex ] = row;
 178                  i == cellsCount - 1 && ( nextRowIndex = rowIndex + 1 );
 179              }
 180  
 181              var table = row.getAscendant( 'table' ),
 182                      rows =  table.$.rows,
 183                      rowCount = rows.length;
 184  
 185              // Where to put the cursor after rows been deleted?

 186              // 1. Into next sibling row if any;

 187              // 2. Into previous sibling row if any;

 188              // 3. Into table's parent element if it's the very last row.

 189              cursorPosition = new CKEDITOR.dom.element(
 190                  nextRowIndex < rowCount && table.$.rows[ nextRowIndex ] ||
 191                  previousRowIndex > 0 && table.$.rows[ previousRowIndex ] ||
 192                  table.$.parentNode );
 193  
 194              for ( i = rowsToDelete.length ; i >= 0 ; i-- )
 195              {
 196                  if ( rowsToDelete[ i ] )
 197                      deleteRows( rowsToDelete[ i ] );
 198              }
 199  
 200              return cursorPosition;
 201          }
 202          else if ( selectionOrRow instanceof CKEDITOR.dom.element )
 203          {
 204              table = selectionOrRow.getAscendant( 'table' );
 205  
 206              if ( table.$.rows.length == 1 )
 207                  table.remove();
 208              else
 209                  selectionOrRow.remove();
 210          }
 211  
 212          return 0;
 213      }
 214  
 215  	function insertColumn( selection, insertBefore )
 216      {
 217          // Get the cell where the selection is placed in.

 218          var startElement = selection.getStartElement();
 219          var cell = startElement.getAscendant( 'td', true ) || startElement.getAscendant( 'th', true );
 220  
 221          if ( !cell )
 222              return;
 223  
 224          // Get the cell's table.

 225          var table = cell.getAscendant( 'table' );
 226          var cellIndex = cell.$.cellIndex;
 227  
 228          // Loop through all rows available in the table.

 229          for ( var i = 0 ; i < table.$.rows.length ; i++ )
 230          {
 231              var $row = table.$.rows[ i ];
 232  
 233              // If the row doesn't have enough cells, ignore it.

 234              if ( $row.cells.length < ( cellIndex + 1 ) )
 235                  continue;
 236  
 237              cell = ( new CKEDITOR.dom.element( $row.cells[ cellIndex ] ) ).clone( false );
 238  
 239              if ( !CKEDITOR.env.ie )
 240                  cell.appendBogus();
 241  
 242              // Get back the currently selected cell.

 243              var baseCell = new CKEDITOR.dom.element( $row.cells[ cellIndex ] );
 244              if ( insertBefore )
 245                  cell.insertBefore( baseCell );
 246              else
 247                  cell.insertAfter( baseCell );
 248          }
 249      }
 250  
 251  	function getFocusElementAfterDelCols( cells )
 252      {
 253          var cellIndexList = [],
 254              table = cells[ 0 ] && cells[ 0 ].getAscendant( 'table' ),
 255              i, length,
 256              targetIndex, targetCell;
 257  
 258          // get the cellIndex list of delete cells

 259          for ( i = 0, length = cells.length; i < length; i++ )
 260              cellIndexList.push( cells[i].$.cellIndex );
 261  
 262          // get the focusable column index

 263          cellIndexList.sort();
 264          for ( i = 1, length = cellIndexList.length; i < length; i++ )
 265          {
 266              if ( cellIndexList[ i ] - cellIndexList[ i - 1 ] > 1 )
 267              {
 268                  targetIndex = cellIndexList[ i - 1 ] + 1;
 269                  break;
 270              }
 271          }
 272  
 273          if ( !targetIndex )
 274              targetIndex = cellIndexList[ 0 ] > 0 ? ( cellIndexList[ 0 ] - 1 )
 275                              : ( cellIndexList[ cellIndexList.length - 1 ] + 1 );
 276  
 277          // scan row by row to get the target cell

 278          var rows = table.$.rows;
 279          for ( i = 0, length = rows.length; i < length ; i++ )
 280          {
 281              targetCell = rows[ i ].cells[ targetIndex ];
 282              if ( targetCell )
 283                  break;
 284          }
 285  
 286          return targetCell ?  new CKEDITOR.dom.element( targetCell ) :  table.getPrevious();
 287      }
 288  
 289  	function deleteColumns( selectionOrCell )
 290      {
 291          if ( selectionOrCell instanceof CKEDITOR.dom.selection )
 292          {
 293              var colsToDelete = getSelectedCells( selectionOrCell ),
 294                  elementToFocus = getFocusElementAfterDelCols( colsToDelete );
 295  
 296              for ( var i = colsToDelete.length - 1 ; i >= 0 ; i-- )
 297              {
 298                  if ( colsToDelete[ i ] )
 299                      deleteColumns( colsToDelete[ i ] );
 300              }
 301  
 302              return elementToFocus;
 303          }
 304          else if ( selectionOrCell instanceof CKEDITOR.dom.element )
 305          {
 306              // Get the cell's table.

 307              var table = selectionOrCell.getAscendant( 'table' );
 308              if ( !table )
 309                  return null;
 310  
 311              // Get the cell index.

 312              var cellIndex = selectionOrCell.$.cellIndex;
 313  
 314              /*

 315               * Loop through all rows from down to up, coz it's possible that some rows

 316               * will be deleted.

 317               */
 318              for ( i = table.$.rows.length - 1 ; i >= 0 ; i-- )
 319              {
 320                  // Get the row.

 321                  var row = new CKEDITOR.dom.element( table.$.rows[ i ] );
 322  
 323                  // If the cell to be removed is the first one and the row has just one cell.

 324                  if ( !cellIndex && row.$.cells.length == 1 )
 325                  {
 326                      deleteRows( row );
 327                      continue;
 328                  }
 329  
 330                  // Else, just delete the cell.

 331                  if ( row.$.cells[ cellIndex ] )
 332                      row.$.removeChild( row.$.cells[ cellIndex ] );
 333              }
 334          }
 335  
 336          return null;
 337      }
 338  
 339  	function insertCell( selection, insertBefore )
 340      {
 341          var startElement = selection.getStartElement();
 342          var cell = startElement.getAscendant( 'td', true ) || startElement.getAscendant( 'th', true );
 343  
 344          if ( !cell )
 345              return;
 346  
 347          // Create the new cell element to be added.

 348          var newCell = cell.clone();
 349          if ( !CKEDITOR.env.ie )
 350              newCell.appendBogus();
 351  
 352          if ( insertBefore )
 353              newCell.insertBefore( cell );
 354          else
 355              newCell.insertAfter( cell );
 356      }
 357  
 358  	function deleteCells( selectionOrCell )
 359      {
 360          if ( selectionOrCell instanceof CKEDITOR.dom.selection )
 361          {
 362              var cellsToDelete = getSelectedCells( selectionOrCell );
 363              var table = cellsToDelete[ 0 ] && cellsToDelete[ 0 ].getAscendant( 'table' );
 364              var cellToFocus   = getFocusElementAfterDelCells( cellsToDelete );
 365  
 366              for ( var i = cellsToDelete.length - 1 ; i >= 0 ; i-- )
 367                  deleteCells( cellsToDelete[ i ] );
 368  
 369              if ( cellToFocus )
 370                  placeCursorInCell( cellToFocus, true );
 371              else if ( table )
 372                  table.remove();
 373          }
 374          else if ( selectionOrCell instanceof CKEDITOR.dom.element )
 375          {
 376              var tr = selectionOrCell.getParent();
 377              if ( tr.getChildCount() == 1 )
 378                  tr.remove();
 379              else
 380                  selectionOrCell.remove();
 381          }
 382      }
 383  
 384      // Remove filler at end and empty spaces around the cell content.

 385  	function trimCell( cell )
 386      {
 387          var bogus = cell.getBogus();
 388          bogus && bogus.remove();
 389          cell.trim();
 390      }
 391  
 392  	function placeCursorInCell( cell, placeAtEnd )
 393      {
 394          var range = new CKEDITOR.dom.range( cell.getDocument() );
 395          if ( !range[ 'moveToElementEdit' + ( placeAtEnd ? 'End' : 'Start' ) ]( cell ) )
 396          {
 397              range.selectNodeContents( cell );
 398              range.collapse( placeAtEnd ? false : true );
 399          }
 400          range.select( true );
 401      }
 402  
 403  	function cellInRow( tableMap, rowIndex, cell )
 404      {
 405          var oRow = tableMap[ rowIndex ];
 406          if ( typeof cell == 'undefined' )
 407              return oRow;
 408  
 409          for ( var c = 0 ; oRow && c < oRow.length ; c++ )
 410          {
 411              if ( cell.is && oRow[c] == cell.$ )
 412                  return c;
 413              else if ( c == cell )
 414                  return new CKEDITOR.dom.element( oRow[ c ] );
 415          }
 416          return cell.is ? -1 : null;
 417      }
 418  
 419  	function cellInCol( tableMap, colIndex, cell )
 420      {
 421          var oCol = [];
 422          for ( var r = 0; r < tableMap.length; r++ )
 423          {
 424              var row = tableMap[ r ];
 425              if ( typeof cell == 'undefined' )
 426                  oCol.push( row[ colIndex ] );
 427              else if ( cell.is && row[ colIndex ] == cell.$ )
 428                  return r;
 429              else if ( r == cell )
 430                  return new CKEDITOR.dom.element( row[ colIndex ] );
 431          }
 432  
 433          return ( typeof cell == 'undefined' )? oCol : cell.is ? -1 :  null;
 434      }
 435  
 436  	function mergeCells( selection, mergeDirection, isDetect )
 437      {
 438          var cells = getSelectedCells( selection );
 439  
 440          // Invalid merge request if:

 441          // 1. In batch mode despite that less than two selected.

 442          // 2. In solo mode while not exactly only one selected.

 443          // 3. Cells distributed in different table groups (e.g. from both thead and tbody).

 444          var commonAncestor;
 445          if ( ( mergeDirection ? cells.length != 1 : cells.length < 2 )
 446                  || ( commonAncestor = selection.getCommonAncestor() )
 447                  && commonAncestor.type == CKEDITOR.NODE_ELEMENT
 448                  && commonAncestor.is( 'table' ) )
 449          {
 450              return false;
 451          }
 452  
 453          var    cell,
 454              firstCell = cells[ 0 ],
 455              table = firstCell.getAscendant( 'table' ),
 456              map = CKEDITOR.tools.buildTableMap( table ),
 457              mapHeight = map.length,
 458              mapWidth = map[ 0 ].length,
 459              startRow = firstCell.getParent().$.rowIndex,
 460              startColumn = cellInRow( map, startRow, firstCell );
 461  
 462          if ( mergeDirection )
 463          {
 464              var targetCell;
 465              try
 466              {
 467                  targetCell =
 468                      map[ mergeDirection == 'up' ?
 469                              ( startRow - 1 ):
 470                              mergeDirection == 'down' ? ( startRow + 1 ) : startRow  ] [
 471                           mergeDirection == 'left' ?
 472                              ( startColumn - 1 ):
 473                           mergeDirection == 'right' ?  ( startColumn + 1 ) : startColumn ];
 474  
 475              }
 476              catch( er )
 477              {
 478                  return false;
 479              }
 480  
 481              // 1. No cell could be merged.

 482              // 2. Same cell actually.

 483              if ( !targetCell || firstCell.$ == targetCell  )
 484                  return false;
 485  
 486              // Sort in map order regardless of the DOM sequence.

 487              cells[ ( mergeDirection == 'up' || mergeDirection == 'left' ) ?
 488                       'unshift' : 'push' ]( new CKEDITOR.dom.element( targetCell ) );
 489          }
 490  
 491          // Start from here are merging way ignorance (merge up/right, batch merge).

 492          var    doc = firstCell.getDocument(),
 493              lastRowIndex = startRow,
 494              totalRowSpan = 0,
 495              totalColSpan = 0,
 496              // Use a documentFragment as buffer when appending cell contents.

 497              frag = !isDetect && new CKEDITOR.dom.documentFragment( doc ),
 498              dimension = 0;
 499  
 500          for ( var i = 0; i < cells.length; i++ )
 501          {
 502              cell = cells[ i ];
 503  
 504              var tr = cell.getParent(),
 505                  cellFirstChild = cell.getFirst(),
 506                  colSpan = cell.$.colSpan,
 507                  rowSpan = cell.$.rowSpan,
 508                  rowIndex = tr.$.rowIndex,
 509                  colIndex = cellInRow( map, rowIndex, cell );
 510  
 511              // Accumulated the actual places taken by all selected cells.

 512              dimension += colSpan * rowSpan;
 513              // Accumulated the maximum virtual spans from column and row.

 514              totalColSpan = Math.max( totalColSpan, colIndex - startColumn + colSpan ) ;
 515              totalRowSpan = Math.max( totalRowSpan, rowIndex - startRow + rowSpan );
 516  
 517              if ( !isDetect )
 518              {
 519                  // Trim all cell fillers and check to remove empty cells.

 520                  if ( trimCell( cell ), cell.getChildren().count() )
 521                  {
 522                      // Merge vertically cells as two separated paragraphs.

 523                      if ( rowIndex != lastRowIndex
 524                          && cellFirstChild
 525                          && !( cellFirstChild.isBlockBoundary
 526                                && cellFirstChild.isBlockBoundary( { br : 1 } ) ) )
 527                      {
 528                          var last = frag.getLast( CKEDITOR.dom.walker.whitespaces( true ) );
 529                          if ( last && !( last.is && last.is( 'br' ) ) )
 530                              frag.append( new CKEDITOR.dom.element( 'br' ) );
 531                      }
 532  
 533                      cell.moveChildren( frag );
 534                  }
 535                  i ? cell.remove() : cell.setHtml( '' );
 536              }
 537              lastRowIndex = rowIndex;
 538          }
 539  
 540          if ( !isDetect )
 541          {
 542              frag.moveChildren( firstCell );
 543  
 544              if ( !CKEDITOR.env.ie )
 545                  firstCell.appendBogus();
 546  
 547              if ( totalColSpan >= mapWidth )
 548                  firstCell.removeAttribute( 'rowSpan' );
 549              else
 550                  firstCell.$.rowSpan = totalRowSpan;
 551  
 552              if ( totalRowSpan >= mapHeight )
 553                  firstCell.removeAttribute( 'colSpan' );
 554              else
 555                  firstCell.$.colSpan = totalColSpan;
 556  
 557              // Swip empty <tr> left at the end of table due to the merging.

 558              var trs = new CKEDITOR.dom.nodeList( table.$.rows ),
 559                  count = trs.count();
 560  
 561              for ( i = count - 1; i >= 0; i-- )
 562              {
 563                  var tailTr = trs.getItem( i );
 564                  if ( !tailTr.$.cells.length )
 565                  {
 566                      tailTr.remove();
 567                      count++;
 568                      continue;
 569                  }
 570              }
 571  
 572              return firstCell;
 573          }
 574          // Be able to merge cells only if actual dimension of selected

 575          // cells equals to the caculated rectangle.

 576          else
 577              return ( totalRowSpan * totalColSpan ) == dimension;
 578      }
 579  
 580  	function verticalSplitCell ( selection, isDetect )
 581      {
 582          var cells = getSelectedCells( selection );
 583          if ( cells.length > 1 )
 584              return false;
 585          else if ( isDetect )
 586              return true;
 587  
 588          var cell = cells[ 0 ],
 589              tr = cell.getParent(),
 590              table = tr.getAscendant( 'table' ),
 591              map = CKEDITOR.tools.buildTableMap( table ),
 592              rowIndex = tr.$.rowIndex,
 593              colIndex = cellInRow( map, rowIndex, cell ),
 594              rowSpan = cell.$.rowSpan,
 595              newCell,
 596              newRowSpan,
 597              newCellRowSpan,
 598              newRowIndex;
 599  
 600          if ( rowSpan > 1 )
 601          {
 602              newRowSpan = Math.ceil( rowSpan / 2 );
 603              newCellRowSpan = Math.floor( rowSpan / 2 );
 604              newRowIndex = rowIndex + newRowSpan;
 605              var newCellTr = new CKEDITOR.dom.element( table.$.rows[ newRowIndex ] ),
 606                  newCellRow = cellInRow( map, newRowIndex ),
 607                  candidateCell;
 608  
 609              newCell = cell.clone();
 610  
 611              // Figure out where to insert the new cell by checking the vitual row.

 612              for ( var c = 0; c < newCellRow.length; c++ )
 613              {
 614                  candidateCell = newCellRow[ c ];
 615                  // Catch first cell actually following the column.

 616                  if ( candidateCell.parentNode == newCellTr.$
 617                      && c > colIndex )
 618                  {
 619                      newCell.insertBefore( new CKEDITOR.dom.element( candidateCell ) );
 620                      break;
 621                  }
 622                  else
 623                      candidateCell = null;
 624              }
 625  
 626              // The destination row is empty, append at will.

 627              if ( !candidateCell )
 628                  newCellTr.append( newCell, true );
 629          }
 630          else
 631          {
 632              newCellRowSpan = newRowSpan = 1;
 633  
 634              newCellTr = tr.clone();
 635              newCellTr.insertAfter( tr );
 636              newCellTr.append( newCell = cell.clone() );
 637  
 638              var cellsInSameRow = cellInRow( map, rowIndex );
 639              for ( var i = 0; i < cellsInSameRow.length; i++ )
 640                  cellsInSameRow[ i ].rowSpan++;
 641          }
 642  
 643          if ( !CKEDITOR.env.ie )
 644              newCell.appendBogus();
 645  
 646          cell.$.rowSpan = newRowSpan;
 647          newCell.$.rowSpan = newCellRowSpan;
 648          if ( newRowSpan == 1 )
 649              cell.removeAttribute( 'rowSpan' );
 650          if ( newCellRowSpan == 1 )
 651              newCell.removeAttribute( 'rowSpan' );
 652  
 653          return newCell;
 654      }
 655  
 656  	function horizontalSplitCell( selection, isDetect )
 657      {
 658          var cells = getSelectedCells( selection );
 659          if ( cells.length > 1 )
 660              return false;
 661          else if ( isDetect )
 662              return true;
 663  
 664          var cell = cells[ 0 ],
 665              tr = cell.getParent(),
 666              table = tr.getAscendant( 'table' ),
 667              map = CKEDITOR.tools.buildTableMap( table ),
 668              rowIndex = tr.$.rowIndex,
 669              colIndex = cellInRow( map, rowIndex, cell ),
 670              colSpan = cell.$.colSpan,
 671              newCell,
 672              newColSpan,
 673              newCellColSpan;
 674  
 675          if ( colSpan > 1 )
 676          {
 677              newColSpan = Math.ceil( colSpan / 2 );
 678              newCellColSpan = Math.floor( colSpan / 2 );
 679          }
 680          else
 681          {
 682              newCellColSpan = newColSpan = 1;
 683              var cellsInSameCol = cellInCol( map, colIndex );
 684              for ( var i = 0; i < cellsInSameCol.length; i++ )
 685                  cellsInSameCol[ i ].colSpan++;
 686          }
 687          newCell = cell.clone();
 688          newCell.insertAfter( cell );
 689          if ( !CKEDITOR.env.ie )
 690              newCell.appendBogus();
 691  
 692          cell.$.colSpan = newColSpan;
 693          newCell.$.colSpan = newCellColSpan;
 694          if ( newColSpan == 1 )
 695              cell.removeAttribute( 'colSpan' );
 696          if ( newCellColSpan == 1 )
 697              newCell.removeAttribute( 'colSpan' );
 698  
 699          return newCell;
 700      }
 701      // Context menu on table caption incorrect (#3834)

 702      var contextMenuTags = { thead : 1, tbody : 1, tfoot : 1, td : 1, tr : 1, th : 1 };
 703  
 704      CKEDITOR.plugins.tabletools =
 705      {
 706          init : function( editor )
 707          {
 708              var lang = editor.lang.table;
 709  
 710              editor.addCommand( 'cellProperties', new CKEDITOR.dialogCommand( 'cellProperties' ) );
 711              CKEDITOR.dialog.add( 'cellProperties', this.path + 'dialogs/tableCell.js' );
 712  
 713              editor.addCommand( 'tableDelete',
 714                  {
 715                      exec : function( editor )
 716                      {
 717                          var selection = editor.getSelection();
 718                          var startElement = selection && selection.getStartElement();
 719                          var table = startElement && startElement.getAscendant( 'table', true );
 720  
 721                          if ( !table )
 722                              return;
 723  
 724                          // Maintain the selection point at where the table was deleted.

 725                          selection.selectElement( table );
 726                          var range = selection.getRanges()[0];
 727                          range.collapse();
 728                          selection.selectRanges( [ range ] );
 729  
 730                          // If the table's parent has only one child, remove it,except body,as well.( #5416 )

 731                          var parent = table.getParent();
 732                          if ( parent.getChildCount() == 1 && parent.getName() != 'body' )
 733                              parent.remove();
 734                          else
 735                              table.remove();
 736                      }
 737                  } );
 738  
 739              editor.addCommand( 'rowDelete',
 740                  {
 741                      exec : function( editor )
 742                      {
 743                          var selection = editor.getSelection();
 744                          placeCursorInCell( deleteRows( selection ) );
 745                      }
 746                  } );
 747  
 748              editor.addCommand( 'rowInsertBefore',
 749                  {
 750                      exec : function( editor )
 751                      {
 752                          var selection = editor.getSelection();
 753                          insertRow( selection, true );
 754                      }
 755                  } );
 756  
 757              editor.addCommand( 'rowInsertAfter',
 758                  {
 759                      exec : function( editor )
 760                      {
 761                          var selection = editor.getSelection();
 762                          insertRow( selection );
 763                      }
 764                  } );
 765  
 766              editor.addCommand( 'columnDelete',
 767                  {
 768                      exec : function( editor )
 769                      {
 770                          var selection = editor.getSelection();
 771                          var element = deleteColumns( selection );
 772                          element &&  placeCursorInCell( element, true );
 773                      }
 774                  } );
 775  
 776              editor.addCommand( 'columnInsertBefore',
 777                  {
 778                      exec : function( editor )
 779                      {
 780                          var selection = editor.getSelection();
 781                          insertColumn( selection, true );
 782                      }
 783                  } );
 784  
 785              editor.addCommand( 'columnInsertAfter',
 786                  {
 787                      exec : function( editor )
 788                      {
 789                          var selection = editor.getSelection();
 790                          insertColumn( selection );
 791                      }
 792                  } );
 793  
 794              editor.addCommand( 'cellDelete',
 795                  {
 796                      exec : function( editor )
 797                      {
 798                          var selection = editor.getSelection();
 799                          deleteCells( selection );
 800                      }
 801                  } );
 802  
 803              editor.addCommand( 'cellMerge',
 804                  {
 805                      exec : function( editor )
 806                      {
 807                          placeCursorInCell( mergeCells( editor.getSelection() ), true );
 808                      }
 809                  } );
 810  
 811              editor.addCommand( 'cellMergeRight',
 812                  {
 813                      exec : function( editor )
 814                      {
 815                          placeCursorInCell( mergeCells( editor.getSelection(), 'right' ), true );
 816                      }
 817                  } );
 818  
 819              editor.addCommand( 'cellMergeDown',
 820                  {
 821                      exec : function( editor )
 822                      {
 823                          placeCursorInCell( mergeCells( editor.getSelection(), 'down' ), true );
 824                      }
 825                  } );
 826  
 827              editor.addCommand( 'cellVerticalSplit',
 828                  {
 829                      exec : function( editor )
 830                      {
 831                          placeCursorInCell( verticalSplitCell( editor.getSelection() ) );
 832                      }
 833                  } );
 834  
 835              editor.addCommand( 'cellHorizontalSplit',
 836                  {
 837                      exec : function( editor )
 838                      {
 839                          placeCursorInCell( horizontalSplitCell( editor.getSelection() ) );
 840                      }
 841                  } );
 842  
 843              editor.addCommand( 'cellInsertBefore',
 844                  {
 845                      exec : function( editor )
 846                      {
 847                          var selection = editor.getSelection();
 848                          insertCell( selection, true );
 849                      }
 850                  } );
 851  
 852              editor.addCommand( 'cellInsertAfter',
 853                  {
 854                      exec : function( editor )
 855                      {
 856                          var selection = editor.getSelection();
 857                          insertCell( selection );
 858                      }
 859                  } );
 860  
 861              // If the "menu" plugin is loaded, register the menu items.

 862              if ( editor.addMenuItems )
 863              {
 864                  editor.addMenuItems(
 865                      {
 866                          tablecell :
 867                          {
 868                              label : lang.cell.menu,
 869                              group : 'tablecell',
 870                              order : 1,
 871                              getItems : function()
 872                              {
 873                                  var selection = editor.getSelection(),
 874                                      cells = getSelectedCells( selection );
 875                                  return {
 876                                      tablecell_insertBefore : CKEDITOR.TRISTATE_OFF,
 877                                      tablecell_insertAfter : CKEDITOR.TRISTATE_OFF,
 878                                      tablecell_delete : CKEDITOR.TRISTATE_OFF,
 879                                      tablecell_merge : mergeCells( selection, null, true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
 880                                      tablecell_merge_right : mergeCells( selection, 'right', true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
 881                                      tablecell_merge_down : mergeCells( selection, 'down', true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
 882                                      tablecell_split_vertical : verticalSplitCell( selection, true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
 883                                      tablecell_split_horizontal : horizontalSplitCell( selection, true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
 884                                      tablecell_properties : cells.length > 0 ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED
 885                                  };
 886                              }
 887                          },
 888  
 889                          tablecell_insertBefore :
 890                          {
 891                              label : lang.cell.insertBefore,
 892                              group : 'tablecell',
 893                              command : 'cellInsertBefore',
 894                              order : 5
 895                          },
 896  
 897                          tablecell_insertAfter :
 898                          {
 899                              label : lang.cell.insertAfter,
 900                              group : 'tablecell',
 901                              command : 'cellInsertAfter',
 902                              order : 10
 903                          },
 904  
 905                          tablecell_delete :
 906                          {
 907                              label : lang.cell.deleteCell,
 908                              group : 'tablecell',
 909                              command : 'cellDelete',
 910                              order : 15
 911                          },
 912  
 913                          tablecell_merge :
 914                          {
 915                              label : lang.cell.merge,
 916                              group : 'tablecell',
 917                              command : 'cellMerge',
 918                              order : 16
 919                          },
 920  
 921                          tablecell_merge_right :
 922                          {
 923                              label : lang.cell.mergeRight,
 924                              group : 'tablecell',
 925                              command : 'cellMergeRight',
 926                              order : 17
 927                          },
 928  
 929                          tablecell_merge_down :
 930                          {
 931                              label : lang.cell.mergeDown,
 932                              group : 'tablecell',
 933                              command : 'cellMergeDown',
 934                              order : 18
 935                          },
 936  
 937                          tablecell_split_horizontal :
 938                          {
 939                              label : lang.cell.splitHorizontal,
 940                              group : 'tablecell',
 941                              command : 'cellHorizontalSplit',
 942                              order : 19
 943                          },
 944  
 945                          tablecell_split_vertical :
 946                          {
 947                              label : lang.cell.splitVertical,
 948                              group : 'tablecell',
 949                              command : 'cellVerticalSplit',
 950                              order : 20
 951                          },
 952  
 953                          tablecell_properties :
 954                          {
 955                              label : lang.cell.title,
 956                              group : 'tablecellproperties',
 957                              command : 'cellProperties',
 958                              order : 21
 959                          },
 960  
 961                          tablerow :
 962                          {
 963                              label : lang.row.menu,
 964                              group : 'tablerow',
 965                              order : 1,
 966                              getItems : function()
 967                              {
 968                                  return {
 969                                      tablerow_insertBefore : CKEDITOR.TRISTATE_OFF,
 970                                      tablerow_insertAfter : CKEDITOR.TRISTATE_OFF,
 971                                      tablerow_delete : CKEDITOR.TRISTATE_OFF
 972                                  };
 973                              }
 974                          },
 975  
 976                          tablerow_insertBefore :
 977                          {
 978                              label : lang.row.insertBefore,
 979                              group : 'tablerow',
 980                              command : 'rowInsertBefore',
 981                              order : 5
 982                          },
 983  
 984                          tablerow_insertAfter :
 985                          {
 986                              label : lang.row.insertAfter,
 987                              group : 'tablerow',
 988                              command : 'rowInsertAfter',
 989                              order : 10
 990                          },
 991  
 992                          tablerow_delete :
 993                          {
 994                              label : lang.row.deleteRow,
 995                              group : 'tablerow',
 996                              command : 'rowDelete',
 997                              order : 15
 998                          },
 999  
1000                          tablecolumn :
1001                          {
1002                              label : lang.column.menu,
1003                              group : 'tablecolumn',
1004                              order : 1,
1005                              getItems : function()
1006                              {
1007                                  return {
1008                                      tablecolumn_insertBefore : CKEDITOR.TRISTATE_OFF,
1009                                      tablecolumn_insertAfter : CKEDITOR.TRISTATE_OFF,
1010                                      tablecolumn_delete : CKEDITOR.TRISTATE_OFF
1011                                  };
1012                              }
1013                          },
1014  
1015                          tablecolumn_insertBefore :
1016                          {
1017                              label : lang.column.insertBefore,
1018                              group : 'tablecolumn',
1019                              command : 'columnInsertBefore',
1020                              order : 5
1021                          },
1022  
1023                          tablecolumn_insertAfter :
1024                          {
1025                              label : lang.column.insertAfter,
1026                              group : 'tablecolumn',
1027                              command : 'columnInsertAfter',
1028                              order : 10
1029                          },
1030  
1031                          tablecolumn_delete :
1032                          {
1033                              label : lang.column.deleteColumn,
1034                              group : 'tablecolumn',
1035                              command : 'columnDelete',
1036                              order : 15
1037                          }
1038                      });
1039              }
1040  
1041              // If the "contextmenu" plugin is laoded, register the listeners.

1042              if ( editor.contextMenu )
1043              {
1044                  editor.contextMenu.addListener( function( element, selection )
1045                      {
1046                          if ( !element || element.isReadOnly() )
1047                              return null;
1048  
1049                          while ( element )
1050                          {
1051                              if ( element.getName() in contextMenuTags )
1052                              {
1053                                  return {
1054                                      tablecell : CKEDITOR.TRISTATE_OFF,
1055                                      tablerow : CKEDITOR.TRISTATE_OFF,
1056                                      tablecolumn : CKEDITOR.TRISTATE_OFF
1057                                  };
1058                              }
1059                              element = element.getParent();
1060                          }
1061  
1062                          return null;
1063                      } );
1064              }
1065          },
1066  
1067          getSelectedCells : getSelectedCells
1068  
1069      };
1070      CKEDITOR.plugins.add( 'tabletools', CKEDITOR.plugins.tabletools );
1071  })();
1072  
1073  /**

1074   * Create a two-dimension array that reflects the actual layout of table cells,

1075   * with cell spans, with mappings to the original td elements.

1076   * @param table {CKEDITOR.dom.element}

1077   */
1078  CKEDITOR.tools.buildTableMap = function ( table )
1079  {
1080      var aRows = table.$.rows ;
1081  
1082      // Row and Column counters.

1083      var r = -1 ;
1084  
1085      var aMap = [];
1086  
1087      for ( var i = 0 ; i < aRows.length ; i++ )
1088      {
1089          r++ ;
1090          !aMap[r] && ( aMap[r] = [] );
1091  
1092          var c = -1 ;
1093  
1094          for ( var j = 0 ; j < aRows[i].cells.length ; j++ )
1095          {
1096              var oCell = aRows[i].cells[j] ;
1097  
1098              c++ ;
1099              while ( aMap[r][c] )
1100                  c++ ;
1101  
1102              var iColSpan = isNaN( oCell.colSpan ) ? 1 : oCell.colSpan ;
1103              var iRowSpan = isNaN( oCell.rowSpan ) ? 1 : oCell.rowSpan ;
1104  
1105              for ( var rs = 0 ; rs < iRowSpan ; rs++ )
1106              {
1107                  if ( !aMap[r + rs] )
1108                      aMap[r + rs] = [];
1109  
1110                  for ( var cs = 0 ; cs < iColSpan ; cs++ )
1111                  {
1112                      aMap[r + rs][c + cs] = aRows[i].cells[j] ;
1113                  }
1114              }
1115  
1116              c += iColSpan - 1 ;
1117          }
1118      }
1119      return aMap ;
1120  };


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