`

excel的简单js实现

阅读更多

 var TableApi; 
 (function () { 
     var MyDom = Helper.Dom; 
     var MyCore = Helper.Core; 
  
     TableApi = { 
         /**
          * 获取table元素的单元格分布矩阵
          * @param table
          */ 
         getMatrix : function (table) { 
             var matrix = []; 
             for (var rowIndex = 0, rCnt = table.rows.length; rowIndex < rCnt; rowIndex++) { 
                 if (!matrix[rowIndex]) { 
                     matrix[rowIndex] = []; 
                 } 
                 for (var cellIndex = 0, cCnt = table.rows[rowIndex].cells.length; cellIndex < cCnt; cellIndex++) { 
                     var columnIndex = cellIndex; 
                 //In case there's are any horizontal or vertical spans before this cell 
                     while (matrix[rowIndex][columnIndex]) { 
                         columnIndex++; 
                     } 
  
                     var cell = table.rows[rowIndex].cells[cellIndex]; 
  
                 //Fill the corresponding matrix points 
                     for (var i = 0; i < cell.rowSpan; i++) { 
                         if (!matrix[rowIndex + i]) { 
                             matrix[rowIndex + i] = []; 
                         } 
                         for (var j = 0; j < cell.colSpan; j++) { 
                             matrix[rowIndex + i][columnIndex + j] = cell; 
                         } 
                     } 
                 } 
             } 
             return matrix; 
         }, 
         /**
          * 合并单元格分布矩阵中选中的单元格
          * @param matrix
          */ 
         merge : function (matrix) { 
             var maxRowIndex = 0; 
             var minRowIndex = matrix.length - 1; 
             var maxColumnIndex = 0; 
             var minColumnIndex = matrix[0].length - 1; 
  
             var rowIndex, columnIndex, rCnt, cCnt; 
  
         //decide if selected cells region is mergable 
             for (rowIndex = 0,rCnt = matrix.length; rowIndex < rCnt; rowIndex++) { 
                 for (columnIndex = 0,cCnt = matrix[0].length; columnIndex < cCnt; columnIndex++) { 
                     if ($(matrix[rowIndex][columnIndex]).hasClass('selected')) { 
                         if (rowIndex > maxRowIndex) { 
                             maxRowIndex = rowIndex; 
                         } 
                         if (rowIndex < minRowIndex) { 
                             minRowIndex = rowIndex; 
                         } 
                         if (columnIndex > maxColumnIndex) { 
                             maxColumnIndex = columnIndex; 
                         } 
                         if (columnIndex < minColumnIndex) { 
                             minColumnIndex = columnIndex; 
                         } 
                     } 
                 } 
             } 
  
             var mergable = true; 
             for (rowIndex = minRowIndex; rowIndex <= maxRowIndex && mergable; rowIndex++) { 
                 for (columnIndex = minColumnIndex; columnIndex <= maxColumnIndex; columnIndex++) { 
                     if (!$(matrix[rowIndex][columnIndex]).hasClass('selected')) { 
                         mergable = false; 
                         break; 
                     } 
                 } 
             } 
  
             if (mergable) { 
                 //then merge 
                 var cellToMergeInto = matrix[minRowIndex][minColumnIndex]; 
                 for (rowIndex = minRowIndex; rowIndex <= maxRowIndex; rowIndex++) { 
                     for (columnIndex = minColumnIndex; columnIndex <= maxColumnIndex; columnIndex++) { 
                         var cell = matrix[rowIndex][columnIndex]; 
                         if (cell !== cellToMergeInto) { 
                             for (var i = 0; i < cell.rowSpan; i++) { 
                                 for (var j = 0; j < cell.colSpan; j++) { 
                                     matrix[rowIndex + i][columnIndex + j] = cellToMergeInto; 
                                 } 
                             } 
                             MyDom.removeEl(cell); 
                         } 
                     } 
                 } 
  
                 cellToMergeInto.colSpan = (maxColumnIndex - minColumnIndex) + 1; 
                 cellToMergeInto.rowSpan = (maxRowIndex - minRowIndex) + 1; 
  
                 this.cleanUpEmptyRowsAndColumns(matrix); 
             } 
  
             return mergable; 
         }, 
         /**
          * 在单元格分布矩阵中指定行中搜索指定列的前一个单元格
          * @param matrix
          * @param rowIndex
          * @param columnIndex
          */ 
         searchForPreviousCellInRow : function (matrix, rowIndex, columnIndex) { 
             var columnIndexForPreviousCell = columnIndex; 
             var previousCell = null; 
             do{ 
                 columnIndexForPreviousCell -= 1; 
                 previousCell = matrix[rowIndex][columnIndexForPreviousCell]; 
             } 
             while (previousCell && (previousCell.parentNode.rowIndex !== rowIndex)); 
  
             return previousCell; 
         }, 
         /**
          * 还原合并的单元格
          * @param cell
          */ 
         revertMerged : function (cell) { 
             var table = MyDom.searchUpByTagName(cell, 'TABLE'); 
             var matrix = this.getMatrix(table); 
             var rowIndex = cell.parentNode.rowIndex; 
             var columnIndex = matrix[rowIndex].indexOf(cell); 
             var jCell = $(cell); 
  
             var tableApi = this; 
  
             MyCore.repeat(cell.colSpan - 1, function () { 
                 jCell.after('<td>'); 
             }); 
  
             MyCore.repeat(cell.rowSpan - 1, function (time) { 
                 var previousCell = tableApi.searchForPreviousCellInRow(matrix, rowIndex + time, columnIndex); 
  
                 var task = null; 
                 if (previousCell) { 
                     var jPreviousCell = $(previousCell); 
                     task = function () { 
                         jPreviousCell.after('<td>'); 
                     }; 
                 } 
                 else { 
                     var jRow = $(table.rows[rowIndex + time]); 
                     task = function () { 
                         jRow.prepend('<td>'); 
                     }; 
                 } 
  
                 MyCore.repeat(cell.colSpan, task); 
             }); 
  
             cell.colSpan = cell.rowSpan = 1; 
         }, 
         /**
          * 清理单元格分布矩阵中的空行空列
          * @param matrix
          * @requires the matrix must reflect the current state of the table
          */ 
         cleanUpEmptyRowsAndColumns : function (matrix) { 
             var table = matrix[0][0].parentNode.parentNode.parentNode; 
  
             var rowIndex, columnIndex, cell, cellToCollapse<script src="/javascripts/tinymce/themes/advanced/langs/zh.js" type="text/javascript"><!--mce:0--></script><script src="/javascripts/tinymce/plugins/javaeye/langs/zh.js" type="text/javascript"><!--mce:1--></script>, rCnt, cCnt; 
  
             cCnt = matrix[0].length; 
             //clean up empty rows 
             for (rowIndex = 0,rCnt = matrix.length; rowIndex < rCnt; rowIndex++) { 
                 var isEmptyRow = true; 
                 for (columnIndex = 0; columnIndex < cCnt; columnIndex++) { 
                     cell = matrix[rowIndex][columnIndex]; 
                     if (cell.rowSpan === 1 || cell.parentNode.rowIndex === rowIndex) { 
                         isEmptyRow = false; 
                         break; 
                     } 
                 } 
                 if (!isEmptyRow) { 
                     continue; 
                 } 
  
             //recalculate the rowspan 
                 columnIndex = 0; 
                 do{ 
                     cellToCollapse = matrix[rowIndex][columnIndex]; 
                     cellToCollapse.rowSpan -= 1; 
                     columnIndex += cellToCollapse.colSpan; 
                 } 
                 while (columnIndex < cCnt); 
  
             //remove empty tr element 
                 var row = table.rows[rowIndex]; 
                 MyDom.removeEl(row); 
  
             //remove empty row from matrix 
                 for (var i = rowIndex, iLen = rCnt - 1; i < iLen; i++) { 
                     matrix[i] = matrix[i + 1]; 
                 } 
                 matrix.length -= 1; 
                 rCnt--; 
  
             //cuz the original next row is now the current row 
                 rowIndex--; 
             } 
  
         //clean up empty columns 
             for (columnIndex = 0; columnIndex < cCnt; columnIndex++) { 
                 var isEmptyColumn = true; 
                 for (rowIndex = 0; rowIndex < rCnt; rowIndex++) { 
                     cell = matrix[rowIndex][columnIndex]; 
                     if (cell.colSpan === 1 || matrix[rowIndex][columnIndex + cell.colSpan - 1] === cell) { 
                         isEmptyColumn = false; 
                         break; 
                     } 
                 } 
  
                 if (!isEmptyColumn) { 
                     continue; 
                 } 
  
             //recalculate the colspan 
                 rowIndex = 0; 
                 do{ 
                     cellToCollapse = matrix[rowIndex][columnIndex]; 
                     cellToCollapse.colSpan -= 1; 
                     rowIndex += cellToCollapse.rowSpan; 
                 } 
                 while (rowIndex < rCnt); 
  
             //remove empty column from matrix 
                 for (rowIndex = 0; rowIndex < rCnt; rowIndex++) { 
                     for (var j = columnIndex, jLen = cCnt - 1; j < jLen; j++) { 
                         matrix[rowIndex][j] = matrix[rowIndex][j + 1]; 
                     } 
                     matrix[rowIndex].length -= 1; 
                 } 
                 cCnt--; 
  
             //remove corresponding col from colgroup if one exists 
                 var colGroup = $('colgroup', table).get(0); 
                 if (colGroup && colGroup.parentNode === table) { 
                     MyDom.removeEl($('col:eq(' + columnIndex + ')', colGroup).get(0)); 
                 } 
  
             //cuz the original next column is now the current column 
                 columnIndex--; 
             } 
         }, 
         /**
          * 根据指定的单元格和坐标获取在单元格分布矩阵中的精确位置
          * @param matrix
          * @param cell
          * @param pageX
          * @param pageY
          */ 
         getAccuratePositionInMatrix : function (matrix, cell, pageX, pageY) { 
             var rowIndex = -1; 
             var columnIndex = -1; 
  
             var found, i, j, jCell, offset, iLen; 
  
             if (cell.colSpan === 1) { 
                 columnIndex = matrix[cell.parentNode.rowIndex].indexOf(cell); 
             } 
             else { 
                 var firstApperanceColumnIndex = matrix[cell.parentNode.rowIndex].indexOf(cell); 
                 found = false; 
  
             //search for a single-column cell within the same column as the multi-column cell, which cuts through pageX horizontally. 
                 for (j = firstApperanceColumnIndex; !found && j < firstApperanceColumnIndex + cell.colSpan; j++) { 
                     for (i = 0,iLen = matrix.length; i < iLen; i++) { 
                         if (matrix[i][j].colSpan !== 1) { 
                             continue; 
                         } 
  
                         jCell = $(matrix[i][j]); 
                         offset = jCell.offset(); 
                         if (offset.left <= pageX && offset.left + jCell.width() >= pageX) { 
                             columnIndex = j; 
                             found = true; 
                         } 
                         break; 
                     } 
                 } 
  
                 if (!found) { 
                     columnIndex = firstApperanceColumnIndex; 
                 } 
             } 
  
             if (cell.rowSpan === 1) { 
                 rowIndex = cell.parentNode.rowIndex; 
             } 
             else { 
                 found = false; 
                 var jLen = matrix[0].length; 
             //search for a single-row cell within the same row as the multi-row cell, which cuts through pageY vertically. 
                 for (i = cell.parentNode.rowIndex; !found && i < cell.parentNode.rowIndex + cell.rowSpan; i++) { 
                     for (j = 0; j < jLen; j++) { 
                         if (matrix[i][j].rowSpan !== 1) { 
                             continue; 
                         } 
  
                         jCell = $(matrix[i][j]); 
                         offset = jCell.offset(); 
                         if (offset.top <= pageY && offset.top + jCell.height() >= pageY) { 
                             rowIndex = i; 
                             found = true; 
                         } 
                         break; 
                     } 
                 } 
  
                 if (!found) { 
                     rowIndex = cell.parentNode.rowIndex; 
                 } 
             } 
  
             return { 
                 rowIndex : rowIndex, 
                 columnIndex : columnIndex 
             }; 
         }, 
         /**
          * 重设列宽度
          * @param table
          * @param columnIndex
          * @param width
          */ 
         resizeColumn : function (table, columnIndex, width) { 
             //Notice that IE6 has problem with applying column width solely by col element. Set table-layout to fixed will solve this problem. 
             $('colgroup:first col:eq(' + columnIndex + ')', table).css('width', width); 
         }, 
         /**
          * 重设行高度
          * @param table
          * @param rowIndex
          * @param height
          */ 
         resizeRow : function (table, rowIndex, height) { 
             $('tbody:eq(0) > tr:eq(' + rowIndex + ')', table).css('height', height); 
         }, 
         /**
          * 计算获得table元素的行和列的位置偏移量
          * @param matrix
          */ 
         getOffsetsToTableForColumnAndRow : function (matrix) { 
             var columnOffsets = []; // the offset for the left edge of the columns 
             var rowOffsets = []; //the offset for the top edge of the rows 
  
             var tableOffset = $(MyDom.searchUpByTagName(matrix[0][0], 'TABLE')).offset(); 
  
             var cell; 
  
             var 
                     rCnt = matrix.length, 
                     cCnt = matrix[0].length; 
             for (var rowIndex = 0; rowIndex < rCnt; rowIndex++) { 
                 for (var columnIndex = 0; columnIndex < cCnt; columnIndex++) { 
                     if (!columnOffsets[columnIndex]) { 
                         cell = matrix[rowIndex][columnIndex]; 
                         if (cell.colSpan === 1 || matrix[rowIndex][columnIndex + cell.colSpan - 1] === cell) { 
                             columnOffsets[columnIndex] = $(cell).offset().left - tableOffset.left; 
                         } 
                     } 
  
                     if (!rowOffsets[rowIndex]) { 
                         cell = matrix[rowIndex][columnIndex]; 
                         if (cell.rowSpan === 1 || cell.parentNode.rowIndex === rowIndex) { 
                             rowOffsets[rowIndex] = $(cell).offset().top - tableOffset.top; 
                         } 
                     } 
                 } 
             } 
  
             return { 
                 columnOffsets : columnOffsets, 
                 rowOffsets : rowOffsets 
             }; 
         }, 
         /**
          * 在单元格所在列右边插入新列
          * @param cell
          * @param width
          */ 
         insertColumnAfterCell : function (cell, width) { 
             var table = MyDom.searchUpByTagName(cell, 'TABLE'); 
             var matrix = this.getMatrix(table); 
             var columnIndex = matrix[cell.parentNode.rowIndex].indexOf(cell) + cell.colSpan - 1; 
  
         //if the current column isn't the last column 
             if (columnIndex < matrix[0].length - 1) { 
                 for (var rowIndex = 0, rCnt = matrix.length; rowIndex < rCnt; rowIndex++) { 
                     var currentCell = matrix[rowIndex][columnIndex]; 
  
                     if (currentCell !== matrix[rowIndex][columnIndex + 1]) { 
                         $(currentCell).after('<td>'); 
  
                         for (var i = 1; i < currentCell.rowSpan; i++) { 
                             var previousCell = this.searchForPreviousCellInRow(matrix, rowIndex + i, columnIndex); 
  
                             if (previousCell) { 
                                 $(previousCell).after('<td>'); 
                             } 
                             else { 
                                 $(table.rows[rowIndex + i]).prepend('<td>'); 
                             } 
                         } 
                     } 
                     else { 
                         currentCell.colSpan++; 
                     } 
  
                     rowIndex += currentCell.rowSpan - 1; 
                 } 
             } 
             else { 
                 MyCore.each(table.rows, function (row) { 
                     $(row).append('<td>'); 
                 }); 
             } 
  
             $('col:eq(' + columnIndex + ')', table).after('<col style="width:' + width + 'px" />'); 
         }, 
         /**
          * 在单元格所在列左边插入新列
          * @param cell
          * @param width
          */ 
         insertColumnBeforeCell : function (cell, width) { 
             var table = MyDom.searchUpByTagName(cell, 'TABLE'); 
             var matrix = this.getMatrix(table); 
             var columnIndex = matrix[cell.parentNode.rowIndex].indexOf(cell); 
  
         //if the current column isn't the first column 
             if (columnIndex > 0) { 
                 for (var rowIndex = 0, rCnt = matrix.length; rowIndex < rCnt; rowIndex++) { 
                     var currentCell = matrix[rowIndex][columnIndex]; 
  
                     if (currentCell !== matrix[rowIndex][columnIndex - 1]) { 
                         $(currentCell).before('<td>'); 
  
                         for (var i = 1; i < currentCell.rowSpan; i++) { 
                             var previousCell = this.searchForPreviousCellInRow(matrix, rowIndex + i, columnIndex); 
  
                             if (previousCell) { 
                                 $(previousCell).after('<td>'); 
                             } 
                             else { 
                                 $(table.rows[rowIndex + i]).prepend('<td>'); 
                             } 
                         } 
                     } 
                     else { 
                         currentCell.colSpan++; 
                     } 
  
                     rowIndex += currentCell.rowSpan - 1; 
                 } 
             } 
             else { 
                 MyCore.each(table.rows, function (row) { 
                     $(row).prepend('<td>'); 
                 }); 
             } 
  
             $('col:eq(' + columnIndex + ')', table).before('<col style="width:' + width + 'px" />'); 
         }, 
         /**
          * 在单元格所在行下面插入新行
          * @param cell
          * @param height
          */ 
         insertRowBelowCell : function (cell, height) { 
             var table = MyDom.searchUpByTagName(cell, 'TABLE'); 
             var matrix = this.getMatrix(table); 
             var rowIndex = cell.parentNode.rowIndex + cell.rowSpan - 1; 
  
             var newRow = '<tr style="height:' + height + 'px">'; 
  
             if (rowIndex < matrix.length - 1) { 
                 for (var columnIndex = 0, cCnt = matrix[rowIndex].length; columnIndex < cCnt; columnIndex++) { 
                     var currentCell = matrix[rowIndex][columnIndex]; 
                     if (currentCell !== matrix[rowIndex + 1][columnIndex]) { 
                         MyCore.repeat(currentCell.colSpan, function () { 
                             newRow += '<td></td>'; 
                         }); 
                     } 
                     else { 
                         currentCell.rowSpan++; 
                     } 
  
                     columnIndex += currentCell.colSpan - 1; 
                 } 
             } 
             else { 
                 MyCore.repeat(matrix[rowIndex].length, function () { 
                     newRow += '<td></td>'; 
                 }); 
             } 
  
             newRow += '</tr>'; 
  
             $(table.rows[rowIndex]).after(newRow); 
         }, 
         /**
          * 在单元格所在行上面插入新行
          * @param cell
          * @param height
          */ 
         insertRowAboveCell : function (cell, height) { 
             var table = MyDom.searchUpByTagName(cell, 'TABLE'); 
             var matrix = this.getMatrix(table); 
             var rowIndex = cell.parentNode.rowIndex; 
  
             var newRow = '<tr style="height:' + height + 'px">'; 
  
             if (rowIndex > 0) { 
                 for (var columnIndex = 0, cCnt = matrix[rowIndex].length; columnIndex < cCnt; columnIndex++) { 
                     var currentCell = matrix[rowIndex][columnIndex]; 
                     if (currentCell !== matrix[rowIndex - 1][columnIndex]) { 
                         MyCore.repeat(currentCell.colSpan, function () { 
                             newRow += '<td></td>'; 
                         }); 
                     } 
                     else { 
                         currentCell.rowSpan++; 
                     } 
  
                     columnIndex += currentCell.colSpan - 1; 
                 } 
             } 
             else { 
                 MyCore.repeat(matrix[rowIndex].length, function () { 
                     newRow += '<td></td>'; 
                 }); 
             } 
  
             newRow += '</tr>'; 
  
             $(table.rows[rowIndex]).before(newRow); 
         }, 
         /**
          * 按照源table的尺寸更新目标table
          * @param srcTable
          * @param targetTable
          */ 
         copySize : function (srcTable, targetTable) { 
             var targetCols = $('colgroup:first col', targetTable).get(); 
             $('colgroup:first col', srcTable).each(function (index) { 
                 targetCols[index].style.width = this.style.width; 
             }); 
  
             var targetRows = $('tbody:first tr', targetTable).get(); 
             $('tbody:first tr', srcTable).each(function (index) { 
                 targetRows[index].style.height = this.style.height; 
             }); 
         }, 
         /**
          * 移除单元格所在的行
          * @param cell
          */ 
         removeRow : function (cell) { 
             if (cell.rowSpan !== 1) { 
                 throw 'The cell has to only belong to one row!'; 
             } 
  
             var table = MyDom.searchUpByTagName(cell, 'TABLE'); 
  
             if (table.rows.length === 1) { 
                 throw '这是表中唯一的一行,不允许删除!'; 
             } 
  
             var matrix = this.getMatrix(table); 
  
             var rowIndex = cell.parentNode.rowIndex; 
  
             for (var columnIndex = 0, cCnt = matrix[rowIndex].length; columnIndex < cCnt; columnIndex++) { 
                 var currentCell = matrix[rowIndex][columnIndex]; 
                 if (currentCell.rowSpan > 1) { 
                     currentCell.rowSpan -= 1; 
  
                     if (currentCell.parentNode.rowIndex === rowIndex) { 
                         var cellToInsertAfter = null; 
                         for (var columnIndexOfTheRowBelow = columnIndex - 1; columnIndexOfTheRowBelow >= 0; columnIndexOfTheRowBelow--) { 
                             var cellOfTheRowBelow = matrix[rowIndex + 1][columnIndexOfTheRowBelow]; 
                             if (cellOfTheRowBelow.rowSpan === 1 || cellOfTheRowBelow.parentNode.rowIndex === rowIndex + 1) { 
                                 cellToInsertAfter = cellOfTheRowBelow; 
                                 break; 
                             } 
                         } 
  
                         var rowBelow = currentCell.parentNode.nextSibling; 
                         if (cellToInsertAfter) { 
                             rowBelow.insertBefore(currentCell, cellToInsertAfter.nextSibling); 
                         } 
                         else { 
                             rowBelow.insertBefore(currentCell, rowBelow.firstChild); 
                         } 
                     } 
                 } 
  
                 columnIndex += currentCell.colSpan - 1; 
             } 
  
             MyDom.removeEl(table.rows[rowIndex]); 
  
             this.cleanUpEmptyRowsAndColumns(this.getMatrix(table)); 
         }, 
         /**
          * 移除单元格所在的列
          * @param cell
          */ 
         removeColumn : function (cell) { 
             if (cell.colSpan !== 1) { 
                 throw 'The cell has to only belong to one column!'; 
             } 
  
             var table = MyDom.searchUpByTagName(cell, 'TABLE'); 
  
             var matrix = this.getMatrix(table); 
             if (matrix[0].length === 1) { 
                 throw '这是该表唯一的一列,不允许删除!'; 
             } 
  
             var columnIndex = matrix[cell.parentNode.rowIndex].indexOf(cell); 
  
             for (var rowIndex = 0, rCnt = matrix.length; rowIndex < rCnt; rowIndex++) { 
                 var currentCell = matrix[rowIndex][columnIndex]; 
                 if (currentCell.colSpan > 1) { 
                     currentCell.colSpan -= 1; 
                 } 
                 else { 
                     MyDom.removeEl(currentCell); 
                 } 
  
                 rowIndex += currentCell.rowSpan - 1; 
             } 
  
             MyDom.removeEl($('colgroup:first col:eq(' + columnIndex + ')', table).get(0)); 
  
             this.cleanUpEmptyRowsAndColumns(this.getMatrix(table)); 
         } 
     }; 
 })();

0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics