downcasttable.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /**
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
  6. import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
  7. import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  8. import downcastTable from '../../src/converters/downcasttable';
  9. describe( 'downcastTable()', () => {
  10. let editor, model, viewDocument;
  11. beforeEach( () => {
  12. return VirtualTestEditor.create()
  13. .then( newEditor => {
  14. editor = newEditor;
  15. model = editor.model;
  16. viewDocument = editor.editing.view;
  17. const conversion = editor.conversion;
  18. const schema = model.schema;
  19. schema.register( 'table', {
  20. allowWhere: '$block',
  21. allowAttributes: [ 'headingRows', 'headingColumns' ],
  22. isBlock: true,
  23. isObject: true
  24. } );
  25. schema.register( 'tableRow', {
  26. allowIn: 'table',
  27. allowAttributes: [],
  28. isBlock: true,
  29. isLimit: true
  30. } );
  31. schema.register( 'tableCell', {
  32. allowIn: 'tableRow',
  33. allowContentOf: '$block',
  34. allowAttributes: [ 'colspan', 'rowspan' ],
  35. isBlock: true,
  36. isLimit: true
  37. } );
  38. conversion.for( 'downcast' ).add( downcastTable() );
  39. conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
  40. conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
  41. } );
  42. } );
  43. it( 'should create table with tbody', () => {
  44. setModelData( model,
  45. '<table>' +
  46. '<tableRow><tableCell></tableCell></tableRow>' +
  47. '</table>'
  48. );
  49. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  50. '<table>' +
  51. '<tbody>' +
  52. '<tr><td></td></tr>' +
  53. '</tbody>' +
  54. '</table>'
  55. );
  56. } );
  57. it( 'should create table with tbody and thead', () => {
  58. setModelData( model,
  59. '<table headingRows="1">' +
  60. '<tableRow><tableCell>1</tableCell></tableRow>' +
  61. '<tableRow><tableCell>2</tableCell></tableRow>' +
  62. '</table>'
  63. );
  64. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  65. '<table>' +
  66. '<thead>' +
  67. '<tr><th>1</th></tr>' +
  68. '</thead>' +
  69. '<tbody>' +
  70. '<tr><td>2</td></tr>' +
  71. '</tbody>' +
  72. '</table>'
  73. );
  74. } );
  75. it( 'should create table with thead', () => {
  76. setModelData( model,
  77. '<table headingRows="2">' +
  78. '<tableRow><tableCell>1</tableCell></tableRow>' +
  79. '<tableRow><tableCell>2</tableCell></tableRow>' +
  80. '</table>'
  81. );
  82. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  83. '<table>' +
  84. '<thead>' +
  85. '<tr><th>1</th></tr>' +
  86. '<tr><th>2</th></tr>' +
  87. '</thead>' +
  88. '</table>'
  89. );
  90. } );
  91. it( 'should create table with heading columns and rows', () => {
  92. setModelData( model,
  93. '<table headingColumns="3" headingRows="1">' +
  94. '<tableRow>' +
  95. '<tableCell>11</tableCell><tableCell>12</tableCell><tableCell>13</tableCell><tableCell>14</tableCell>' +
  96. '</tableRow>' +
  97. '<tableRow>' +
  98. '<tableCell>21</tableCell><tableCell>22</tableCell><tableCell>23</tableCell><tableCell>24</tableCell>' +
  99. '</tableRow>' +
  100. '</table>'
  101. );
  102. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  103. '<table>' +
  104. '<thead>' +
  105. '<tr><th>11</th><th>12</th><th>13</th><th>14</th></tr>' +
  106. '</thead>' +
  107. '<tbody>' +
  108. '<tr><th>21</th><th>22</th><th>23</th><td>24</td></tr>' +
  109. '</tbody>' +
  110. '</table>'
  111. );
  112. } );
  113. it( 'should be possible to overwrite', () => {
  114. editor.conversion.elementToElement( { model: 'tableRow', view: 'tr' } );
  115. editor.conversion.elementToElement( { model: 'tableCell', view: 'td' } );
  116. editor.conversion.for( 'downcast' ).add( dispatcher => {
  117. dispatcher.on( 'insert:table', ( evt, data, conversionApi ) => {
  118. conversionApi.consumable.consume( data.item, 'insert' );
  119. const tableElement = conversionApi.writer.createContainerElement( 'table', { foo: 'bar' } );
  120. const viewPosition = conversionApi.mapper.toViewPosition( data.range.start );
  121. conversionApi.mapper.bindElements( data.item, tableElement );
  122. conversionApi.writer.insert( viewPosition, tableElement );
  123. }, { priority: 'high' } );
  124. } );
  125. setModelData( model,
  126. '<table>' +
  127. '<tableRow><tableCell></tableCell></tableRow>' +
  128. '</table>'
  129. );
  130. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  131. '<table foo="bar">' +
  132. '<tr><td></td></tr>' +
  133. '</table>'
  134. );
  135. } );
  136. describe( 'headingColumns attribute', () => {
  137. it( 'should mark heading columns table cells', () => {
  138. setModelData( model,
  139. '<table headingColumns="2">' +
  140. '<tableRow><tableCell>11</tableCell><tableCell>12</tableCell><tableCell>13</tableCell></tableRow>' +
  141. '<tableRow><tableCell>21</tableCell><tableCell>22</tableCell><tableCell>23</tableCell></tableRow>' +
  142. '</table>'
  143. );
  144. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  145. '<table>' +
  146. '<tbody>' +
  147. '<tr><th>11</th><th>12</th><td>13</td></tr>' +
  148. '<tr><th>21</th><th>22</th><td>23</td></tr>' +
  149. '</tbody>' +
  150. '</table>'
  151. );
  152. } );
  153. it( 'should mark heading columns table cells when one has colspan attribute', () => {
  154. setModelData( model,
  155. '<table headingColumns="3">' +
  156. '<tableRow>' +
  157. '<tableCell>11</tableCell><tableCell>12</tableCell><tableCell>13</tableCell><tableCell>14</tableCell>' +
  158. '</tableRow>' +
  159. '<tableRow><tableCell colspan="2">21</tableCell><tableCell>23</tableCell><tableCell>24</tableCell></tableRow>' +
  160. '</table>'
  161. );
  162. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  163. '<table>' +
  164. '<tbody>' +
  165. '<tr><th>11</th><th>12</th><th>13</th><td>14</td></tr>' +
  166. '<tr><th colspan="2">21</th><th>23</th><td>24</td></tr>' +
  167. '</tbody>' +
  168. '</table>'
  169. );
  170. } );
  171. it( 'should work with colspan and rowspan attributes on table cells', () => {
  172. // The table in this test looks like a table below:
  173. //
  174. // Row headings | Normal cells
  175. // |
  176. // +----+----+----+----+
  177. // | 11 | 12 | 13 | 14 |
  178. // | +----+ +----+
  179. // | | 22 | | 24 |
  180. // |----+----+ +----+
  181. // | 31 | | 34 |
  182. // | +----+----+
  183. // | | 43 | 44 |
  184. // +----+----+----+----+
  185. setModelData( model,
  186. '<table headingColumns="3">' +
  187. '<tableRow>' +
  188. '<tableCell rowspan="2">11</tableCell>' +
  189. '<tableCell>12</tableCell>' +
  190. '<tableCell rowspan="3">13</tableCell>' +
  191. '<tableCell>14</tableCell>' +
  192. '</tableRow>' +
  193. '<tableRow><tableCell>22</tableCell><tableCell>24</tableCell></tableRow>' +
  194. '<tableRow><tableCell colspan="2" rowspan="2">31</tableCell><tableCell>34</tableCell></tableRow>' +
  195. '<tableRow><tableCell>43</tableCell><tableCell>44</tableCell></tableRow>' +
  196. '</table>'
  197. );
  198. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  199. '<table>' +
  200. '<tbody>' +
  201. '<tr><th rowspan="2">11</th><th>12</th><th rowspan="3">13</th><td>14</td></tr>' +
  202. '<tr><th>22</th><td>24</td></tr>' +
  203. '<tr><th colspan="2" rowspan="2">31</th><td>34</td></tr>' +
  204. '<tr><th>43</th><td>44</td></tr>' +
  205. '</tbody>' +
  206. '</table>'
  207. );
  208. } );
  209. } );
  210. } );