%PDF- %PDF-
| Direktori : /www/varak.net/wiki.varak.net/extensions/VisualEditor/lib/ve/src/dm/nodes/ |
| Current File : /www/varak.net/wiki.varak.net/extensions/VisualEditor/lib/ve/src/dm/nodes/ve.dm.TableNode.js |
/*!
* VisualEditor DataModel TableNode class.
*
* @copyright 2011-2016 VisualEditor Team and others; see http://ve.mit-license.org
*/
/**
* DataModel table node.
*
* @class
* @extends ve.dm.BranchNode
*
* @constructor
* @param {ve.dm.Node[]} [children]
*/
ve.dm.TableNode = function VeDmTableNode() {
// Parent constructor
ve.dm.TableNode.super.apply( this, arguments );
// A dense representation of the sparse model to make manipulations
// in presence of spanning cells feasible.
this.matrix = new ve.dm.TableMatrix( this );
// Events
this.connect( this, { splice: 'onSplice' } );
};
/* Inheritance */
OO.inheritClass( ve.dm.TableNode, ve.dm.BranchNode );
/* Static Properties */
ve.dm.TableNode.static.name = 'table';
ve.dm.TableNode.static.childNodeTypes = [ 'tableSection', 'tableCaption' ];
ve.dm.TableNode.static.matchTagNames = [ 'table' ];
/* Methods */
/**
* Handle splicing of child nodes
*/
ve.dm.TableNode.prototype.onSplice = function () {
this.getMatrix().invalidate();
};
/**
* Get table matrix for this table node
*
* @return {ve.dm.TableMatrix} Table matrix
*/
ve.dm.TableNode.prototype.getMatrix = function () {
return this.matrix;
};
/**
* Get the table's caption node, if it exists
*
* @return {ve.dm.TableCaptionNode|null} The table's caption node, or null if not found
*/
ve.dm.TableNode.prototype.getCaptionNode = function () {
var i, l;
for ( i = 0, l = this.children.length; i < l; i++ ) {
if ( this.children[ i ] instanceof ve.dm.TableCaptionNode ) {
return this.children[ i ];
}
}
return null;
};
/**
* Provides a cell iterator that allows convenient traversal regardless of
* the structure with respect to sections.
*
* @return {ve.dm.TableNodeCellIterator}
*/
ve.dm.TableNode.prototype.getIterator = function () {
return new ve.dm.TableNodeCellIterator( this );
};
/* Registration */
ve.dm.modelRegistry.register( ve.dm.TableNode );
/**
* A helper class to iterate over the cells of a table node.
*
* It provides a unified interface to iterate cells in presence of table sections,
* e.g., providing consecutive row indexes.
*
* @class
* @mixins OO.EventEmitter
*
* @constructor
* @param {ve.dm.TableNode} tableNode Table node to iterate through
*/
ve.dm.TableNodeCellIterator = function VeDmTableNodeCellIterator( tableNode ) {
// Mixin constructors
OO.EventEmitter.call( this );
this.table = tableNode;
this.sectionIndex = 0;
this.rowIndex = 0;
this.cellIndex = 0;
this.sectionCount = this.table.children.length;
this.rowCount = 0;
this.cellCount = 0;
this.sectionNode = null;
this.rowNode = null;
this.cellNode = null;
this.finished = false;
};
/* Inheritance */
OO.mixinClass( ve.dm.TableNodeCellIterator, OO.EventEmitter );
/* Events */
/**
* @event newSection
* @param {ve.dm.TableSectionNode} node Table section node
*/
/**
* @event newRow
* @param {ve.dm.TableRowNode} node Table row node
*/
/* Methods */
/**
* Check if the iterator has finished iterating over the cells of a table node.
*
* @return {boolean} Iterator is finished
*/
ve.dm.TableNodeCellIterator.prototype.isFinished = function () {
return this.finished;
};
/**
* Get the next cell node
*
* @return {ve.dm.TableCellNode|null|undefined} Next cell node, null if a not a table cell, or undefined if at the end
* @throws {Error} TableNodeCellIterator has no more cells left.
*/
ve.dm.TableNodeCellIterator.prototype.next = function () {
if ( this.isFinished() ) {
throw new Error( 'TableNodeCellIterator has no more cells left.' );
}
this.nextCell( this );
return this.cellNode;
};
/**
* Move to the next table section
*
* @fires newSection
*/
ve.dm.TableNodeCellIterator.prototype.nextSection = function () {
var sectionNode;
// If there are no sections left, finish
if ( this.sectionIndex >= this.sectionCount ) {
this.finished = true;
this.sectionNode = undefined;
return;
}
// Get the next node and make sure it's a section node (and not an alien node)
sectionNode = this.table.children[ this.sectionIndex ];
this.sectionIndex++;
this.rowIndex = 0;
if ( sectionNode instanceof ve.dm.TableSectionNode ) {
this.sectionNode = sectionNode;
this.rowCount = this.sectionNode.children.length;
this.emit( 'newSection', this.sectionNode );
} else {
this.nextSection();
return;
}
};
/**
* Move to the next table row
*
* @fires newRow
*/
ve.dm.TableNodeCellIterator.prototype.nextRow = function () {
var rowNode;
// If there are no rows left, go to the next section
if ( this.rowIndex >= this.rowCount ) {
this.nextSection();
if ( this.isFinished() ) {
this.rowNode = undefined;
return;
}
}
// Get the next node and make sure it's a row node (and not an alien node)
rowNode = this.sectionNode.children[ this.rowIndex ];
this.rowIndex++;
this.cellIndex = 0;
if ( rowNode instanceof ve.dm.TableRowNode ) {
this.rowNode = rowNode;
this.cellCount = this.rowNode.children.length;
this.emit( 'newRow', this.rowNode );
} else {
this.nextRow();
return;
}
};
/**
* Move to the next table cell
*/
ve.dm.TableNodeCellIterator.prototype.nextCell = function () {
var cellNode;
// For the first read, sectionNode and rowNode will be empty
if ( !this.sectionNode ) {
this.nextSection();
}
if ( !this.rowNode ) {
this.nextRow();
}
// If there are no cells left, go to the next row
if ( this.cellIndex >= this.cellCount ) {
this.nextRow();
// If calling next row finished the iterator, clear and return
if ( this.isFinished() ) {
this.cellNode = undefined;
return;
}
}
// Get the next node and make sure it's a cell node (and not an alien node)
cellNode = this.rowNode.children[ this.cellIndex ];
this.cellNode = cellNode && cellNode.isCellable() ? cellNode : null;
this.cellIndex++;
};