tablepropertiesediting.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
  6. import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
  7. import TableEditing from '../../src/tableediting';
  8. import TablePropertiesEditing from '../../src/tableproperties/tablepropertiesediting';
  9. import TableBorderColorCommand from '../../src/tableproperties/commands/tablebordercolorcommand';
  10. import TableBorderStyleCommand from '../../src/tableproperties/commands/tableborderstylecommand';
  11. import TableBorderWidthCommand from '../../src/tableproperties/commands/tableborderwidthcommand';
  12. import TableAlignmentCommand from '../../src/tableproperties/commands/tablealignmentcommand';
  13. import TableWidthCommand from '../../src/tableproperties/commands/tablewidthcommand';
  14. import TableHeightCommand from '../../src/tableproperties/commands/tableheightcommand';
  15. import TableBackgroundColorCommand from '../../src/tableproperties/commands/tablebackgroundcolorcommand';
  16. import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  17. import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
  18. import { assertTableStyle, assertTRBLAttribute } from '../_utils/utils';
  19. describe( 'table properties', () => {
  20. describe( 'TablePropertiesEditing', () => {
  21. let editor, model;
  22. beforeEach( () => {
  23. return VirtualTestEditor
  24. .create( {
  25. plugins: [ TablePropertiesEditing, Paragraph, TableEditing ]
  26. } )
  27. .then( newEditor => {
  28. editor = newEditor;
  29. model = editor.model;
  30. } );
  31. } );
  32. afterEach( () => {
  33. editor.destroy();
  34. } );
  35. it( 'should have pluginName', () => {
  36. expect( TablePropertiesEditing.pluginName ).to.equal( 'TablePropertiesEditing' );
  37. } );
  38. it( 'adds tableBorderColor command', () => {
  39. expect( editor.commands.get( 'tableBorderColor' ) ).to.be.instanceOf( TableBorderColorCommand );
  40. } );
  41. it( 'adds tableBorderStyle command', () => {
  42. expect( editor.commands.get( 'tableBorderStyle' ) ).to.be.instanceOf( TableBorderStyleCommand );
  43. } );
  44. it( 'adds tableBorderWidth command', () => {
  45. expect( editor.commands.get( 'tableBorderWidth' ) ).to.be.instanceOf( TableBorderWidthCommand );
  46. } );
  47. it( 'adds tableAlignment command', () => {
  48. expect( editor.commands.get( 'tableAlignment' ) ).to.be.instanceOf( TableAlignmentCommand );
  49. } );
  50. it( 'adds tableWidth command', () => {
  51. expect( editor.commands.get( 'tableWidth' ) ).to.be.instanceOf( TableWidthCommand );
  52. } );
  53. it( 'adds tableHeight command', () => {
  54. expect( editor.commands.get( 'tableHeight' ) ).to.be.instanceOf( TableHeightCommand );
  55. } );
  56. it( 'adds tableBackgroundColor command', () => {
  57. expect( editor.commands.get( 'tableBackgroundColor' ) ).to.be.instanceOf( TableBackgroundColorCommand );
  58. } );
  59. describe( 'border', () => {
  60. it( 'should set proper schema rules', () => {
  61. expect( model.schema.checkAttribute( [ '$root', 'table' ], 'borderColor' ) ).to.be.true;
  62. expect( model.schema.checkAttribute( [ '$root', 'table' ], 'borderStyle' ) ).to.be.true;
  63. expect( model.schema.checkAttribute( [ '$root', 'table' ], 'borderWidth' ) ).to.be.true;
  64. } );
  65. describe( 'upcast conversion', () => {
  66. it( 'should upcast border shorthand', () => {
  67. editor.setData( '<table style="border:1px solid #f00"><tr><td>foo</td></tr></table>' );
  68. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  69. assertTRBLAttribute( table, 'borderColor', '#f00' );
  70. assertTRBLAttribute( table, 'borderStyle', 'solid' );
  71. assertTRBLAttribute( table, 'borderWidth', '1px' );
  72. } );
  73. it( 'should upcast border-color shorthand', () => {
  74. editor.setData( '<table style="border-color:#f00"><tr><td>foo</td></tr></table>' );
  75. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  76. assertTRBLAttribute( table, 'borderColor', '#f00' );
  77. } );
  78. it( 'should upcast border-style shorthand', () => {
  79. editor.setData( '<table style="border-style:ridge"><tr><td>foo</td></tr></table>' );
  80. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  81. assertTRBLAttribute( table, 'borderStyle', 'ridge' );
  82. } );
  83. it( 'should upcast border-width shorthand', () => {
  84. editor.setData( '<table style="border-width:1px"><tr><td>foo</td></tr></table>' );
  85. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  86. assertTRBLAttribute( table, 'borderWidth', '1px' );
  87. } );
  88. it( 'should upcast border-top shorthand', () => {
  89. editor.setData( '<table style="border-top:1px solid #f00"><tr><td>foo</td></tr></table>' );
  90. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  91. assertTRBLAttribute( table, 'borderColor', '#f00', null, null, null );
  92. assertTRBLAttribute( table, 'borderStyle', 'solid', null, null, null );
  93. assertTRBLAttribute( table, 'borderWidth', '1px', null, null, null );
  94. } );
  95. it( 'should upcast border-right shorthand', () => {
  96. editor.setData( '<table style="border-right:1px solid #f00"><tr><td>foo</td></tr></table>' );
  97. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  98. assertTRBLAttribute( table, 'borderColor', null, '#f00', null, null );
  99. assertTRBLAttribute( table, 'borderStyle', null, 'solid', null, null );
  100. assertTRBLAttribute( table, 'borderWidth', null, '1px', null, null );
  101. } );
  102. it( 'should upcast border-bottom shorthand', () => {
  103. editor.setData( '<table style="border-bottom:1px solid #f00"><tr><td>foo</td></tr></table>' );
  104. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  105. assertTRBLAttribute( table, 'borderColor', null, null, '#f00', null );
  106. assertTRBLAttribute( table, 'borderStyle', null, null, 'solid', null );
  107. assertTRBLAttribute( table, 'borderWidth', null, null, '1px', null );
  108. } );
  109. it( 'should upcast border-left shorthand', () => {
  110. editor.setData( '<table style="border-left:1px solid #f00"><tr><td>foo</td></tr></table>' );
  111. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  112. assertTRBLAttribute( table, 'borderColor', null, null, null, '#f00' );
  113. assertTRBLAttribute( table, 'borderStyle', null, null, null, 'solid' );
  114. assertTRBLAttribute( table, 'borderWidth', null, null, null, '1px' );
  115. } );
  116. it( 'should upcast border-top-* styles', () => {
  117. editor.setData(
  118. '<table style="border-top-width:1px;border-top-style:solid;border-top-color:#f00"><tr><td>foo</td></tr></table>'
  119. );
  120. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  121. assertTRBLAttribute( table, 'borderColor', '#f00', null, null, null );
  122. assertTRBLAttribute( table, 'borderStyle', 'solid', null, null, null );
  123. assertTRBLAttribute( table, 'borderWidth', '1px', null, null, null );
  124. } );
  125. it( 'should upcast border-right-* styles', () => {
  126. editor.setData(
  127. '<table style="border-right-width:1px;border-right-style:solid;border-right-color:#f00">' +
  128. '<tr>' +
  129. '<td>foo</td>' +
  130. '</tr>' +
  131. '</table>'
  132. );
  133. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  134. assertTRBLAttribute( table, 'borderColor', null, '#f00', null, null );
  135. assertTRBLAttribute( table, 'borderStyle', null, 'solid', null, null );
  136. assertTRBLAttribute( table, 'borderWidth', null, '1px', null, null );
  137. } );
  138. it( 'should upcast border-bottom-* styles', () => {
  139. editor.setData(
  140. '<table style="border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#f00">' +
  141. '<tr>' +
  142. '<td>foo</td>' +
  143. '</tr>' +
  144. '</table>'
  145. );
  146. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  147. assertTRBLAttribute( table, 'borderColor', null, null, '#f00', null );
  148. assertTRBLAttribute( table, 'borderStyle', null, null, 'solid', null );
  149. assertTRBLAttribute( table, 'borderWidth', null, null, '1px', null );
  150. } );
  151. it( 'should upcast border-left-* styles', () => {
  152. editor.setData(
  153. '<table style="border-left-width:1px;border-left-style:solid;border-left-color:#f00"><tr><td>foo</td></tr></table>'
  154. );
  155. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  156. assertTRBLAttribute( table, 'borderColor', null, null, null, '#f00' );
  157. assertTRBLAttribute( table, 'borderStyle', null, null, null, 'solid' );
  158. assertTRBLAttribute( table, 'borderWidth', null, null, null, '1px' );
  159. } );
  160. // https://github.com/ckeditor/ckeditor5/issues/6177
  161. it( 'should upcast tables with nested tables in their cells', () => {
  162. editor.setData( '<table style="border:1px solid red">' +
  163. '<tr>' +
  164. '<td>parent:00</td>' +
  165. '<td>' +
  166. '<table style="border:1px solid green"><tr><td>child:00</td></tr></table>' +
  167. '</td>' +
  168. '</tr>' +
  169. '</table>' );
  170. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  171. assertTRBLAttribute( table, 'borderColor', 'red' );
  172. assertTRBLAttribute( table, 'borderStyle', 'solid' );
  173. assertTRBLAttribute( table, 'borderWidth', '1px' );
  174. } );
  175. } );
  176. describe( 'downcast conversion', () => {
  177. let table;
  178. beforeEach( () => {
  179. table = createEmptyTable();
  180. } );
  181. it( 'should consume converted item borderColor attribute', () => {
  182. editor.conversion.for( 'downcast' )
  183. .add( dispatcher => dispatcher.on( 'attribute:borderColor:table', ( evt, data, conversionApi ) => {
  184. expect( conversionApi.consumable.consume( data.item, evt.name ) ).to.be.false;
  185. } ) );
  186. model.change( writer => writer.setAttribute( 'borderColor', '#f00', table ) );
  187. } );
  188. it( 'should be overridable', () => {
  189. editor.conversion.for( 'downcast' )
  190. .add( dispatcher => dispatcher.on( 'attribute:borderColor:table', ( evt, data, conversionApi ) => {
  191. conversionApi.consumable.consume( data.item, evt.name );
  192. }, { priority: 'high' } ) );
  193. model.change( writer => writer.setAttribute( 'borderColor', '#f00', table ) );
  194. assertTableStyle( editor, '' );
  195. } );
  196. it( 'should downcast borderColor attribute (same top, right, bottom, left)', () => {
  197. model.change( writer => writer.setAttribute( 'borderColor', {
  198. top: '#f00',
  199. right: '#f00',
  200. bottom: '#f00',
  201. left: '#f00'
  202. }, table ) );
  203. assertTableStyle( editor, 'border-bottom:#f00;border-left:#f00;border-right:#f00;border-top:#f00;' );
  204. } );
  205. it( 'should downcast borderColor attribute (different top, right, bottom, left)', () => {
  206. model.change( writer => writer.setAttribute( 'borderColor', {
  207. top: '#f00',
  208. right: 'hsla(0, 100%, 50%, 0.5)',
  209. bottom: 'deeppink',
  210. left: 'rgb(255, 0, 0)'
  211. }, table ) );
  212. assertTableStyle( editor,
  213. 'border-bottom:deeppink;' +
  214. 'border-left:rgb(255, 0, 0);' +
  215. 'border-right:hsla(0, 100%, 50%, 0.5);' +
  216. 'border-top:#f00;'
  217. );
  218. } );
  219. it( 'should consume converted item borderStyle attribute', () => {
  220. editor.conversion.for( 'downcast' )
  221. .add( dispatcher => dispatcher.on( 'attribute:borderStyle:table', ( evt, data, conversionApi ) => {
  222. expect( conversionApi.consumable.consume( data.item, evt.name ) ).to.be.false;
  223. } ) );
  224. model.change( writer => writer.setAttribute( 'borderStyle', 'solid', table ) );
  225. } );
  226. it( 'should be overridable for borderStyle', () => {
  227. editor.conversion.for( 'downcast' )
  228. .add( dispatcher => dispatcher.on( 'attribute:borderStyle:table', ( evt, data, conversionApi ) => {
  229. conversionApi.consumable.consume( data.item, evt.name );
  230. }, { priority: 'high' } ) );
  231. model.change( writer => writer.setAttribute( 'borderStyle', 'solid', table ) );
  232. assertTableStyle( editor, '' );
  233. } );
  234. it( 'should downcast borderStyle attribute (same top, right, bottom, left)', () => {
  235. model.change( writer => writer.setAttribute( 'borderStyle', {
  236. top: 'solid',
  237. right: 'solid',
  238. bottom: 'solid',
  239. left: 'solid'
  240. }, table ) );
  241. assertTableStyle( editor, 'border-bottom:solid;border-left:solid;border-right:solid;border-top:solid;' );
  242. } );
  243. it( 'should downcast borderStyle attribute (different top, right, bottom, left)', () => {
  244. model.change( writer => writer.setAttribute( 'borderStyle', {
  245. top: 'solid',
  246. right: 'ridge',
  247. bottom: 'dotted',
  248. left: 'dashed'
  249. }, table ) );
  250. assertTableStyle( editor, 'border-bottom:dotted;border-left:dashed;border-right:ridge;border-top:solid;' );
  251. } );
  252. it( 'should consume converted item borderWidth attribute', () => {
  253. editor.conversion.for( 'downcast' )
  254. .add( dispatcher => dispatcher.on( 'attribute:borderWidth:table', ( evt, data, conversionApi ) => {
  255. expect( conversionApi.consumable.consume( data.item, evt.name ) ).to.be.false;
  256. } ) );
  257. model.change( writer => writer.setAttribute( 'borderWidth', '2px', table ) );
  258. } );
  259. it( 'should be overridable for borderWidth', () => {
  260. editor.conversion.for( 'downcast' )
  261. .add( dispatcher => dispatcher.on( 'attribute:borderWidth:table', ( evt, data, conversionApi ) => {
  262. conversionApi.consumable.consume( data.item, evt.name );
  263. }, { priority: 'high' } ) );
  264. model.change( writer => writer.setAttribute( 'borderWidth', '2px', table ) );
  265. assertTableStyle( editor, '' );
  266. } );
  267. it( 'should downcast borderWidth attribute (same top, right, bottom, left)', () => {
  268. model.change( writer => writer.setAttribute( 'borderWidth', {
  269. top: '42px',
  270. right: '.1em',
  271. bottom: '1337rem',
  272. left: 'thick'
  273. }, table ) );
  274. assertTableStyle( editor, 'border-bottom:1337rem;border-left:thick;border-right:.1em;border-top:42px;' );
  275. } );
  276. it( 'should downcast borderWidth attribute (different top, right, bottom, left)', () => {
  277. model.change( writer => writer.setAttribute( 'borderWidth', {
  278. top: '42px',
  279. right: '42px',
  280. bottom: '42px',
  281. left: '42px'
  282. }, table ) );
  283. assertTableStyle( editor, 'border-bottom:42px;border-left:42px;border-right:42px;border-top:42px;' );
  284. } );
  285. it( 'should downcast borderColor, borderStyle and borderWidth attributes together (same top, right, bottom, left)', () => {
  286. model.change( writer => {
  287. writer.setAttribute( 'borderColor', {
  288. top: '#f00',
  289. right: '#f00',
  290. bottom: '#f00',
  291. left: '#f00'
  292. }, table );
  293. writer.setAttribute( 'borderStyle', {
  294. top: 'solid',
  295. right: 'solid',
  296. bottom: 'solid',
  297. left: 'solid'
  298. }, table );
  299. writer.setAttribute( 'borderWidth', {
  300. top: '42px',
  301. right: '42px',
  302. bottom: '42px',
  303. left: '42px'
  304. }, table );
  305. } );
  306. assertTableStyle( editor,
  307. 'border-bottom:42px solid #f00;' +
  308. 'border-left:42px solid #f00;' +
  309. 'border-right:42px solid #f00;' +
  310. 'border-top:42px solid #f00;'
  311. );
  312. } );
  313. it(
  314. 'should downcast borderColor, borderStyle and borderWidth attributes together (different top, right, bottom, left)',
  315. () => {
  316. model.change( writer => {
  317. writer.setAttribute( 'borderColor', {
  318. top: '#f00',
  319. right: 'hsla(0, 100%, 50%, 0.5)',
  320. bottom: 'deeppink',
  321. left: 'rgb(255, 0, 0)'
  322. }, table );
  323. writer.setAttribute( 'borderStyle', {
  324. top: 'solid',
  325. right: 'ridge',
  326. bottom: 'dotted',
  327. left: 'dashed'
  328. }, table );
  329. writer.setAttribute( 'borderWidth', {
  330. top: '42px',
  331. right: '.1em',
  332. bottom: '1337rem',
  333. left: 'thick'
  334. }, table );
  335. } );
  336. assertTableStyle( editor,
  337. 'border-bottom:1337rem dotted deeppink;' +
  338. 'border-left:thick dashed rgb(255, 0, 0);' +
  339. 'border-right:.1em ridge hsla(0, 100%, 50%, 0.5);' +
  340. 'border-top:42px solid #f00;'
  341. );
  342. }
  343. );
  344. describe( 'change attribute', () => {
  345. beforeEach( () => {
  346. model.change( writer => {
  347. writer.setAttribute( 'borderColor', {
  348. top: '#f00',
  349. right: '#f00',
  350. bottom: '#f00',
  351. left: '#f00'
  352. }, table );
  353. writer.setAttribute( 'borderStyle', {
  354. top: 'solid',
  355. right: 'solid',
  356. bottom: 'solid',
  357. left: 'solid'
  358. }, table );
  359. writer.setAttribute( 'borderWidth', {
  360. top: '42px',
  361. right: '42px',
  362. bottom: '42px',
  363. left: '42px'
  364. }, table );
  365. } );
  366. } );
  367. it( 'should downcast borderColor attribute change', () => {
  368. model.change( writer => writer.setAttribute( 'borderColor', {
  369. top: 'deeppink',
  370. right: 'deeppink',
  371. bottom: 'deeppink',
  372. left: 'deeppink'
  373. }, table ) );
  374. assertTableStyle( editor,
  375. 'border-bottom:42px solid deeppink;' +
  376. 'border-left:42px solid deeppink;' +
  377. 'border-right:42px solid deeppink;' +
  378. 'border-top:42px solid deeppink;'
  379. );
  380. } );
  381. it( 'should downcast borderStyle attribute change', () => {
  382. model.change( writer => writer.setAttribute( 'borderStyle', {
  383. top: 'ridge',
  384. right: 'ridge',
  385. bottom: 'ridge',
  386. left: 'ridge'
  387. }, table ) );
  388. assertTableStyle( editor,
  389. 'border-bottom:42px ridge #f00;' +
  390. 'border-left:42px ridge #f00;' +
  391. 'border-right:42px ridge #f00;' +
  392. 'border-top:42px ridge #f00;'
  393. );
  394. } );
  395. it( 'should downcast borderWidth attribute change', () => {
  396. model.change( writer => writer.setAttribute( 'borderWidth', {
  397. top: 'thick',
  398. right: 'thick',
  399. bottom: 'thick',
  400. left: 'thick'
  401. }, table ) );
  402. assertTableStyle( editor,
  403. 'border-bottom:thick solid #f00;' +
  404. 'border-left:thick solid #f00;' +
  405. 'border-right:thick solid #f00;' +
  406. 'border-top:thick solid #f00;'
  407. );
  408. } );
  409. it( 'should downcast borderColor attribute removal', () => {
  410. model.change( writer => writer.removeAttribute( 'borderColor', table ) );
  411. assertTableStyle( editor,
  412. 'border-bottom:42px solid;' +
  413. 'border-left:42px solid;' +
  414. 'border-right:42px solid;' +
  415. 'border-top:42px solid;'
  416. );
  417. } );
  418. it( 'should downcast borderStyle attribute removal', () => {
  419. model.change( writer => writer.removeAttribute( 'borderStyle', table ) );
  420. assertTableStyle( editor,
  421. 'border-bottom:42px #f00;' +
  422. 'border-left:42px #f00;' +
  423. 'border-right:42px #f00;' +
  424. 'border-top:42px #f00;'
  425. );
  426. } );
  427. it( 'should downcast borderWidth attribute removal', () => {
  428. model.change( writer => writer.removeAttribute( 'borderWidth', table ) );
  429. assertTableStyle( editor,
  430. 'border-bottom:solid #f00;' +
  431. 'border-left:solid #f00;' +
  432. 'border-right:solid #f00;' +
  433. 'border-top:solid #f00;'
  434. );
  435. } );
  436. it( 'should downcast borderColor, borderStyle and borderWidth attributes removal', () => {
  437. model.change( writer => {
  438. writer.removeAttribute( 'borderColor', table );
  439. writer.removeAttribute( 'borderStyle', table );
  440. writer.removeAttribute( 'borderWidth', table );
  441. } );
  442. assertEqualMarkup(
  443. editor.getData(),
  444. '<figure class="table"><table><tbody><tr><td>foo</td></tr></tbody></table></figure>'
  445. );
  446. } );
  447. } );
  448. } );
  449. } );
  450. describe( 'background color', () => {
  451. it( 'should set proper schema rules', () => {
  452. expect( model.schema.checkAttribute( [ '$root', 'table' ], 'backgroundColor' ) ).to.be.true;
  453. } );
  454. describe( 'upcast conversion', () => {
  455. it( 'should upcast background-color', () => {
  456. editor.setData( '<table style="background-color:#f00"><tr><td>foo</td></tr></table>' );
  457. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  458. expect( table.getAttribute( 'backgroundColor' ) ).to.equal( '#f00' );
  459. } );
  460. it( 'should upcast from background shorthand', () => {
  461. editor.setData( '<table style="background:#f00 center center"><tr><td>foo</td></tr></table>' );
  462. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  463. expect( table.getAttribute( 'backgroundColor' ) ).to.equal( '#f00' );
  464. } );
  465. it( 'should upcast from background shorthand (rbg color value with spaces)', () => {
  466. editor.setData( '<table style="background:rgb(253, 253, 119) center center"><tr><td>foo</td></tr></table>' );
  467. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  468. expect( table.getAttribute( 'backgroundColor' ) ).to.equal( 'rgb(253, 253, 119)' );
  469. } );
  470. } );
  471. describe( 'downcast conversion', () => {
  472. let table;
  473. beforeEach( () => {
  474. table = createEmptyTable();
  475. } );
  476. it( 'should consume converted item', () => {
  477. editor.conversion.for( 'downcast' )
  478. .add( dispatcher => dispatcher.on( 'attribute:backgroundColor:table', ( evt, data, conversionApi ) => {
  479. expect( conversionApi.consumable.consume( data.item, evt.name ) ).to.be.false;
  480. } ) );
  481. model.change( writer => writer.setAttribute( 'backgroundColor', '#f00', table ) );
  482. } );
  483. it( 'should be overridable', () => {
  484. editor.conversion.for( 'downcast' )
  485. .add( dispatcher => dispatcher.on( 'attribute:backgroundColor:table', ( evt, data, conversionApi ) => {
  486. conversionApi.consumable.consume( data.item, evt.name );
  487. }, { priority: 'high' } ) );
  488. model.change( writer => writer.setAttribute( 'backgroundColor', '#f00', table ) );
  489. assertTableStyle( editor, '' );
  490. } );
  491. it( 'should downcast backgroundColor', () => {
  492. model.change( writer => writer.setAttribute( 'backgroundColor', '#f00', table ) );
  493. assertTableStyle( editor, 'background-color:#f00;' );
  494. } );
  495. it( 'should downcast backgroundColor removal', () => {
  496. model.change( writer => writer.setAttribute( 'backgroundColor', '#f00', table ) );
  497. model.change( writer => writer.removeAttribute( 'backgroundColor', table ) );
  498. assertTableStyle( editor );
  499. } );
  500. it( 'should downcast backgroundColor change', () => {
  501. model.change( writer => writer.setAttribute( 'backgroundColor', '#f00', table ) );
  502. assertTableStyle( editor, 'background-color:#f00;' );
  503. model.change( writer => writer.setAttribute( 'backgroundColor', '#ba7', table ) );
  504. assertTableStyle( editor, 'background-color:#ba7;' );
  505. } );
  506. } );
  507. } );
  508. describe( 'width', () => {
  509. it( 'should set proper schema rules', () => {
  510. expect( model.schema.checkAttribute( [ '$root', 'table' ], 'width' ) ).to.be.true;
  511. } );
  512. describe( 'upcast conversion', () => {
  513. it( 'should upcast width from <table>', () => {
  514. editor.setData( '<table style="width:1337px"><tr><td>foo</td></tr></table>' );
  515. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  516. expect( table.getAttribute( 'width' ) ).to.equal( '1337px' );
  517. } );
  518. it( 'should upcast width from <figure>', () => {
  519. editor.setData( '<figure style="width:1337px"><table><tr><td>foo</td></tr></table></figure>' );
  520. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  521. expect( table.getAttribute( 'width' ) ).to.equal( '1337px' );
  522. } );
  523. } );
  524. describe( 'downcast conversion', () => {
  525. let table;
  526. beforeEach( () => {
  527. table = createEmptyTable();
  528. } );
  529. it( 'should consume converted item', () => {
  530. editor.conversion.for( 'downcast' )
  531. .add( dispatcher => dispatcher.on( 'attribute:width:table', ( evt, data, conversionApi ) => {
  532. expect( conversionApi.consumable.consume( data.item, evt.name ) ).to.be.false;
  533. } ) );
  534. model.change( writer => writer.setAttribute( 'width', '400px', table ) );
  535. } );
  536. it( 'should be overridable', () => {
  537. editor.conversion.for( 'downcast' )
  538. .add( dispatcher => dispatcher.on( 'attribute:width:table', ( evt, data, conversionApi ) => {
  539. conversionApi.consumable.consume( data.item, evt.name );
  540. }, { priority: 'high' } ) );
  541. model.change( writer => writer.setAttribute( 'width', '400px', table ) );
  542. assertTableStyle( editor, '' );
  543. } );
  544. it( 'should downcast width', () => {
  545. model.change( writer => writer.setAttribute( 'width', '1337px', table ) );
  546. assertTableStyle( editor, null, 'width:1337px;' );
  547. } );
  548. it( 'should downcast width removal', () => {
  549. model.change( writer => writer.setAttribute( 'width', '1337px', table ) );
  550. model.change( writer => writer.removeAttribute( 'width', table ) );
  551. assertTableStyle( editor );
  552. } );
  553. it( 'should downcast width change', () => {
  554. model.change( writer => writer.setAttribute( 'width', '1337px', table ) );
  555. assertTableStyle( editor, null, 'width:1337px;' );
  556. model.change( writer => writer.setAttribute( 'width', '1410em', table ) );
  557. assertTableStyle( editor, null, 'width:1410em;' );
  558. } );
  559. } );
  560. } );
  561. describe( 'height', () => {
  562. it( 'should set proper schema rules', () => {
  563. expect( model.schema.checkAttribute( [ '$root', 'table' ], 'height' ) ).to.be.true;
  564. } );
  565. describe( 'upcast conversion', () => {
  566. it( 'should upcast height from <table>', () => {
  567. editor.setData( '<table style="height:1337px"><tr><td>foo</td></tr></table>' );
  568. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  569. expect( table.getAttribute( 'height' ) ).to.equal( '1337px' );
  570. } );
  571. it( 'should upcast height from <figure>', () => {
  572. editor.setData( '<figure style="height:1337px"><table><tr><td>foo</td></tr></table></figure>' );
  573. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  574. expect( table.getAttribute( 'height' ) ).to.equal( '1337px' );
  575. } );
  576. } );
  577. describe( 'downcast conversion', () => {
  578. let table;
  579. beforeEach( () => {
  580. table = createEmptyTable();
  581. } );
  582. it( 'should downcast height', () => {
  583. model.change( writer => writer.setAttribute( 'height', '1337px', table ) );
  584. assertTableStyle( editor, null, 'height:1337px;' );
  585. } );
  586. it( 'should downcast height removal', () => {
  587. model.change( writer => writer.setAttribute( 'height', '1337px', table ) );
  588. model.change( writer => writer.removeAttribute( 'height', table ) );
  589. assertTableStyle( editor );
  590. } );
  591. it( 'should downcast height change', () => {
  592. model.change( writer => writer.setAttribute( 'height', '1337px', table ) );
  593. assertTableStyle( editor, null, 'height:1337px;' );
  594. model.change( writer => writer.setAttribute( 'height', '1410em', table ) );
  595. assertTableStyle( editor, null, 'height:1410em;' );
  596. } );
  597. it( 'should consume converted item', () => {
  598. editor.conversion.for( 'downcast' )
  599. .add( dispatcher => dispatcher.on( 'attribute:height:table', ( evt, data, conversionApi ) => {
  600. expect( conversionApi.consumable.consume( data.item, evt.name ) ).to.be.false;
  601. } ) );
  602. model.change( writer => writer.setAttribute( 'height', '400px', table ) );
  603. } );
  604. it( 'should be overridable', () => {
  605. editor.conversion.for( 'downcast' )
  606. .add( dispatcher => dispatcher.on( 'attribute:height:table', ( evt, data, conversionApi ) => {
  607. conversionApi.consumable.consume( data.item, evt.name );
  608. }, { priority: 'high' } ) );
  609. model.change( writer => writer.setAttribute( 'height', '400px', table ) );
  610. assertTableStyle( editor, '' );
  611. } );
  612. } );
  613. } );
  614. describe( 'alignment', () => {
  615. it( 'should set proper schema rules', () => {
  616. expect( model.schema.checkAttribute( [ '$root', 'table' ], 'alignment' ) ).to.be.true;
  617. } );
  618. describe( 'upcast conversion', () => {
  619. it( 'should upcast style="float:right" to right value', () => {
  620. editor.setData( '<table style="float:right"><tr><td>foo</td></tr></table>' );
  621. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  622. expect( table.getAttribute( 'alignment' ) ).to.equal( 'right' );
  623. } );
  624. it( 'should upcast style="float:left;" to left value', () => {
  625. editor.setData( '<table style="float:left;"><tr><td>foo</td></tr></table>' );
  626. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  627. expect( table.getAttribute( 'alignment' ) ).to.equal( 'left' );
  628. } );
  629. it( 'should upcast align=right attribute', () => {
  630. editor.setData( '<table align="right"><tr><td>foo</td></tr></table>' );
  631. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  632. expect( table.getAttribute( 'alignment' ) ).to.equal( 'right' );
  633. } );
  634. it( 'should upcast align=left attribute', () => {
  635. editor.setData( '<table align="left"><tr><td>foo</td></tr></table>' );
  636. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  637. expect( table.getAttribute( 'alignment' ) ).to.equal( 'left' );
  638. } );
  639. it( 'should discard align=center attribute', () => {
  640. editor.setData( '<table align="center"><tr><td>foo</td></tr></table>' );
  641. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  642. expect( table.getAttribute( 'alignment' ) ).to.be.undefined;
  643. } );
  644. it( 'should discard align=justify attribute', () => {
  645. editor.setData( '<table align="justify"><tr><td>foo</td></tr></table>' );
  646. const table = model.document.getRoot().getNodeByPath( [ 0 ] );
  647. expect( table.hasAttribute( 'alignment' ) ).to.be.false;
  648. } );
  649. } );
  650. describe( 'downcast conversion', () => {
  651. let table;
  652. beforeEach( () => {
  653. table = createEmptyTable();
  654. } );
  655. it( 'should consume converted item', () => {
  656. editor.conversion.for( 'downcast' )
  657. .add( dispatcher => dispatcher.on( 'attribute:alignment:table', ( evt, data, conversionApi ) => {
  658. expect( conversionApi.consumable.consume( data.item, evt.name ) ).to.be.false;
  659. } ) );
  660. model.change( writer => writer.setAttribute( 'alignment', 'right', table ) );
  661. } );
  662. it( 'should be overridable', () => {
  663. editor.conversion.for( 'downcast' )
  664. .add( dispatcher => dispatcher.on( 'attribute:alignment:table', ( evt, data, conversionApi ) => {
  665. conversionApi.consumable.consume( data.item, evt.name );
  666. }, { priority: 'highest' } ) );
  667. model.change( writer => writer.setAttribute( 'alignment', 'right', table ) );
  668. assertTableStyle( editor, '' );
  669. } );
  670. it( 'should downcast "right" alignment', () => {
  671. model.change( writer => writer.setAttribute( 'alignment', 'right', table ) );
  672. assertTableStyle( editor, null, 'float:right;' );
  673. } );
  674. it( 'should downcast "left" alignment', () => {
  675. model.change( writer => writer.setAttribute( 'alignment', 'left', table ) );
  676. assertTableStyle( editor, null, 'float:left;' );
  677. } );
  678. it( 'should not downcast "center" alignment', () => {
  679. model.change( writer => writer.setAttribute( 'alignment', 'center', table ) );
  680. assertTableStyle( editor, null, null );
  681. } );
  682. it( 'should downcast changed alignment (left -> right)', () => {
  683. model.change( writer => writer.setAttribute( 'alignment', 'left', table ) );
  684. assertTableStyle( editor, null, 'float:left;' );
  685. model.change( writer => writer.setAttribute( 'alignment', 'right', table ) );
  686. assertTableStyle( editor, null, 'float:right;' );
  687. } );
  688. it( 'should downcast changed alignment (right -> left)', () => {
  689. model.change( writer => writer.setAttribute( 'alignment', 'right', table ) );
  690. assertTableStyle( editor, null, 'float:right;' );
  691. model.change( writer => writer.setAttribute( 'alignment', 'left', table ) );
  692. assertTableStyle( editor, null, 'float:left;' );
  693. } );
  694. it( 'should downcast removed alignment (from left)', () => {
  695. model.change( writer => writer.setAttribute( 'alignment', 'left', table ) );
  696. assertTableStyle( editor, null, 'float:left;' );
  697. model.change( writer => writer.removeAttribute( 'alignment', table ) );
  698. assertTableStyle( editor );
  699. } );
  700. it( 'should downcast removed alignment (from right)', () => {
  701. model.change( writer => writer.setAttribute( 'alignment', 'right', table ) );
  702. assertTableStyle( editor, null, 'float:right;' );
  703. model.change( writer => writer.removeAttribute( 'alignment', table ) );
  704. assertTableStyle( editor );
  705. } );
  706. } );
  707. } );
  708. function createEmptyTable() {
  709. setModelData(
  710. model,
  711. '<table headingRows="0" headingColumns="0">' +
  712. '<tableRow>' +
  713. '<tableCell>' +
  714. '<paragraph>foo</paragraph>' +
  715. '</tableCell>' +
  716. '</tableRow>' +
  717. '</table>'
  718. );
  719. return model.document.getRoot().getNodeByPath( [ 0 ] );
  720. }
  721. } );
  722. } );