8
0

liststyleediting.js 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  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 { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  8. import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
  9. import UndoEditing from '@ckeditor/ckeditor5-undo/src/undoediting';
  10. import ListStyleEditing from '../src/liststyleediting';
  11. import TodoListEditing from '../src/todolistediting';
  12. import ListStyleCommand from '../src/liststylecommand';
  13. describe( 'ListStyleEditing', () => {
  14. let editor, model, view;
  15. beforeEach( () => {
  16. return VirtualTestEditor
  17. .create( {
  18. plugins: [ Paragraph, ListStyleEditing, UndoEditing ]
  19. } )
  20. .then( newEditor => {
  21. editor = newEditor;
  22. model = editor.model;
  23. view = editor.editing.view;
  24. } );
  25. } );
  26. afterEach( () => {
  27. return editor.destroy();
  28. } );
  29. it( 'should have pluginName', () => {
  30. expect( ListStyleEditing.pluginName ).to.equal( 'ListStyleEditing' );
  31. } );
  32. it( 'should be loaded', () => {
  33. expect( editor.plugins.get( ListStyleEditing ) ).to.be.instanceOf( ListStyleEditing );
  34. } );
  35. describe( 'schema rules', () => {
  36. it( 'should allow set `listStyle` on the `listItem`', () => {
  37. expect( model.schema.checkAttribute( [ '$root', 'listItem' ], 'listStyle' ) ).to.be.true;
  38. } );
  39. } );
  40. describe( 'command', () => {
  41. it( 'should register listStyle command', () => {
  42. const command = editor.commands.get( 'listStyle' );
  43. expect( command ).to.be.instanceOf( ListStyleCommand );
  44. } );
  45. } );
  46. describe( 'conversion in data pipeline', () => {
  47. describe( 'model to data', () => {
  48. it( 'should convert single list (type: bulleted)', () => {
  49. setModelData( model,
  50. '<listItem listIndent="0" listType="bulleted">Foo</listItem>' +
  51. '<listItem listIndent="0" listType="bulleted">Bar</listItem>'
  52. );
  53. expect( editor.getData() ).to.equal( '<ul><li>Foo</li><li>Bar</li></ul>' );
  54. } );
  55. it( 'should convert single list (type: numbered)', () => {
  56. setModelData( model,
  57. '<listItem listIndent="0" listType="numbered">Foo</listItem>' +
  58. '<listItem listIndent="0" listType="numbered">Bar</listItem>'
  59. );
  60. expect( editor.getData() ).to.equal( '<ol><li>Foo</li><li>Bar</li></ol>' );
  61. } );
  62. it( 'should convert single list (type: bulleted, style: default)', () => {
  63. setModelData( model,
  64. '<listItem listIndent="0" listType="bulleted" listStyle="default">Foo</listItem>' +
  65. '<listItem listIndent="0" listType="bulleted" listStyle="default">Bar</listItem>'
  66. );
  67. expect( editor.getData() ).to.equal( '<ul><li>Foo</li><li>Bar</li></ul>' );
  68. } );
  69. it( 'should convert single list (type: numbered, style: default)', () => {
  70. setModelData( model,
  71. '<listItem listIndent="0" listType="numbered" listStyle="default">Foo</listItem>' +
  72. '<listItem listIndent="0" listType="numbered" listStyle="default">Bar</listItem>'
  73. );
  74. expect( editor.getData() ).to.equal( '<ol><li>Foo</li><li>Bar</li></ol>' );
  75. } );
  76. it( 'should convert single list (type: bulleted, style: circle)', () => {
  77. setModelData( model,
  78. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo</listItem>' +
  79. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar</listItem>'
  80. );
  81. expect( editor.getData() ).to.equal( '<ul style="list-style-type:circle;"><li>Foo</li><li>Bar</li></ul>' );
  82. } );
  83. it( 'should convert single list (type: numbered, style: upper-alpha)', () => {
  84. setModelData( model,
  85. '<listItem listIndent="0" listType="numbered" listStyle="upper-alpha">Foo</listItem>' +
  86. '<listItem listIndent="0" listType="numbered" listStyle="upper-alpha">Bar</listItem>'
  87. );
  88. expect( editor.getData() ).to.equal( '<ol style="list-style-type:upper-alpha;"><li>Foo</li><li>Bar</li></ol>' );
  89. } );
  90. it( 'should convert nested bulleted lists (main: circle, nested: disc)', () => {
  91. setModelData( model,
  92. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 1</listItem>' +
  93. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 1</listItem>' +
  94. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 2</listItem>' +
  95. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 2</listItem>' +
  96. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 3</listItem>'
  97. );
  98. expect( editor.getData() ).to.equal(
  99. '<ul style="list-style-type:circle;">' +
  100. '<li>Foo 1' +
  101. '<ul style="list-style-type:disc;">' +
  102. '<li>Bar 1</li>' +
  103. '<li>Bar 2</li>' +
  104. '</ul>' +
  105. '</li>' +
  106. '<li>Foo 2</li>' +
  107. '<li>Foo 3</li>' +
  108. '</ul>'
  109. );
  110. } );
  111. it( 'should convert nested numbered lists (main: decimal-leading-zero, nested: lower-latin)', () => {
  112. setModelData( model,
  113. '<listItem listIndent="0" listType="numbered" listStyle="decimal-leading-zero">Foo 1</listItem>' +
  114. '<listItem listIndent="1" listType="numbered" listStyle="lower-latin">Bar 1</listItem>' +
  115. '<listItem listIndent="1" listType="numbered" listStyle="lower-latin">Bar 2</listItem>' +
  116. '<listItem listIndent="0" listType="numbered" listStyle="decimal-leading-zero">Foo 2</listItem>' +
  117. '<listItem listIndent="0" listType="numbered" listStyle="decimal-leading-zero">Foo 3</listItem>'
  118. );
  119. expect( editor.getData() ).to.equal(
  120. '<ol style="list-style-type:decimal-leading-zero;">' +
  121. '<li>Foo 1' +
  122. '<ol style="list-style-type:lower-latin;">' +
  123. '<li>Bar 1</li>' +
  124. '<li>Bar 2</li>' +
  125. '</ol>' +
  126. '</li>' +
  127. '<li>Foo 2</li>' +
  128. '<li>Foo 3</li>' +
  129. '</ol>'
  130. );
  131. } );
  132. it( 'should convert nested mixed lists (ul>ol, main: square, nested: lower-roman)', () => {
  133. setModelData( model,
  134. '<listItem listIndent="0" listType="bulleted" listStyle="square">Foo 1</listItem>' +
  135. '<listItem listIndent="1" listType="numbered" listStyle="lower-roman">Bar 1</listItem>' +
  136. '<listItem listIndent="1" listType="numbered" listStyle="lower-roman">Bar 2</listItem>' +
  137. '<listItem listIndent="0" listType="bulleted" listStyle="square">Foo 2</listItem>' +
  138. '<listItem listIndent="0" listType="bulleted" listStyle="square">Foo 3</listItem>'
  139. );
  140. expect( editor.getData() ).to.equal(
  141. '<ul style="list-style-type:square;">' +
  142. '<li>Foo 1' +
  143. '<ol style="list-style-type:lower-roman;">' +
  144. '<li>Bar 1</li>' +
  145. '<li>Bar 2</li>' +
  146. '</ol>' +
  147. '</li>' +
  148. '<li>Foo 2</li>' +
  149. '<li>Foo 3</li>' +
  150. '</ul>'
  151. );
  152. } );
  153. it( 'should produce nested lists (different `listIndent` attribute)', () => {
  154. setModelData( model,
  155. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 1</listItem>' +
  156. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 2</listItem>' +
  157. '<listItem listIndent="1" listType="numbered" listStyle="decimal">Bar 1</listItem>' +
  158. '<listItem listIndent="1" listType="numbered" listStyle="decimal">Bar 2</listItem>'
  159. );
  160. expect( editor.getData() ).to.equal(
  161. '<ol style="list-style-type:decimal;">' +
  162. '<li>Foo 1</li>' +
  163. '<li>Foo 2' +
  164. '<ol style="list-style-type:decimal;">' +
  165. '<li>Bar 1</li>' +
  166. '<li>Bar 2</li>' +
  167. '</ol>' +
  168. '</li>' +
  169. '</ol>'
  170. );
  171. } );
  172. it( 'should produce two different lists (different `listType` attribute)', () => {
  173. setModelData( model,
  174. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 1</listItem>' +
  175. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 2</listItem>' +
  176. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Bar 1</listItem>' +
  177. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Bar 2</listItem>'
  178. );
  179. expect( editor.getData() ).to.equal(
  180. '<ol style="list-style-type:decimal;">' +
  181. '<li>Foo 1</li>' +
  182. '<li>Foo 2</li>' +
  183. '</ol>' +
  184. '<ul style="list-style-type:disc;">' +
  185. '<li>Bar 1</li>' +
  186. '<li>Bar 2</li>' +
  187. '</ul>'
  188. );
  189. } );
  190. it( 'should produce two different lists (different `listStyle` attribute)', () => {
  191. setModelData( model,
  192. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Foo 1</listItem>' +
  193. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Foo 2</listItem>' +
  194. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar 1</listItem>' +
  195. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar 2</listItem>'
  196. );
  197. expect( editor.getData() ).to.equal(
  198. '<ul style="list-style-type:disc;">' +
  199. '<li>Foo 1</li>' +
  200. '<li>Foo 2</li>' +
  201. '</ul>' +
  202. '<ul style="list-style-type:circle;">' +
  203. '<li>Bar 1</li>' +
  204. '<li>Bar 2</li>' +
  205. '</ul>'
  206. );
  207. } );
  208. it( 'should not allow to set the `listStyle` attribute in to-do list item', () => {
  209. setModelData( model, '<listItem listIndent="0" listType="todo">Foo</listItem>' );
  210. const listItem = model.document.getRoot().getChild( 0 );
  211. expect( listItem.hasAttribute( 'listItem' ) ).to.be.false;
  212. model.change( writer => {
  213. writer.setAttribute( 'listType', 'foo', listItem );
  214. } );
  215. expect( listItem.hasAttribute( 'listItem' ) ).to.be.false;
  216. } );
  217. } );
  218. describe( 'view to model', () => {
  219. it( 'should convert single list (type: bulleted)', () => {
  220. editor.setData( '<ul><li>Foo</li><li>Bar</li></ul>' );
  221. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  222. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo</listItem>' +
  223. '<listItem listIndent="0" listStyle="default" listType="bulleted">Bar</listItem>'
  224. );
  225. } );
  226. it( 'should convert single list (type: numbered)', () => {
  227. editor.setData( '<ol><li>Foo</li><li>Bar</li></ol>' );
  228. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  229. '<listItem listIndent="0" listStyle="default" listType="numbered">Foo</listItem>' +
  230. '<listItem listIndent="0" listStyle="default" listType="numbered">Bar</listItem>'
  231. );
  232. } );
  233. it( 'should convert single list (type: bulleted, style: circle)', () => {
  234. editor.setData( '<ul style="list-style-type:circle;"><li>Foo</li><li>Bar</li></ul>' );
  235. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  236. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  237. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  238. );
  239. } );
  240. it( 'should convert single list (type: numbered, style: upper-alpha)', () => {
  241. editor.setData( '<ol style="list-style-type:upper-alpha;"><li>Foo</li><li>Bar</li></ol>' );
  242. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  243. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Foo</listItem>' +
  244. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Bar</listItem>'
  245. );
  246. } );
  247. it( 'should convert nested and mixed lists', () => {
  248. editor.setData(
  249. '<ol style="list-style-type:upper-alpha;">' +
  250. '<li>OL 1</li>' +
  251. '<li>OL 2' +
  252. '<ul style="list-style-type:circle;">' +
  253. '<li>UL 1</li>' +
  254. '<li>UL 2</li>' +
  255. '</ul>' +
  256. '</li>' +
  257. '<li>OL 3</li>' +
  258. '</ol>'
  259. );
  260. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  261. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">OL 1</listItem>' +
  262. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">OL 2</listItem>' +
  263. '<listItem listIndent="1" listStyle="circle" listType="bulleted">UL 1</listItem>' +
  264. '<listItem listIndent="1" listStyle="circle" listType="bulleted">UL 2</listItem>' +
  265. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">OL 3</listItem>'
  266. );
  267. } );
  268. it( 'should convert when the list is in the middle of the content', () => {
  269. editor.setData(
  270. '<p>Paragraph.</p>' +
  271. '<ol style="list-style-type:upper-alpha;">' +
  272. '<li>Foo</li>' +
  273. '<li>Bar</li>' +
  274. '</ol>' +
  275. '<p>Paragraph.</p>'
  276. );
  277. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  278. '<paragraph>Paragraph.</paragraph>' +
  279. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Foo</listItem>' +
  280. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Bar</listItem>' +
  281. '<paragraph>Paragraph.</paragraph>'
  282. );
  283. } );
  284. } );
  285. } );
  286. // At this moment editing and data pipelines produce exactly the same content.
  287. // Just a few tests will be enough here. `model to data` block contains all cases checked.
  288. describe( 'conversion in editing pipeline', () => {
  289. describe( 'model to view', () => {
  290. it( 'should convert single list (type: bulleted, style: default)', () => {
  291. setModelData( model,
  292. '<listItem listIndent="0" listType="bulleted" listStyle="default">Foo</listItem>' +
  293. '<listItem listIndent="0" listType="bulleted" listStyle="default">Bar</listItem>'
  294. );
  295. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  296. '<ul><li>Foo</li><li>Bar</li></ul>'
  297. );
  298. } );
  299. it( 'should convert single list (type: bulleted, style: circle)', () => {
  300. setModelData( model,
  301. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo</listItem>' +
  302. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar</listItem>'
  303. );
  304. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  305. '<ul style="list-style-type:circle"><li>Foo</li><li>Bar</li></ul>'
  306. );
  307. } );
  308. it( 'should convert nested bulleted lists (main: circle, nested: disc)', () => {
  309. setModelData( model,
  310. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 1</listItem>' +
  311. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 1</listItem>' +
  312. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 2</listItem>' +
  313. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 2</listItem>' +
  314. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 3</listItem>'
  315. );
  316. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  317. '<ul style="list-style-type:circle">' +
  318. '<li>Foo 1' +
  319. '<ul style="list-style-type:disc">' +
  320. '<li>Bar 1</li>' +
  321. '<li>Bar 2</li>' +
  322. '</ul>' +
  323. '</li>' +
  324. '<li>Foo 2</li>' +
  325. '<li>Foo 3</li>' +
  326. '</ul>'
  327. );
  328. } );
  329. } );
  330. } );
  331. describe( 'integrations', () => {
  332. describe( 'merging a list into a styled list', () => {
  333. it( 'should inherit the list style attribute when merging the same kind of lists (from top, merge a single item)', () => {
  334. setModelData( model,
  335. '<paragraph>Foo Bar.[]</paragraph>' +
  336. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  337. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  338. );
  339. editor.execute( 'bulletedList' );
  340. expect( getModelData( model ) ).to.equal(
  341. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>' +
  342. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  343. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  344. );
  345. } );
  346. it( 'should inherit the list style attribute when merging the same kind of lists (from top, merge a few items)', () => {
  347. setModelData( model,
  348. '<paragraph>[Foo Bar 1.</paragraph>' +
  349. '<paragraph>Foo Bar 2.]</paragraph>' +
  350. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  351. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  352. );
  353. editor.execute( 'bulletedList' );
  354. expect( getModelData( model ) ).to.equal(
  355. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[Foo Bar 1.</listItem>' +
  356. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar 2.]</listItem>' +
  357. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  358. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  359. );
  360. } );
  361. it( 'should not inherit anything if there is no list below the inserted list', () => {
  362. setModelData( model,
  363. '<paragraph>Foo Bar 1.[]</paragraph>' +
  364. '<paragraph>Foo Bar 2.</paragraph>'
  365. );
  366. editor.execute( 'bulletedList' );
  367. expect( getModelData( model ) ).to.equal(
  368. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar 1.[]</listItem>' +
  369. '<paragraph>Foo Bar 2.</paragraph>'
  370. );
  371. } );
  372. it( 'should not inherit anything if replacing the entire content with a list', () => {
  373. setModelData( model,
  374. '<paragraph>Foo Bar 1.[]</paragraph>'
  375. );
  376. editor.execute( 'bulletedList' );
  377. expect( getModelData( model ) ).to.equal(
  378. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar 1.[]</listItem>'
  379. );
  380. } );
  381. it( 'should not inherit the list style attribute when merging different kind of lists (from top, merge a single item)', () => {
  382. setModelData( model,
  383. '<paragraph>Foo Bar.[]</paragraph>' +
  384. '<listItem listIndent="0" listStyle="default" listType="numbered">Foo</listItem>' +
  385. '<listItem listIndent="0" listStyle="default" listType="numbered">Bar</listItem>'
  386. );
  387. editor.execute( 'bulletedList' );
  388. expect( getModelData( model ) ).to.equal(
  389. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>' +
  390. '<listItem listIndent="0" listStyle="default" listType="numbered">Foo</listItem>' +
  391. '<listItem listIndent="0" listStyle="default" listType="numbered">Bar</listItem>'
  392. );
  393. } );
  394. it( 'should inherit the list style attribute when merging the same kind of lists (from bottom, merge a single item)', () => {
  395. setModelData( model,
  396. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  397. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  398. '<paragraph>Foo Bar.[]</paragraph>'
  399. );
  400. editor.execute( 'bulletedList' );
  401. expect( getModelData( model ) ).to.equal(
  402. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  403. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  404. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>'
  405. );
  406. } );
  407. it(
  408. 'should inherit the list style attribute from listIndent=0 element when merging the same kind of lists (from bottom)',
  409. () => {
  410. setModelData( model,
  411. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  412. '<listItem listIndent="1" listStyle="square" listType="bulleted">Bar</listItem>' +
  413. '<listItem listIndent="2" listStyle="disc" listType="bulleted">Foo Bar</listItem>' +
  414. '<paragraph>Foo Bar.[]</paragraph>'
  415. );
  416. editor.execute( 'bulletedList' );
  417. expect( getModelData( model ) ).to.equal(
  418. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  419. '<listItem listIndent="1" listStyle="square" listType="bulleted">Bar</listItem>' +
  420. '<listItem listIndent="2" listStyle="disc" listType="bulleted">Foo Bar</listItem>' +
  421. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>'
  422. );
  423. }
  424. );
  425. } );
  426. describe( 'indenting lists', () => {
  427. it( 'should restore the default value for the list style attribute when indenting a single item', () => {
  428. setModelData( model,
  429. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  430. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  431. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  432. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  433. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  434. );
  435. editor.execute( 'indentList' );
  436. expect( getModelData( model ) ).to.equal(
  437. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  438. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  439. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  440. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  441. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  442. );
  443. } );
  444. it( 'should restore the default value for the list style attribute when indenting a few items', () => {
  445. setModelData( model,
  446. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  447. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[2.</listItem>' +
  448. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.]</listItem>'
  449. );
  450. editor.execute( 'indentList' );
  451. expect( getModelData( model ) ).to.equal(
  452. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  453. '<listItem listIndent="1" listStyle="default" listType="bulleted">[2.</listItem>' +
  454. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.]</listItem>'
  455. );
  456. } );
  457. it(
  458. 'should copy the value for the list style attribute when indenting a single item into a nested list (default value)',
  459. () => {
  460. setModelData( model,
  461. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  462. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  463. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>' +
  464. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  465. );
  466. editor.execute( 'indentList' );
  467. expect( getModelData( model ) ).to.equal(
  468. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  469. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  470. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.[]</listItem>' +
  471. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  472. );
  473. }
  474. );
  475. it(
  476. 'should copy the value for the list style attribute when indenting a single item into a nested list (changed value)',
  477. () => {
  478. setModelData( model,
  479. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  480. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  481. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>' +
  482. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  483. );
  484. editor.execute( 'indentList' );
  485. expect( getModelData( model ) ).to.equal(
  486. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  487. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  488. '<listItem listIndent="1" listStyle="disc" listType="bulleted">3.[]</listItem>' +
  489. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  490. );
  491. }
  492. );
  493. it( 'should copy the value for the list style attribute when indenting a single item into a nested list', () => {
  494. setModelData( model,
  495. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  496. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  497. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  498. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  499. );
  500. editor.execute( 'indentList' );
  501. expect( getModelData( model ) ).to.equal(
  502. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  503. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  504. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  505. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  506. );
  507. } );
  508. it(
  509. 'should copy the value for the list style attribute when indenting a single item into a nested list ' +
  510. '(many nested lists check)',
  511. () => {
  512. setModelData( model,
  513. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  514. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  515. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  516. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.[]</listItem>'
  517. );
  518. editor.execute( 'indentList' );
  519. expect( getModelData( model ) ).to.equal(
  520. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  521. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  522. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  523. '<listItem listIndent="1" listStyle="disc" listType="bulleted">4.[]</listItem>'
  524. );
  525. }
  526. );
  527. it( 'should inherit the list style attribute from nested list if the `listType` is other than indenting element', () => {
  528. setModelData( model,
  529. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  530. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.</listItem>' +
  531. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>'
  532. );
  533. editor.execute( 'indentList' );
  534. expect( getModelData( model ) ).to.equal(
  535. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  536. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.</listItem>' +
  537. '<listItem listIndent="1" listStyle="decimal" listType="numbered">3.[]</listItem>'
  538. );
  539. } );
  540. } );
  541. describe( 'outdenting lists', () => {
  542. it( 'should inherit the list style attribute from parent list (change the first nested item)', () => {
  543. setModelData( model,
  544. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  545. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  546. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  547. );
  548. editor.execute( 'outdentList' );
  549. expect( getModelData( model ) ).to.equal(
  550. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  551. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  552. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  553. );
  554. } );
  555. it( 'should inherit the list style attribute from parent list (change the second nested item)', () => {
  556. setModelData( model,
  557. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  558. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  559. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.[]</listItem>'
  560. );
  561. editor.execute( 'outdentList' );
  562. expect( getModelData( model ) ).to.equal(
  563. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  564. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  565. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>'
  566. );
  567. } );
  568. it( 'should inherit the list style attribute from parent list (modifying nested lists)', () => {
  569. setModelData( model,
  570. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  571. '<listItem listIndent="1" listStyle="default" listType="bulleted">[2.</listItem>' +
  572. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.]</listItem>'
  573. );
  574. editor.execute( 'outdentList' );
  575. expect( getModelData( model ) ).to.equal(
  576. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  577. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[2.</listItem>' +
  578. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.]</listItem>'
  579. );
  580. } );
  581. it(
  582. 'should inherit the list style attribute from parent list (outdenting many items, including the first one in the list)',
  583. () => {
  584. setModelData( model,
  585. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[1.</listItem>' +
  586. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  587. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.]</listItem>' +
  588. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  589. );
  590. editor.execute( 'outdentList' );
  591. expect( getModelData( model ) ).to.equal(
  592. '<paragraph>[1.</paragraph>' +
  593. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  594. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.]</listItem>' +
  595. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  596. );
  597. }
  598. );
  599. it(
  600. 'should inherit the list style attribute from parent list (outdenting the first item that is a parent for next list)',
  601. () => {
  602. setModelData( model,
  603. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  604. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  605. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  606. '<listItem listIndent="3" listStyle="disc" listType="bulleted">4.</listItem>' +
  607. '<listItem listIndent="0" listStyle="circle" listType="bulleted">5.</listItem>'
  608. );
  609. editor.execute( 'outdentList' );
  610. expect( getModelData( model ) ).to.equal(
  611. '<paragraph>1.[]</paragraph>' +
  612. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  613. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  614. '<listItem listIndent="2" listStyle="disc" listType="bulleted">4.</listItem>' +
  615. '<listItem listIndent="0" listStyle="circle" listType="bulleted">5.</listItem>'
  616. );
  617. }
  618. );
  619. it( 'should not inherit the list style if outdented the only one item in the list', () => {
  620. setModelData( model,
  621. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  622. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  623. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>'
  624. );
  625. editor.execute( 'outdentList' );
  626. expect( getModelData( model ) ).to.equal(
  627. '<paragraph>1.[]</paragraph>' +
  628. '<listItem listIndent="0" listStyle="disc" listType="bulleted">2.</listItem>' +
  629. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>'
  630. );
  631. } );
  632. it( 'should not inherit the list style if outdented the only one item in the list (a paragraph below the list)', () => {
  633. setModelData( model,
  634. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  635. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  636. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  637. '<paragraph>Foo</paragraph>'
  638. );
  639. editor.execute( 'outdentList' );
  640. expect( getModelData( model ) ).to.equal(
  641. '<paragraph>1.[]</paragraph>' +
  642. '<listItem listIndent="0" listStyle="disc" listType="bulleted">2.</listItem>' +
  643. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  644. '<paragraph>Foo</paragraph>'
  645. );
  646. } );
  647. it( 'should not inherit the list style attribute from parent list if the `listType` is other than outdenting element', () => {
  648. setModelData( model,
  649. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  650. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.[]</listItem>' +
  651. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  652. );
  653. editor.execute( 'outdentList' );
  654. expect( getModelData( model ) ).to.equal(
  655. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  656. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.[]</listItem>' +
  657. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  658. );
  659. } );
  660. it( 'should not do anything if there is no list after outdenting', () => {
  661. setModelData( model,
  662. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>'
  663. );
  664. editor.execute( 'outdentList' );
  665. expect( getModelData( model ) ).to.equal(
  666. '<paragraph>1.[]</paragraph>'
  667. );
  668. } );
  669. } );
  670. describe( 'indent/outdent + undo', () => {
  671. it( 'should use the same batch for indenting a list and updating `listType` attribute', () => {
  672. setModelData( model,
  673. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  674. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  675. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  676. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  677. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  678. );
  679. editor.execute( 'indentList' );
  680. editor.execute( 'undo' );
  681. expect( getModelData( model ) ).to.equal(
  682. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  683. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  684. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  685. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  686. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  687. );
  688. } );
  689. it( 'should use the same batch for outdenting a list and updating `listType` attribute', () => {
  690. setModelData( model,
  691. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  692. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  693. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  694. );
  695. editor.execute( 'outdentList' );
  696. editor.execute( 'undo' );
  697. expect( getModelData( model ) ).to.equal(
  698. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  699. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  700. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  701. );
  702. } );
  703. } );
  704. describe( 'todo list', () => {
  705. let editor, model;
  706. beforeEach( () => {
  707. return VirtualTestEditor
  708. .create( {
  709. // TodoListEditing is at the end by design. Check `ListStyleEditing.afterInit()` call.
  710. plugins: [ Paragraph, ListStyleEditing, TodoListEditing ]
  711. } )
  712. .then( newEditor => {
  713. editor = newEditor;
  714. model = editor.model;
  715. } );
  716. } );
  717. afterEach( () => {
  718. return editor.destroy();
  719. } );
  720. it( 'should not add the `listStyle` attribute while creating a todo list', () => {
  721. setModelData( model, '<paragraph>Foo[]</paragraph>' );
  722. editor.execute( 'todoList' );
  723. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  724. } );
  725. it( 'should not add the `listStyle` attribute while switching the list type', () => {
  726. setModelData( model, '<listItem listIndent="0" listType="bulleted">Foo[]</listItem>' );
  727. editor.execute( 'todoList' );
  728. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  729. } );
  730. it( 'should remove the `listStyle` attribute while switching the list type that uses the list style feature', () => {
  731. setModelData( model, '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo[]</listItem>' );
  732. editor.execute( 'todoList' );
  733. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  734. } );
  735. it( 'should not inherit the list style attribute when inserting a todo list item', () => {
  736. setModelData( model,
  737. '<paragraph>Foo Bar.[]</paragraph>' +
  738. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  739. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  740. );
  741. editor.execute( 'todoList' );
  742. expect( getModelData( model ) ).to.equal(
  743. '<listItem listIndent="0" listType="todo">Foo Bar.[]</listItem>' +
  744. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  745. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  746. );
  747. } );
  748. } );
  749. } );
  750. } );