%PDF- %PDF-
| Direktori : /www/varak.net/wiki.varak.net/extensions/VisualEditor/lib/ve/src/dm/ |
| Current File : /www/varak.net/wiki.varak.net/extensions/VisualEditor/lib/ve/src/dm/ve.dm.TableMatrix.js |
/**
* A helper class that allows random access to the table cells
* and introduces place-holders for fields occupied by spanning cells,
* making it a non-sparse representation of the sparse HTML model.
* This is essential for the implementation of table manipulations, such as row insertions or deletions.
*
* Example:
*
* <table>
* <tr><td rowspan=2>1</td><td colspan=2>2</td><td rowspan=2 colspan=2>3</td></tr>
* <tr><td>4</td><td>5</td></tr>
* </table>
*
* Visually this table would look like:
*
* -------------------
* | 1 | 2 | 3 |
* | |-------| |
* | | 4 | 5 | |
* -------------------
*
* The HTML model is sparse which makes it hard to read but also difficult to work with programmatically.
* The corresponding TableCellMatrix would look like:
*
* | C[1] | C[2] | P[2] | C[3] | P[3] |
* | P[1] | C[4] | C[5] | P[3] | P[3] |
*
* Where C[1] represents a Cell instance wrapping cell 1,
* and P[1] a PlaceHolder instance owned by that cell.
*
* @class
* @constructor
* @param {ve.dm.TableNode} tableNode Reference to a table instance
*/
ve.dm.TableMatrix = function VeDmTableMatrix( tableNode ) {
this.tableNode = tableNode;
// Do not access these directly as they get invalidated on structural changes
// Use the accessor methods instead.
this.matrix = null;
this.rowNodes = null;
};
/**
* Invalidates the matrix structure.
*
* This is called by ve.dm.TableNode on structural changes.
*/
ve.dm.TableMatrix.prototype.invalidate = function () {
this.matrix = null;
this.rowNodes = null;
};
/**
* Recreates the matrix structure.
*/
ve.dm.TableMatrix.prototype.update = function () {
var cellNode, cell,
rowSpan, colSpan, i, j, r, c,
matrix = [],
rowNodes = [],
iterator = this.tableNode.getIterator(),
row = -1,
col = -1;
// Handle row transitions
iterator.on( 'newRow', function ( rowNode ) {
row++;
col = -1;
// initialize a matrix row
matrix[ row ] = matrix[ row ] || [];
// store the row node
rowNodes.push( rowNode );
} );
// Iterates through all cells and stores the cells as well as
// so called placeholders into the matrix.
while ( ( cellNode = iterator.next() ) !== undefined ) {
col++;
// skip placeholders
while ( matrix[ row ][ col ] ) {
col++;
}
if ( !cellNode ) {
matrix[ row ][ col ] = null;
continue;
}
cell = new ve.dm.TableMatrixCell( cellNode, row, col );
// store the cell in the matrix
matrix[ row ][ col ] = cell;
// add place holders for spanned cells
rowSpan = cellNode.getRowspan();
colSpan = cellNode.getColspan();
if ( rowSpan === 1 && colSpan === 1 ) {
continue;
}
for ( i = 0; i < rowSpan; i++ ) {
for ( j = 0; j < colSpan; j++ ) {
if ( i === 0 && j === 0 ) {
continue;
}
r = row + i;
c = col + j;
// initialize the cell matrix row if not yet present
matrix[ r ] = matrix[ r ] || [];
matrix[ r ][ c ] = new ve.dm.TableMatrixCell( cellNode, r, c, cell );
}
}
}
this.matrix = matrix;
this.rowNodes = rowNodes;
};
/**
* Retrieves a single cell.
*
* @param {number} row Row index
* @param {number} col Column index
* @return {ve.dm.TableMatrixCell|undefined} Cell, or undefined if out of bounds
*/
ve.dm.TableMatrix.prototype.getCell = function ( row, col ) {
var matrix = this.getMatrix();
return matrix[ row ] ? matrix[ row ][ col ] : undefined;
};
/**
* Retrieves all cells of a column with given index.
*
* @param {number} col Column index
* @return {ve.dm.TableMatrixCell[]} The cells of a column
*/
ve.dm.TableMatrix.prototype.getColumn = function ( col ) {
var cells, row,
matrix = this.getMatrix();
cells = [];
for ( row = 0; row < matrix.length; row++ ) {
cells.push( matrix[ row ][ col ] );
}
return cells;
};
/**
* Retrieves all cells of a row with given index.
*
* @param {number} row Row index
* @return {ve.dm.TableMatrixCell[]} The cells of a row
*/
ve.dm.TableMatrix.prototype.getRow = function ( row ) {
var matrix = this.getMatrix();
return matrix[ row ];
};
/**
* Retrieves the row node of a row with given index.
*
* @param {number} row Row index
* @return {ve.dm.TableRowNode} Node at give index
*/
ve.dm.TableMatrix.prototype.getRowNode = function ( row ) {
var rowNodes = this.getRowNodes();
return rowNodes[ row ];
};
/**
* Provides a reference to the internal cell matrix.
*
* Note: this is primarily for internal use. Do not change the delivered matrix
* and do not store as it may be invalidated.
*
* @return {ve.dm.TableMatrixCell[][]} Table matrix
*/
ve.dm.TableMatrix.prototype.getMatrix = function () {
if ( !this.matrix ) {
this.update();
}
return this.matrix;
};
/**
* Provides a reference to the internal array of row nodes.
*
* Note: this is primarily for internal use. Do not change the delivered array
* and do not store it as it may be invalidated.
*
* @return {ve.dm.TableRowNode[]} Table row nodes
*/
ve.dm.TableMatrix.prototype.getRowNodes = function () {
if ( !this.rowNodes ) {
this.update();
}
return this.rowNodes;
};
/**
* Get number of rows in the table
*
* @return {number} Number of rows
*/
ve.dm.TableMatrix.prototype.getRowCount = function () {
return this.getMatrix().length;
};
/**
* Get number of columns in a row
*
* To get the number of columns in a table use #getMaxColCount
*
* @param {number} row Row to count columns in
* @return {number} Number of columns
*/
ve.dm.TableMatrix.prototype.getColCount = function ( row ) {
var matrix = this.getMatrix();
return matrix.length ? matrix[ row ].length : 0;
};
/**
* Get the maximum number of columns in a table
*
* This is required because in sparse tables the column count is variable.
*
* @return {number} Number of columns
*/
ve.dm.TableMatrix.prototype.getMaxColCount = function () {
var row, colCount = 0;
for ( row = this.getRowCount() - 1; row >= 0; row-- ) {
colCount = Math.max( colCount, this.getColCount( row ) );
}
return colCount;
};
/**
* Look up the matrix cell for a given cell node.
*
* @param {ve.dm.TableCellNode} cellNode Cell node
* @return {ve.dm.TableMatrixCell|null} The cell or null if not found
*/
ve.dm.TableMatrix.prototype.lookupCell = function ( cellNode ) {
var row, col, cols, rowCells,
matrix = this.getMatrix(),
rowNodes = this.getRowNodes();
row = rowNodes.indexOf( cellNode.getParent() );
if ( row < 0 ) {
return null;
}
rowCells = matrix[ row ];
for ( col = 0, cols = rowCells.length; col < cols; col++ ) {
if ( rowCells[ col ] && rowCells[ col ].node === cellNode ) {
return rowCells[ col ];
}
}
return null;
};
/**
* Finds the closest cell not being a placeholder for a given cell.
*
* @param {ve.dm.TableMatrixCell} cell Table cell
* @return {ve.dm.TableMatrixCell|null} Closest cell
*/
ve.dm.TableMatrix.prototype.findClosestCell = function ( cell ) {
var col, cols, rowCells,
matrix = this.getMatrix();
rowCells = matrix[ cell.row ];
for ( col = cell.col; col >= 0; col-- ) {
if ( !rowCells[ col ].isPlaceholder() ) {
return rowCells[ col ];
}
}
for ( col = cell.col + 1, cols = rowCells.length; col < cols; col++ ) {
if ( !rowCells[ col ].isPlaceholder() ) {
return rowCells[ col ];
}
}
return null;
};
/**
* An object wrapping a table cell node, augmenting it with row and column indexes.
*
* Cells which are occupied by another cell's with 'rowspan' or 'colspan' attributes are
* placeholders and have an owner property other than themselves.
* Placeholders are used to create a dense representation of the sparse HTML table model.
*
* @class
* @constructor
* @param {ve.dm.TableCellNode} node DM Node
* @param {number} row Row index
* @param {number} col Column index
* @param {ve.dm.TableMatrixCell} [owner] Owner cell if this is a placeholder
*/
ve.dm.TableMatrixCell = function VeDmTableMatrixCell( node, row, col, owner ) {
this.node = node;
this.row = row;
this.col = col;
this.key = row + '_' + col;
this.owner = owner || this;
// Used when moving cells
this.data = null;
};
/* Inheritance */
OO.initClass( ve.dm.TableMatrixCell );
/* Static Methods */
/**
* Comparison function for sorting cells in text flow order
*
* @param {ve.dm.TableMatrixCell} a First cell
* @param {ve.dm.TableMatrixCell} b Second cell
* @return {number} Positive, negative or zero, depending on relative position
*/
ve.dm.TableMatrixCell.static.sortDescending = function ( a, b ) {
if ( a.row !== b.row ) {
return b.row - a.row;
}
return b.col - a.col;
};
/* Methods */
/**
* Check if this cell is a placeholder
*
* @return {boolean} This cell is a placeholder
*/
ve.dm.TableMatrixCell.prototype.isPlaceholder = function () {
return this.owner !== this;
};
/**
* Get owner matrix cell
*
* @return {ve.dm.TableMatrixCell} Owner cell
*/
ve.dm.TableMatrixCell.prototype.getOwner = function () {
return this.owner;
};
/**
* Compare to another cell
*
* Cells are considered equal to their placeholders
*
* @param {ve.dm.TableMatrixCell} other Cell to compare
* @return {boolean} Cells are equal
*/
ve.dm.TableMatrixCell.prototype.equals = function ( other ) {
return this.getOwner().key === other.getOwner().key;
};