liststyleediting.js 37 KB

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