Add TableCaptionNode

Because we have a node for <table>, we also need one for <caption>,
otherwise we'll try to alienate it and fail.

Added the test case as a separate example document so Ed can use it
for his tests.

Removed test case asserting <caption> is alienated.

Change-Id: I3a917db58e6c0eb97899b214b07d01fc8d86b56d
This commit is contained in:
Roan Kattouw 2013-04-25 15:24:37 -07:00
parent af4868badc
commit c68765639a
6 changed files with 142 additions and 21 deletions

View file

@ -271,6 +271,7 @@ $wgResourceModules += array(
've/dm/nodes/ve.dm.ListNode.js',
've/dm/nodes/ve.dm.ParagraphNode.js',
've/dm/nodes/ve.dm.PreformattedNode.js',
've/dm/nodes/ve.dm.TableCaptionNode.js',
've/dm/nodes/ve.dm.TableCellNode.js',
've/dm/nodes/ve.dm.TableNode.js',
've/dm/nodes/ve.dm.TableRowNode.js',
@ -324,6 +325,7 @@ $wgResourceModules += array(
've/ce/nodes/ve.ce.ListNode.js',
've/ce/nodes/ve.ce.ParagraphNode.js',
've/ce/nodes/ve.ce.PreformattedNode.js',
've/ce/nodes/ve.ce.TableCaptionNode.js',
've/ce/nodes/ve.ce.TableCellNode.js',
've/ce/nodes/ve.ce.TableNode.js',
've/ce/nodes/ve.ce.TableRowNode.js',
@ -516,7 +518,6 @@ $wgResourceModules += array(
),
),
);
// Parsoid Wrapper API
$wgAutoloadClasses['ApiVisualEditor'] = $dir . 'ApiVisualEditor.php';
$wgAPIModules['visualeditor'] = 'ApiVisualEditor';

View file

@ -155,6 +155,7 @@ $html = file_get_contents( $page );
<script src="../../modules/ve/dm/nodes/ve.dm.ListNode.js"></script>
<script src="../../modules/ve/dm/nodes/ve.dm.ParagraphNode.js"></script>
<script src="../../modules/ve/dm/nodes/ve.dm.PreformattedNode.js"></script>
<script src="../../modules/ve/dm/nodes/ve.dm.TableCaptionNode.js"></script>
<script src="../../modules/ve/dm/nodes/ve.dm.TableCellNode.js"></script>
<script src="../../modules/ve/dm/nodes/ve.dm.TableNode.js"></script>
<script src="../../modules/ve/dm/nodes/ve.dm.TableRowNode.js"></script>
@ -208,6 +209,7 @@ $html = file_get_contents( $page );
<script src="../../modules/ve/ce/nodes/ve.ce.ListNode.js"></script>
<script src="../../modules/ve/ce/nodes/ve.ce.ParagraphNode.js"></script>
<script src="../../modules/ve/ce/nodes/ve.ce.PreformattedNode.js"></script>
<script src="../../modules/ve/ce/nodes/ve.ce.TableCaptionNode.js"></script>
<script src="../../modules/ve/ce/nodes/ve.ce.TableCellNode.js"></script>
<script src="../../modules/ve/ce/nodes/ve.ce.TableNode.js"></script>
<script src="../../modules/ve/ce/nodes/ve.ce.TableRowNode.js"></script>

View file

@ -0,0 +1,31 @@
/*!
* VisualEditor ContentEditable TableCaptionNode class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* ContentEditable table caption node.
*
* @class
* @extends ve.ce.BranchNode
* @constructor
* @param {ve.dm.TableCaptionNode} model Model to observe
*/
ve.ce.TableCaptionNode = function VeCeTableCaptionNode( model ) {
// Parent constructor
ve.ce.BranchNode.call( this, model, $( '<caption>' ) );
};
/* Inheritance */
ve.inheritClass( ve.ce.TableCaptionNode, ve.ce.BranchNode );
/* Static Properties */
ve.ce.TableCaptionNode.static.name = 'tableCaption';
/* Registration */
ve.ce.nodeFactory.register( ve.ce.TableCaptionNode );

View file

@ -0,0 +1,44 @@
/*!
* VisualEditor DataModel TableCaptionNode class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* DataModel table caption node.
*
* @class
* @extends ve.dm.BranchNode
* @constructor
* @param {ve.dm.BranchNode[]} [children] Child nodes to attach
* @param {Object} [element] Reference to element in linear model
*/
ve.dm.TableCaptionNode = function VeDmTableCaptionNode( children, element ) {
// Parent constructor
ve.dm.BranchNode.call( this, children, element );
};
/* Inheritance */
ve.inheritClass( ve.dm.TableCaptionNode, ve.dm.BranchNode );
/* Static Properties */
ve.dm.TableCaptionNode.static.name = 'tableCaption';
ve.dm.TableCaptionNode.static.parentNodeTypes = [ 'table' ];
ve.dm.TableCaptionNode.static.matchTagNames = [ 'caption' ];
ve.dm.TableCaptionNode.static.toDataElement = function () {
return { 'type': 'tableCaption' };
};
ve.dm.TableCaptionNode.static.toDomElements = function ( dataElement, doc ) {
return [ doc.createElement( 'caption' ) ];
};
/* Registration */
ve.dm.modelRegistry.register( ve.dm.TableCaptionNode );

View file

@ -570,6 +570,63 @@ ve.dm.example.withMetaMetaData = [
]
];
ve.dm.example.complexTableHtml = '<table><caption>Foo</caption><thead><tr><th>Bar</th></tr></thead>' +
'<tfoot><tr><td>Baz</td></tr></tfoot><tbody><tr><td>Quux</td><td>Whee</td></tr></tbody></table>';
ve.dm.example.complexTable = [
{ 'type': 'table' },
{ 'type': 'tableCaption' },
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
'F',
'o',
'o',
{ 'type': '/paragraph' },
{ 'type': '/tableCaption' },
{ 'type': 'tableSection', 'attributes': { 'style': 'header' } },
{ 'type': 'tableRow' },
{ 'type': 'tableCell', 'attributes': { 'style': 'header' } },
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
'B',
'a',
'r',
{ 'type': '/paragraph' },
{ 'type': '/tableCell' },
{ 'type': '/tableRow' },
{ 'type': '/tableSection' },
{ 'type': 'tableSection', 'attributes': { 'style': 'footer' } },
{ 'type': 'tableRow' },
{ 'type': 'tableCell', 'attributes': { 'style': 'data' } },
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
'B',
'a',
'z',
{ 'type': '/paragraph' },
{ 'type': '/tableCell' },
{ 'type': '/tableRow' },
{ 'type': '/tableSection' },
{ 'type': 'tableSection', 'attributes': { 'style': 'body' } },
{ 'type': 'tableRow' },
{ 'type': 'tableCell', 'attributes': { 'style': 'data' } },
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
'Q',
'u',
'u',
'x',
{ 'type': '/paragraph' },
{ 'type': '/tableCell' },
{ 'type': 'tableCell', 'attributes': { 'style': 'data' } },
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
'W',
'h',
'e',
'e',
{ 'type': '/paragraph' },
{ 'type': '/tableCell' },
{ 'type': '/tableRow' },
{ 'type': '/tableSection' },
{ 'type': '/table' }
];
/**
* Sample content data index.
*
@ -2370,26 +2427,6 @@ ve.dm.example.domToDataCases = {
{ 'type': '/paragraph' }
]
},
'context-sensitive nodes are alienated correctly': {
'html': '<table><caption>Foo</caption><tbody><tr><td>Bar</td></tr></tbody></table>',
'data': [
{ 'type': 'table' },
{ 'type': 'alienBlock', 'attributes': { 'html': '<caption>Foo</caption>' } },
{ 'type': '/alienBlock' },
{ 'type': 'tableSection', 'attributes': { 'style': 'body' } },
{ 'type': 'tableRow' },
{ 'type': 'tableCell', 'attributes': { 'style': 'data' } },
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
'B',
'a',
'r',
{ 'type': '/paragraph' },
{ 'type': '/tableCell' },
{ 'type': '/tableRow' },
{ 'type': '/tableSection' },
{ 'type': '/table' }
]
},
'whitespace before meta node in wrapping mode': {
'html': '<body><table><tbody><tr><td>Foo\n<meta property="mw:foo" content="bar" /></td></tr></tbody></table></body>',
'data': [
@ -2429,6 +2466,10 @@ ve.dm.example.domToDataCases = {
{ 'type': '/tableSection' },
{ 'type': '/table' }
]
},
'table with caption, head, foot and body': {
'html': ve.dm.example.complexTableHtml,
'data': ve.dm.example.complexTable
}
};

View file

@ -98,6 +98,7 @@
<script src="../../ve/dm/nodes/ve.dm.ListNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.ParagraphNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.PreformattedNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.TableCaptionNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.TableCellNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.TableNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.TableRowNode.js"></script>
@ -151,6 +152,7 @@
<script src="../../ve/ce/nodes/ve.ce.ListNode.js"></script>
<script src="../../ve/ce/nodes/ve.ce.ParagraphNode.js"></script>
<script src="../../ve/ce/nodes/ve.ce.PreformattedNode.js"></script>
<script src="../../ve/ce/nodes/ve.ce.TableCaptionNode.js"></script>
<script src="../../ve/ce/nodes/ve.ce.TableCellNode.js"></script>
<script src="../../ve/ce/nodes/ve.ce.TableNode.js"></script>
<script src="../../ve/ce/nodes/ve.ce.TableRowNode.js"></script>