fcktablehandler.js
上传用户:ah_jiwei
上传日期:2022-07-24
资源大小:54044k
文件大小:25k
源码类别:

数据库编程

开发平台:

Visual C++

  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.  * Manage table operations.
  22.  */
  23. var FCKTableHandler = new Object() ;
  24. FCKTableHandler.InsertRow = function( insertBefore )
  25. {
  26. // Get the row where the selection is placed in.
  27. var oRow = FCKSelection.MoveToAncestorNode( 'TR' ) ;
  28. if ( !oRow ) return ;
  29. // Create a clone of the row.
  30. var oNewRow = oRow.cloneNode( true ) ;
  31. // Insert the new row (copy) before of it.
  32. oRow.parentNode.insertBefore( oNewRow, oRow ) ;
  33. // Clean one of the rows to produce the illusion of inserting an empty row before or after.
  34. FCKTableHandler.ClearRow( insertBefore ? oNewRow : oRow ) ;
  35. }
  36. FCKTableHandler.DeleteRows = function( row )
  37. {
  38. // If no row has been passed as a parameter,
  39. // then get the row( s ) containing the cells where the selection is placed in.
  40. // If user selected multiple rows ( by selecting multiple cells ), walk
  41. // the selected cell list and delete the rows containing the selected cells
  42. if ( ! row )
  43. {
  44. var aCells = FCKTableHandler.GetSelectedCells() ;
  45. var aRowsToDelete = new Array() ;
  46. //queue up the rows -- it's possible ( and likely ) that we may get duplicates
  47. for ( var i = 0; i < aCells.length; i++ )
  48. {
  49. var oRow = FCKTools.GetElementAscensor( aCells[i],'TR' ) ;
  50. aRowsToDelete[oRow.rowIndex] = oRow ;
  51. }
  52. for ( var i = aRowsToDelete.length; i >= 0; i-- )
  53. {
  54. if ( aRowsToDelete[i] )
  55. FCKTableHandler.DeleteRows( aRowsToDelete[i] );
  56. }
  57. return ;
  58. }
  59. // Get the row's table.
  60. var oTable = FCKTools.GetElementAscensor( row, 'TABLE' ) ;
  61. // If just one row is available then delete the entire table.
  62. if ( oTable.rows.length == 1 )
  63. {
  64. FCKTableHandler.DeleteTable( oTable ) ;
  65. return ;
  66. }
  67. // Delete the row.
  68. row.parentNode.removeChild( row ) ;
  69. }
  70. FCKTableHandler.DeleteTable = function( table )
  71. {
  72. // If no table has been passed as a parameter,
  73. // then get the table where the selection is placed in.
  74. if ( !table )
  75. {
  76. table = FCKSelection.GetSelectedElement() ;
  77. if ( !table || table.tagName != 'TABLE' )
  78. table = FCKSelection.MoveToAncestorNode( 'TABLE' ) ;
  79. }
  80. if ( !table ) return ;
  81. // Delete the table.
  82. FCKSelection.SelectNode( table ) ;
  83. FCKSelection.Collapse();
  84. // if the table is wrapped with a singleton <p> ( or something similar ), remove
  85. // the surrounding tag -- which likely won't show after deletion anyway
  86. if ( table.parentNode.childNodes.length == 1 )
  87. table.parentNode.parentNode.removeChild( table.parentNode );
  88. else
  89. table.parentNode.removeChild( table  ) ;
  90. }
  91. FCKTableHandler.InsertColumn = function( insertBefore )
  92. {
  93. // Get the cell where the selection is placed in.
  94. var oCell = null ;
  95. var nodes = this.GetSelectedCells() ;
  96. if ( nodes && nodes.length )
  97. oCell = nodes[ insertBefore ? 0 : ( nodes.length - 1 ) ] ;
  98. if ( ! oCell )
  99. return ;
  100. // Get the cell's table.
  101. var oTable = FCKTools.GetElementAscensor( oCell, 'TABLE' ) ;
  102. var iIndex = oCell.cellIndex ;
  103. // Loop throw all rows available in the table.
  104. for ( var i = 0 ; i < oTable.rows.length ; i++ )
  105. {
  106. // Get the row.
  107. var oRow = oTable.rows[i] ;
  108. // If the row doens't have enough cells, ignore it.
  109. if ( oRow.cells.length < ( iIndex + 1 ) )
  110. continue ;
  111. oCell = oRow.cells[iIndex].cloneNode(false) ;
  112. if ( FCKBrowserInfo.IsGeckoLike )
  113. FCKTools.AppendBogusBr( oCell ) ;
  114. // Get back the currently selected cell.
  115. var oBaseCell = oRow.cells[iIndex] ;
  116. if ( insertBefore )
  117. oRow.insertBefore( oCell, oBaseCell ) ;
  118. else if ( oBaseCell.nextSibling )
  119. oRow.insertBefore( oCell, oBaseCell.nextSibling ) ;
  120. else
  121. oRow.appendChild( oCell ) ;
  122. }
  123. }
  124. FCKTableHandler.DeleteColumns = function( oCell )
  125. {
  126. // if user selected multiple cols ( by selecting multiple cells ), walk
  127. // the selected cell list and delete the rows containing the selected cells
  128. if ( !oCell  )
  129. {
  130. var aColsToDelete = FCKTableHandler.GetSelectedCells();
  131. for ( var i = aColsToDelete.length; i >= 0; i--  )
  132. {
  133. if ( aColsToDelete[i]  )
  134. FCKTableHandler.DeleteColumns( aColsToDelete[i]  );
  135. }
  136. return;
  137. }
  138. if ( !oCell ) return ;
  139. // Get the cell's table.
  140. var oTable = FCKTools.GetElementAscensor( oCell, 'TABLE' ) ;
  141. // Get the cell index.
  142. var iIndex = oCell.cellIndex ;
  143. // Loop throw all rows (from down to up, because it's possible that some
  144. // rows will be deleted).
  145. for ( var i = oTable.rows.length - 1 ; i >= 0 ; i-- )
  146. {
  147. // Get the row.
  148. var oRow = oTable.rows[i] ;
  149. // If the cell to be removed is the first one and the row has just one cell.
  150. if ( iIndex == 0 && oRow.cells.length == 1 )
  151. {
  152. // Remove the entire row.
  153. FCKTableHandler.DeleteRows( oRow ) ;
  154. continue ;
  155. }
  156. // If the cell to be removed exists the delete it.
  157. if ( oRow.cells[iIndex] )
  158. oRow.removeChild( oRow.cells[iIndex] ) ;
  159. }
  160. }
  161. FCKTableHandler.InsertCell = function( cell, insertBefore )
  162. {
  163. // Get the cell where the selection is placed in.
  164. var oCell = null ;
  165. var nodes = this.GetSelectedCells() ;
  166. if ( nodes && nodes.length )
  167. oCell = nodes[ insertBefore ? 0 : ( nodes.length - 1 ) ] ;
  168. if ( ! oCell )
  169. return null ;
  170. // Create the new cell element to be added.
  171. var oNewCell = FCK.EditorDocument.createElement( 'TD' ) ;
  172. if ( FCKBrowserInfo.IsGeckoLike )
  173. FCKTools.AppendBogusBr( oNewCell ) ;
  174. if ( !insertBefore && oCell.cellIndex == oCell.parentNode.cells.length - 1 )
  175. oCell.parentNode.appendChild( oNewCell ) ;
  176. else
  177. oCell.parentNode.insertBefore( oNewCell, insertBefore ? oCell : oCell.nextSibling ) ;
  178. return oNewCell ;
  179. }
  180. FCKTableHandler.DeleteCell = function( cell )
  181. {
  182. // If this is the last cell in the row.
  183. if ( cell.parentNode.cells.length == 1 )
  184. {
  185. // Delete the entire row.
  186. FCKTableHandler.DeleteRows( FCKTools.GetElementAscensor( cell, 'TR' ) ) ;
  187. return ;
  188. }
  189. // Delete the cell from the row.
  190. cell.parentNode.removeChild( cell ) ;
  191. }
  192. FCKTableHandler.DeleteCells = function()
  193. {
  194. var aCells = FCKTableHandler.GetSelectedCells() ;
  195. for ( var i = aCells.length - 1 ; i >= 0  ; i-- )
  196. {
  197. FCKTableHandler.DeleteCell( aCells[i] ) ;
  198. }
  199. }
  200. FCKTableHandler._MarkCells = function( cells, label )
  201. {
  202. for ( var i = 0 ; i < cells.length ; i++ )
  203. cells[i][label] = true ;
  204. }
  205. FCKTableHandler._UnmarkCells = function( cells, label )
  206. {
  207. for ( var i = 0 ; i < cells.length ; i++ )
  208. {
  209. if ( FCKBrowserInfo.IsIE )
  210. cells[i].removeAttribute( label ) ;
  211. else
  212. delete cells[i][label] ;
  213. }
  214. }
  215. FCKTableHandler._ReplaceCellsByMarker = function( tableMap, marker, substitute )
  216. {
  217. for ( var i = 0 ; i < tableMap.length ; i++ )
  218. {
  219. for ( var j = 0 ; j < tableMap[i].length ; j++ )
  220. {
  221. if ( tableMap[i][j][marker] )
  222. tableMap[i][j] = substitute ;
  223. }
  224. }
  225. }
  226. FCKTableHandler._GetMarkerGeometry = function( tableMap, rowIdx, colIdx, markerName )
  227. {
  228. var selectionWidth = 0 ;
  229. var selectionHeight = 0 ;
  230. var cellsLeft = 0 ;
  231. var cellsUp = 0 ;
  232. for ( var i = colIdx ; tableMap[rowIdx][i] && tableMap[rowIdx][i][markerName] ; i++ )
  233. selectionWidth++ ;
  234. for ( var i = colIdx - 1 ; tableMap[rowIdx][i] && tableMap[rowIdx][i][markerName] ; i-- )
  235. {
  236. selectionWidth++ ;
  237. cellsLeft++ ;
  238. }
  239. for ( var i = rowIdx ; tableMap[i] && tableMap[i][colIdx] && tableMap[i][colIdx][markerName] ; i++ )
  240. selectionHeight++ ;
  241. for ( var i = rowIdx - 1 ; tableMap[i] && tableMap[i][colIdx] && tableMap[i][colIdx][markerName] ; i-- )
  242. {
  243. selectionHeight++ ;
  244. cellsUp++ ;
  245. }
  246. return { 'width' : selectionWidth, 'height' : selectionHeight, 'x' : cellsLeft, 'y' : cellsUp } ;
  247. }
  248. FCKTableHandler.CheckIsSelectionRectangular = function()
  249. {
  250. // If every row and column in an area on a plane are of the same width and height,
  251. // Then the area is a rectangle.
  252. var cells = FCKTableHandler.GetSelectedCells() ;
  253. if ( cells.length < 1 )
  254. return false ;
  255. this._MarkCells( cells, '_CellSelected' ) ;
  256. var tableMap = this._CreateTableMap( cells[0].parentNode.parentNode ) ;
  257. var rowIdx = cells[0].parentNode.rowIndex ;
  258. var colIdx = this._GetCellIndexSpan( tableMap, rowIdx, cells[0] ) ;
  259. var geometry = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_CellSelected' ) ;
  260. var baseColIdx = colIdx - geometry.x ;
  261. var baseRowIdx = rowIdx - geometry.y ;
  262. if ( geometry.width >= geometry.height )
  263. {
  264. for ( colIdx = baseColIdx ; colIdx < baseColIdx + geometry.width ; colIdx++ )
  265. {
  266. rowIdx = baseRowIdx + ( colIdx - baseColIdx ) % geometry.height ;
  267. if ( ! tableMap[rowIdx] || ! tableMap[rowIdx][colIdx] )
  268. {
  269. this._UnmarkCells( cells, '_CellSelected' ) ;
  270. return false ;
  271. }
  272. var g = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_CellSelected' ) ;
  273. if ( g.width != geometry.width || g.height != geometry.height )
  274. {
  275. this._UnmarkCells( cells, '_CellSelected' ) ;
  276. return false ;
  277. }
  278. }
  279. }
  280. else
  281. {
  282. for ( rowIdx = baseRowIdx ; rowIdx < baseRowIdx + geometry.height ; rowIdx++ )
  283. {
  284. colIdx = baseColIdx + ( rowIdx - baseRowIdx ) % geometry.width ;
  285. if ( ! tableMap[rowIdx] || ! tableMap[rowIdx][colIdx] )
  286. {
  287. this._UnmarkCells( cells, '_CellSelected' ) ;
  288. return false ;
  289. }
  290. var g = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_CellSelected' ) ;
  291. if ( g.width != geometry.width || g.height != geometry.height )
  292. {
  293. this._UnmarkCells( cells, '_CellSelected' ) ;
  294. return false ;
  295. }
  296. }
  297. }
  298. this._UnmarkCells( cells, '_CellSelected' ) ;
  299. return true ;
  300. }
  301. FCKTableHandler.MergeCells = function()
  302. {
  303. // Get all selected cells.
  304. var cells = this.GetSelectedCells() ;
  305. if ( cells.length < 2 )
  306. return ;
  307. // Assume the selected cells are already in a rectangular geometry.
  308. // Because the checking is already done by FCKTableCommand.
  309. var refCell = cells[0] ;
  310. var tableMap = this._CreateTableMap( refCell.parentNode.parentNode ) ;
  311. var rowIdx = refCell.parentNode.rowIndex ;
  312. var colIdx = this._GetCellIndexSpan( tableMap, rowIdx, refCell ) ;
  313. this._MarkCells( cells, '_SelectedCells' ) ;
  314. var selectionGeometry = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_SelectedCells' ) ;
  315. var baseColIdx = colIdx - selectionGeometry.x ;
  316. var baseRowIdx = rowIdx - selectionGeometry.y ;
  317. var cellContents = refCell.ownerDocument.createDocumentFragment() ;
  318. for ( var i = 0 ; i < selectionGeometry.height ; i++ ) 
  319. {
  320. var rowChildNodesCount = 0 ;
  321. for ( var j = 0 ; j < selectionGeometry.width ; j++ )
  322. {
  323. var currentCell = tableMap[baseRowIdx + i][baseColIdx + j] ;
  324. while ( currentCell.childNodes.length > 0 )
  325. {
  326. var node = currentCell.removeChild( currentCell.firstChild ) ;
  327. if ( node.nodeType != 1 
  328. || ( node.getAttribute( 'type', 2 ) != '_moz' && node.getAttribute( '_moz_dirty' ) != null ) )
  329. {
  330. cellContents.appendChild( node ) ;
  331. rowChildNodesCount++ ;
  332. }
  333. }
  334. }
  335. if ( rowChildNodesCount > 0 )
  336. cellContents.appendChild( refCell.ownerDocument.createElement( 'br' ) ) ;
  337. }
  338. this._ReplaceCellsByMarker( tableMap, '_SelectedCells', refCell ) ;
  339. this._UnmarkCells( cells, '_SelectedCells' ) ;
  340. this._InstallTableMap( tableMap, refCell.parentNode.parentNode ) ;
  341. refCell.appendChild( cellContents ) ;
  342. if ( FCKBrowserInfo.IsGeckoLike && ( ! refCell.firstChild ) )
  343. FCKTools.AppendBogusBr( refCell ) ;
  344. this._MoveCaretToCell( refCell, false ) ;
  345. }
  346. FCKTableHandler.MergeRight = function()
  347. {
  348. var target = this.GetMergeRightTarget() ;
  349. if ( target == null )
  350. return ;
  351. var refCell = target.refCell ;
  352. var tableMap = target.tableMap ;
  353. var nextCell = target.nextCell ; 
  354. var cellContents = FCK.EditorDocument.createDocumentFragment() ;
  355. while ( nextCell && nextCell.childNodes && nextCell.childNodes.length > 0 )
  356. cellContents.appendChild( nextCell.removeChild( nextCell.firstChild ) ) ;
  357. nextCell.parentNode.removeChild( nextCell ) ;
  358. refCell.appendChild( cellContents ) ;
  359. this._MarkCells( [nextCell], '_Replace' ) ;
  360. this._ReplaceCellsByMarker( tableMap, '_Replace', refCell ) ;
  361. this._InstallTableMap( tableMap, refCell.parentNode.parentNode ) ;
  362. this._MoveCaretToCell( refCell, false ) ;
  363. }
  364. FCKTableHandler.MergeDown = function()
  365. {
  366. var target = this.GetMergeDownTarget() ;
  367. if ( target == null )
  368. return ;
  369. var refCell = target.refCell ;
  370. var tableMap = target.tableMap ;
  371. var nextCell = target.nextCell ;
  372. var cellContents = refCell.ownerDocument.createDocumentFragment() ;
  373. while ( nextCell && nextCell.childNodes && nextCell.childNodes.length > 0 )
  374. cellContents.appendChild( nextCell.removeChild( nextCell.firstChild ) ) ;
  375. if ( cellContents.firstChild )
  376. cellContents.insertBefore( nextCell.ownerDocument.createElement( 'br' ), cellContents.firstChild ) ;
  377. refCell.appendChild( cellContents ) ;
  378. this._MarkCells( [nextCell], '_Replace' ) ;
  379. this._ReplaceCellsByMarker( tableMap, '_Replace', refCell ) ;
  380. this._InstallTableMap( tableMap, refCell.parentNode.parentNode ) ;
  381. this._MoveCaretToCell( refCell, false ) ;
  382. }
  383. FCKTableHandler.HorizontalSplitCell = function()
  384. {
  385. var cells = FCKTableHandler.GetSelectedCells() ;
  386. if ( cells.length != 1 )
  387. return ;
  388. var refCell = cells[0] ;
  389. var tableMap = this._CreateTableMap( refCell.parentNode.parentNode ) ;
  390. var rowIdx = refCell.parentNode.rowIndex ;
  391. var colIdx = FCKTableHandler._GetCellIndexSpan( tableMap, rowIdx, refCell ) ;
  392. var cellSpan = isNaN( refCell.colSpan ) ? 1 : refCell.colSpan ;
  393. if ( cellSpan > 1 )
  394. {
  395. // Splittng a multi-column cell - original cell gets ceil(colSpan/2) columns,
  396. // new cell gets floor(colSpan/2).
  397. var newCellSpan = Math.ceil( cellSpan / 2 ) ;
  398. var newCell = refCell.ownerDocument.createElement( 'td' ) ;
  399. if ( FCKBrowserInfo.IsGeckoLike )
  400. FCKTools.AppendBogusBr( newCell ) ;
  401. var startIdx = colIdx + newCellSpan ;
  402. var endIdx = colIdx + cellSpan ;
  403. var rowSpan = isNaN( refCell.rowSpan ) ? 1 : refCell.rowSpan ;
  404. for ( var r = rowIdx ; r < rowIdx + rowSpan ; r++ )
  405. {
  406. for ( var i = startIdx ; i < endIdx ; i++ )
  407. tableMap[r][i] = newCell ;
  408. }
  409. }
  410. else
  411. {
  412. // Splitting a single-column cell - add a new cell, and expand 
  413. // cells crossing the same column.
  414. var newTableMap = [] ;
  415. for ( var i = 0 ; i < tableMap.length ; i++ ) 
  416. {
  417. var newRow = tableMap[i].slice( 0, colIdx ) ;
  418. if ( tableMap[i].length <= colIdx )
  419. {
  420. newTableMap.push( newRow ) ;
  421. continue ;
  422. }
  423. if ( tableMap[i][colIdx] == refCell )
  424. {
  425. newRow.push( refCell ) ;
  426. newRow.push( refCell.ownerDocument.createElement( 'td' ) ) ;
  427. if ( FCKBrowserInfo.IsGeckoLike )
  428. FCKTools.AppendBogusBr( newRow[newRow.length - 1] ) ;
  429. }
  430. else
  431. {
  432. newRow.push( tableMap[i][colIdx] ) ;
  433. newRow.push( tableMap[i][colIdx] ) ;
  434. }
  435. for ( var j = colIdx + 1 ; j < tableMap[i].length ; j++ )
  436. newRow.push( tableMap[i][j] ) ;
  437. newTableMap.push( newRow ) ;
  438. }
  439. tableMap = newTableMap ;
  440. }
  441. this._InstallTableMap( tableMap, refCell.parentNode.parentNode ) ;
  442. }
  443. FCKTableHandler.VerticalSplitCell = function()
  444. {
  445. var cells = FCKTableHandler.GetSelectedCells() ;
  446. if ( cells.length != 1 )
  447. return ;
  448. var currentCell = cells[0] ;
  449. var tableMap = this._CreateTableMap( currentCell.parentNode.parentNode ) ;
  450. var cellIndex = FCKTableHandler._GetCellIndexSpan( tableMap, currentCell.parentNode.rowIndex, currentCell ) ;
  451. var currentRowSpan = currentCell.rowSpan ;
  452. var currentRowIndex = currentCell.parentNode.rowIndex ;
  453. if ( isNaN( currentRowSpan ) )
  454. currentRowSpan = 1 ;
  455. if ( currentRowSpan > 1 )
  456. {
  457. // 1. Set the current cell's rowSpan to 1.
  458. currentCell.rowSpan = Math.ceil( currentRowSpan / 2 ) ;
  459. // 2. Find the appropriate place to insert a new cell at the next row.
  460. var newCellRowIndex = currentRowIndex + Math.ceil( currentRowSpan / 2 ) ;
  461. var insertMarker = null ;
  462. for ( var i = cellIndex+1 ; i < tableMap[newCellRowIndex].length ; i++ )
  463. {
  464. if ( tableMap[newCellRowIndex][i].parentNode.rowIndex == newCellRowIndex )
  465. {
  466. insertMarker = tableMap[newCellRowIndex][i] ;
  467. break ;
  468. }
  469. }
  470. // 3. Insert the new cell to the indicated place, with the appropriate rowSpan, next row.
  471. var newCell = FCK.EditorDocument.createElement( 'td' ) ;
  472. newCell.rowSpan = Math.floor( currentRowSpan / 2 ) ;
  473. if ( FCKBrowserInfo.IsGeckoLike )
  474. FCKTools.AppendBogusBr( newCell ) ;
  475. currentCell.parentNode.parentNode.rows[newCellRowIndex].insertBefore( newCell, insertMarker ) ;
  476. }
  477. else
  478. {
  479. // 1. Insert a new row.
  480. var newCellRowIndex = currentRowIndex + 1 ;
  481. var newRow = FCK.EditorDocument.createElement( 'tr' ) ;
  482. currentCell.parentNode.parentNode.insertBefore( newRow, currentCell.parentNode.parentNode.rows[newCellRowIndex] ) ;
  483. // 2. +1 to rowSpan for all cells crossing currentCell's row.
  484. for ( var i = 0 ; i < tableMap[currentRowIndex].length ; )
  485. {
  486. var colSpan = tableMap[currentRowIndex][i].colSpan ;
  487. if ( isNaN( colSpan ) || colSpan < 1 )
  488. colSpan = 1 ;
  489. if ( i == cellIndex )
  490. {
  491. i += colSpan ;
  492. continue ;
  493. }
  494. var rowSpan = tableMap[currentRowIndex][i].rowSpan ;
  495. if ( isNaN( rowSpan ) )
  496. rowSpan = 1 ;
  497. tableMap[currentRowIndex][i].rowSpan = rowSpan + 1 ;
  498. i += colSpan ;
  499. }
  500. // 3. Insert a new cell to new row.
  501. var newCell = FCK.EditorDocument.createElement( 'td' ) ;
  502. if ( FCKBrowserInfo.IsGeckoLike )
  503. FCKTools.AppendBogusBr( newCell ) ;
  504. newRow.appendChild( newCell ) ;
  505. }
  506. }
  507. // Get the cell index from a TableMap.
  508. FCKTableHandler._GetCellIndexSpan = function( tableMap, rowIndex, cell )
  509. {
  510. if ( tableMap.length < rowIndex + 1 )
  511. return null ;
  512. var oRow = tableMap[ rowIndex ] ;
  513. for ( var c = 0 ; c < oRow.length ; c++ )
  514. {
  515. if ( oRow[c] == cell )
  516. return c ;
  517. }
  518. return null ;
  519. }
  520. // Get the cell location from a TableMap. Returns an array with an [x,y] location
  521. FCKTableHandler._GetCellLocation = function( tableMap, cell  )
  522. {
  523. for ( var i = 0 ; i < tableMap.length; i++ )
  524. {
  525. for ( var c = 0 ; c < tableMap[i].length ; c++  )
  526. {
  527. if ( tableMap[i][c] == cell  ) return [i,c];
  528. }
  529. }
  530. return null ;
  531. }
  532. // Get the cells available in a column of a TableMap.
  533. FCKTableHandler._GetColumnCells = function( tableMap, columnIndex )
  534. {
  535. var aCollCells = new Array() ;
  536. for ( var r = 0 ; r < tableMap.length ; r++ )
  537. {
  538. var oCell = tableMap[r][columnIndex] ;
  539. if ( oCell && ( aCollCells.length == 0 || aCollCells[ aCollCells.length - 1 ] != oCell ) )
  540. aCollCells[ aCollCells.length ] = oCell ;
  541. }
  542. return aCollCells ;
  543. }
  544. // This function is quite hard to explain. It creates a matrix representing all cells in a table.
  545. // The difference here is that the "spanned" cells (colSpan and rowSpan) are duplicated on the matrix
  546. // cells that are "spanned". For example, a row with 3 cells where the second cell has colSpan=2 and rowSpan=3
  547. // will produce a bi-dimensional matrix with the following values (representing the cells):
  548. // Cell1, Cell2, Cell2, Cell 3
  549. // Cell4, Cell2, Cell2, Cell 5
  550. FCKTableHandler._CreateTableMap = function( table )
  551. {
  552. var aRows = table.rows ;
  553. // Row and Column counters.
  554. var r = -1 ;
  555. var aMap = new Array() ;
  556. for ( var i = 0 ; i < aRows.length ; i++ )
  557. {
  558. r++ ;
  559. if ( !aMap[r] )
  560. aMap[r] = new Array() ;
  561. var c = -1 ;
  562. for ( var j = 0 ; j < aRows[i].cells.length ; j++ )
  563. {
  564. var oCell = aRows[i].cells[j] ;
  565. c++ ;
  566. while ( aMap[r][c] )
  567. c++ ;
  568. var iColSpan = isNaN( oCell.colSpan ) ? 1 : oCell.colSpan ;
  569. var iRowSpan = isNaN( oCell.rowSpan ) ? 1 : oCell.rowSpan ;
  570. for ( var rs = 0 ; rs < iRowSpan ; rs++ )
  571. {
  572. if ( !aMap[r + rs] )
  573. aMap[r + rs] = new Array() ;
  574. for ( var cs = 0 ; cs < iColSpan ; cs++ )
  575. {
  576. aMap[r + rs][c + cs] = aRows[i].cells[j] ;
  577. }
  578. }
  579. c += iColSpan - 1 ;
  580. }
  581. }
  582. return aMap ;
  583. }
  584. // This function is the inverse of _CreateTableMap - it takes in a table map and converts it to an HTML table.
  585. FCKTableHandler._InstallTableMap = function( tableMap, table )
  586. {
  587. // Clear the table of all rows first.
  588. while ( table.rows.length > 0 )
  589. {
  590. var row = table.rows[0] ;
  591. row.parentNode.removeChild( row ) ;
  592. }
  593. // Disconnect all the cells in tableMap from their parents, set all colSpan and rowSpan attributes to 1.
  594. for ( var i = 0 ; i < tableMap.length ; i++ )
  595. {
  596. for ( var j = 0 ; j < tableMap[i].length ; j++ )
  597. {
  598. var cell = tableMap[i][j] ;
  599. if ( cell.parentNode )
  600. cell.parentNode.removeChild( cell ) ;
  601. cell.colSpan = cell.rowSpan = 1 ;
  602. }
  603. }
  604. // Scan by rows and set colSpan.
  605. var maxCol = 0 ;
  606. for ( var i = 0 ; i < tableMap.length ; i++ )
  607. {
  608. for ( var j = 0 ; j < tableMap[i].length ; j++ )
  609. {
  610. var cell = tableMap[i][j] ;
  611. if ( ! cell)
  612. continue ;
  613. if ( j > maxCol )
  614. maxCol = j ;
  615. if ( cell._colScanned === true )
  616. continue ;
  617. if ( tableMap[i][j-1] == cell )
  618. cell.colSpan++ ;
  619. if ( tableMap[i][j+1] != cell )
  620. cell._colScanned = true ;
  621. }
  622. }
  623. // Scan by columns and set rowSpan.
  624. for ( var i = 0 ; i <= maxCol ; i++ )
  625. {
  626. for ( var j = 0 ; j < tableMap.length ; j++ )
  627. {
  628. if ( ! tableMap[j] )
  629. continue ;
  630. var cell = tableMap[j][i] ;
  631. if ( ! cell || cell._rowScanned === true )
  632. continue ;
  633. if ( tableMap[j-1] && tableMap[j-1][i] == cell )
  634. cell.rowSpan++ ;
  635. if ( ! tableMap[j+1] || tableMap[j+1][i] != cell )
  636. cell._rowScanned = true ;
  637. }
  638. }
  639. // Clear all temporary flags.
  640. for ( var i = 0 ; i < tableMap.length ; i++ )
  641. {
  642. for ( var j = 0 ; j < tableMap[i].length ; j++)
  643. {
  644. var cell = tableMap[i][j] ;
  645. if ( FCKBrowserInfo.IsIE )
  646. {
  647. cell.removeAttribute( '_colScanned' ) ;
  648. cell.removeAttribute( '_rowScanned' ) ;
  649. }
  650. else
  651. {
  652. delete cell._colScanned ;
  653. delete cell._rowScanned ;
  654. }
  655. }
  656. }
  657. // Insert physical rows and columns to the table.
  658. for ( var i = 0 ; i < tableMap.length ; i++ )
  659. {
  660. var rowObj = table.ownerDocument.createElement( 'tr' ) ;
  661. for ( var j = 0 ; j < tableMap[i].length ; )
  662. {
  663. var cell = tableMap[i][j] ;
  664. if ( tableMap[i-1] && tableMap[i-1][j] == cell )
  665. {
  666. j += cell.colSpan ;
  667. continue ;
  668. }
  669. rowObj.appendChild( cell ) ;
  670. j += cell.colSpan ;
  671. if ( cell.colSpan == 1 )
  672. cell.removeAttribute( 'colspan' ) ;
  673. if ( cell.rowSpan == 1 )
  674. cell.removeAttribute( 'rowspan' ) ;
  675. }
  676. table.appendChild( rowObj ) ;
  677. }
  678. }
  679. FCKTableHandler._MoveCaretToCell = function ( refCell, toStart )
  680. {
  681. var range = new FCKDomRange( FCK.EditorWindow ) ;
  682. range.MoveToNodeContents( refCell ) ;
  683. range.Collapse( toStart ) ;
  684. range.Select() ;
  685. }
  686. FCKTableHandler.ClearRow = function( tr )
  687. {
  688. // Get the array of row's cells.
  689. var aCells = tr.cells ;
  690. // Replace the contents of each cell with "nothing".
  691. for ( var i = 0 ; i < aCells.length ; i++ )
  692. {
  693. aCells[i].innerHTML = '' ;
  694. if ( FCKBrowserInfo.IsGeckoLike )
  695. FCKTools.AppendBogusBr( aCells[i] ) ;
  696. }
  697. }
  698. FCKTableHandler.GetMergeRightTarget = function()
  699. {
  700. var cells = this.GetSelectedCells() ;
  701. if ( cells.length != 1 )
  702. return null ;
  703. var refCell = cells[0] ;
  704. var tableMap = this._CreateTableMap( refCell.parentNode.parentNode ) ;
  705. var rowIdx = refCell.parentNode.rowIndex ;
  706. var colIdx = this._GetCellIndexSpan( tableMap, rowIdx, refCell ) ;
  707. var nextColIdx = colIdx + ( isNaN( refCell.colSpan ) ? 1 : refCell.colSpan ) ;
  708. var nextCell = tableMap[rowIdx][nextColIdx] ;
  709. if ( ! nextCell )
  710. return null ;
  711. // The two cells must have the same vertical geometry, otherwise merging does not make sense.
  712. this._MarkCells( [refCell, nextCell], '_SizeTest' ) ;
  713. var refGeometry = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_SizeTest' ) ;
  714. var nextGeometry = this._GetMarkerGeometry( tableMap, rowIdx, nextColIdx, '_SizeTest' ) ;
  715. this._UnmarkCells( [refCell, nextCell], '_SizeTest' ) ;
  716. if ( refGeometry.height != nextGeometry.height || refGeometry.y != nextGeometry.y )
  717. return null ;
  718. return { 'refCell' : refCell, 'nextCell' : nextCell, 'tableMap' : tableMap } ;
  719. }
  720. FCKTableHandler.GetMergeDownTarget = function()
  721. {
  722. var cells = this.GetSelectedCells() ;
  723. if ( cells.length != 1 )
  724. return null ;
  725. var refCell = cells[0] ;
  726. var tableMap = this._CreateTableMap( refCell.parentNode.parentNode ) ;
  727. var rowIdx = refCell.parentNode.rowIndex ;
  728. var colIdx = this._GetCellIndexSpan( tableMap, rowIdx, refCell ) ;
  729. var newRowIdx = rowIdx + ( isNaN( refCell.rowSpan ) ? 1 : refCell.rowSpan ) ;
  730. if ( ! tableMap[newRowIdx] )
  731. return null ;
  732. var nextCell = tableMap[newRowIdx][colIdx] ;
  733. if ( ! nextCell )
  734. return null ;
  735. // The two cells must have the same horizontal geometry, otherwise merging does not makes sense.
  736. this._MarkCells( [refCell, nextCell], '_SizeTest' ) ;
  737. var refGeometry = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_SizeTest' ) ;
  738. var nextGeometry = this._GetMarkerGeometry( tableMap, newRowIdx, colIdx, '_SizeTest' ) ;
  739. this._UnmarkCells( [refCell, nextCell], '_SizeTest' ) ;
  740. if ( refGeometry.width != nextGeometry.width || refGeometry.x != nextGeometry.x )
  741. return null ;
  742. return { 'refCell' : refCell, 'nextCell' : nextCell, 'tableMap' : tableMap } ;
  743. }