liststyleediting.js 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246
  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 Typing from '@ckeditor/ckeditor5-typing/src/typing';
  8. import UndoEditing from '@ckeditor/ckeditor5-undo/src/undoediting';
  9. import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  10. import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
  11. import ListStyleEditing from '../src/liststyleediting';
  12. import TodoListEditing from '../src/todolistediting';
  13. import ListStyleCommand from '../src/liststylecommand';
  14. describe( 'ListStyleEditing', () => {
  15. let editor, model, view;
  16. beforeEach( () => {
  17. return VirtualTestEditor
  18. .create( {
  19. plugins: [ Paragraph, ListStyleEditing, UndoEditing ]
  20. } )
  21. .then( newEditor => {
  22. editor = newEditor;
  23. model = editor.model;
  24. view = editor.editing.view;
  25. } );
  26. } );
  27. afterEach( () => {
  28. return editor.destroy();
  29. } );
  30. it( 'should have pluginName', () => {
  31. expect( ListStyleEditing.pluginName ).to.equal( 'ListStyleEditing' );
  32. } );
  33. it( 'should be loaded', () => {
  34. expect( editor.plugins.get( ListStyleEditing ) ).to.be.instanceOf( ListStyleEditing );
  35. } );
  36. describe( 'schema rules', () => {
  37. it( 'should allow set `listStyle` on the `listItem`', () => {
  38. expect( model.schema.checkAttribute( [ '$root', 'listItem' ], 'listStyle' ) ).to.be.true;
  39. } );
  40. } );
  41. describe( 'command', () => {
  42. it( 'should register listStyle command', () => {
  43. const command = editor.commands.get( 'listStyle' );
  44. expect( command ).to.be.instanceOf( ListStyleCommand );
  45. } );
  46. } );
  47. describe( 'conversion in data pipeline', () => {
  48. describe( 'model to data', () => {
  49. it( 'should convert single list (type: bulleted)', () => {
  50. setModelData( model,
  51. '<listItem listIndent="0" listType="bulleted">Foo</listItem>' +
  52. '<listItem listIndent="0" listType="bulleted">Bar</listItem>'
  53. );
  54. expect( editor.getData() ).to.equal( '<ul><li>Foo</li><li>Bar</li></ul>' );
  55. } );
  56. it( 'should convert single list (type: numbered)', () => {
  57. setModelData( model,
  58. '<listItem listIndent="0" listType="numbered">Foo</listItem>' +
  59. '<listItem listIndent="0" listType="numbered">Bar</listItem>'
  60. );
  61. expect( editor.getData() ).to.equal( '<ol><li>Foo</li><li>Bar</li></ol>' );
  62. } );
  63. it( 'should convert single list (type: bulleted, style: default)', () => {
  64. setModelData( model,
  65. '<listItem listIndent="0" listType="bulleted" listStyle="default">Foo</listItem>' +
  66. '<listItem listIndent="0" listType="bulleted" listStyle="default">Bar</listItem>'
  67. );
  68. expect( editor.getData() ).to.equal( '<ul><li>Foo</li><li>Bar</li></ul>' );
  69. } );
  70. it( 'should convert single list (type: numbered, style: default)', () => {
  71. setModelData( model,
  72. '<listItem listIndent="0" listType="numbered" listStyle="default">Foo</listItem>' +
  73. '<listItem listIndent="0" listType="numbered" listStyle="default">Bar</listItem>'
  74. );
  75. expect( editor.getData() ).to.equal( '<ol><li>Foo</li><li>Bar</li></ol>' );
  76. } );
  77. it( 'should convert single list (type: bulleted, style: circle)', () => {
  78. setModelData( model,
  79. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo</listItem>' +
  80. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar</listItem>'
  81. );
  82. expect( editor.getData() ).to.equal( '<ul style="list-style-type:circle;"><li>Foo</li><li>Bar</li></ul>' );
  83. } );
  84. it( 'should convert single list (type: numbered, style: upper-alpha)', () => {
  85. setModelData( model,
  86. '<listItem listIndent="0" listType="numbered" listStyle="upper-alpha">Foo</listItem>' +
  87. '<listItem listIndent="0" listType="numbered" listStyle="upper-alpha">Bar</listItem>'
  88. );
  89. expect( editor.getData() ).to.equal( '<ol style="list-style-type:upper-alpha;"><li>Foo</li><li>Bar</li></ol>' );
  90. } );
  91. it( 'should convert nested bulleted lists (main: circle, nested: disc)', () => {
  92. setModelData( model,
  93. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 1</listItem>' +
  94. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 1</listItem>' +
  95. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 2</listItem>' +
  96. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 2</listItem>' +
  97. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 3</listItem>'
  98. );
  99. expect( editor.getData() ).to.equal(
  100. '<ul style="list-style-type:circle;">' +
  101. '<li>Foo 1' +
  102. '<ul style="list-style-type:disc;">' +
  103. '<li>Bar 1</li>' +
  104. '<li>Bar 2</li>' +
  105. '</ul>' +
  106. '</li>' +
  107. '<li>Foo 2</li>' +
  108. '<li>Foo 3</li>' +
  109. '</ul>'
  110. );
  111. } );
  112. it( 'should convert nested numbered lists (main: decimal-leading-zero, nested: lower-latin)', () => {
  113. setModelData( model,
  114. '<listItem listIndent="0" listType="numbered" listStyle="decimal-leading-zero">Foo 1</listItem>' +
  115. '<listItem listIndent="1" listType="numbered" listStyle="lower-latin">Bar 1</listItem>' +
  116. '<listItem listIndent="1" listType="numbered" listStyle="lower-latin">Bar 2</listItem>' +
  117. '<listItem listIndent="0" listType="numbered" listStyle="decimal-leading-zero">Foo 2</listItem>' +
  118. '<listItem listIndent="0" listType="numbered" listStyle="decimal-leading-zero">Foo 3</listItem>'
  119. );
  120. expect( editor.getData() ).to.equal(
  121. '<ol style="list-style-type:decimal-leading-zero;">' +
  122. '<li>Foo 1' +
  123. '<ol style="list-style-type:lower-latin;">' +
  124. '<li>Bar 1</li>' +
  125. '<li>Bar 2</li>' +
  126. '</ol>' +
  127. '</li>' +
  128. '<li>Foo 2</li>' +
  129. '<li>Foo 3</li>' +
  130. '</ol>'
  131. );
  132. } );
  133. it( 'should convert nested mixed lists (ul>ol, main: square, nested: lower-roman)', () => {
  134. setModelData( model,
  135. '<listItem listIndent="0" listType="bulleted" listStyle="square">Foo 1</listItem>' +
  136. '<listItem listIndent="1" listType="numbered" listStyle="lower-roman">Bar 1</listItem>' +
  137. '<listItem listIndent="1" listType="numbered" listStyle="lower-roman">Bar 2</listItem>' +
  138. '<listItem listIndent="0" listType="bulleted" listStyle="square">Foo 2</listItem>' +
  139. '<listItem listIndent="0" listType="bulleted" listStyle="square">Foo 3</listItem>'
  140. );
  141. expect( editor.getData() ).to.equal(
  142. '<ul style="list-style-type:square;">' +
  143. '<li>Foo 1' +
  144. '<ol style="list-style-type:lower-roman;">' +
  145. '<li>Bar 1</li>' +
  146. '<li>Bar 2</li>' +
  147. '</ol>' +
  148. '</li>' +
  149. '<li>Foo 2</li>' +
  150. '<li>Foo 3</li>' +
  151. '</ul>'
  152. );
  153. } );
  154. it( 'should produce nested lists (different `listIndent` attribute)', () => {
  155. setModelData( model,
  156. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 1</listItem>' +
  157. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 2</listItem>' +
  158. '<listItem listIndent="1" listType="numbered" listStyle="decimal">Bar 1</listItem>' +
  159. '<listItem listIndent="1" listType="numbered" listStyle="decimal">Bar 2</listItem>'
  160. );
  161. expect( editor.getData() ).to.equal(
  162. '<ol style="list-style-type:decimal;">' +
  163. '<li>Foo 1</li>' +
  164. '<li>Foo 2' +
  165. '<ol style="list-style-type:decimal;">' +
  166. '<li>Bar 1</li>' +
  167. '<li>Bar 2</li>' +
  168. '</ol>' +
  169. '</li>' +
  170. '</ol>'
  171. );
  172. } );
  173. it( 'should produce two different lists (different `listType` attribute)', () => {
  174. setModelData( model,
  175. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 1</listItem>' +
  176. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 2</listItem>' +
  177. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Bar 1</listItem>' +
  178. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Bar 2</listItem>'
  179. );
  180. expect( editor.getData() ).to.equal(
  181. '<ol style="list-style-type:decimal;">' +
  182. '<li>Foo 1</li>' +
  183. '<li>Foo 2</li>' +
  184. '</ol>' +
  185. '<ul style="list-style-type:disc;">' +
  186. '<li>Bar 1</li>' +
  187. '<li>Bar 2</li>' +
  188. '</ul>'
  189. );
  190. } );
  191. it( 'should produce two different lists (different `listStyle` attribute)', () => {
  192. setModelData( model,
  193. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Foo 1</listItem>' +
  194. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Foo 2</listItem>' +
  195. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar 1</listItem>' +
  196. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar 2</listItem>'
  197. );
  198. expect( editor.getData() ).to.equal(
  199. '<ul style="list-style-type:disc;">' +
  200. '<li>Foo 1</li>' +
  201. '<li>Foo 2</li>' +
  202. '</ul>' +
  203. '<ul style="list-style-type:circle;">' +
  204. '<li>Bar 1</li>' +
  205. '<li>Bar 2</li>' +
  206. '</ul>'
  207. );
  208. } );
  209. it( 'should not allow to set the `listStyle` attribute in to-do list item', () => {
  210. setModelData( model, '<listItem listIndent="0" listType="todo">Foo</listItem>' );
  211. const listItem = model.document.getRoot().getChild( 0 );
  212. expect( listItem.hasAttribute( 'listItem' ) ).to.be.false;
  213. model.change( writer => {
  214. writer.setAttribute( 'listType', 'foo', listItem );
  215. } );
  216. expect( listItem.hasAttribute( 'listItem' ) ).to.be.false;
  217. } );
  218. } );
  219. describe( 'view to model', () => {
  220. it( 'should convert single list (type: bulleted)', () => {
  221. editor.setData( '<ul><li>Foo</li><li>Bar</li></ul>' );
  222. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  223. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo</listItem>' +
  224. '<listItem listIndent="0" listStyle="default" listType="bulleted">Bar</listItem>'
  225. );
  226. } );
  227. it( 'should convert single list (type: numbered)', () => {
  228. editor.setData( '<ol><li>Foo</li><li>Bar</li></ol>' );
  229. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  230. '<listItem listIndent="0" listStyle="default" listType="numbered">Foo</listItem>' +
  231. '<listItem listIndent="0" listStyle="default" listType="numbered">Bar</listItem>'
  232. );
  233. } );
  234. it( 'should convert single list (type: bulleted, style: circle)', () => {
  235. editor.setData( '<ul style="list-style-type:circle;"><li>Foo</li><li>Bar</li></ul>' );
  236. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  237. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  238. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  239. );
  240. } );
  241. it( 'should convert single list (type: numbered, style: upper-alpha)', () => {
  242. editor.setData( '<ol style="list-style-type:upper-alpha;"><li>Foo</li><li>Bar</li></ol>' );
  243. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  244. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Foo</listItem>' +
  245. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Bar</listItem>'
  246. );
  247. } );
  248. it( 'should convert nested and mixed lists', () => {
  249. editor.setData(
  250. '<ol style="list-style-type:upper-alpha;">' +
  251. '<li>OL 1</li>' +
  252. '<li>OL 2' +
  253. '<ul style="list-style-type:circle;">' +
  254. '<li>UL 1</li>' +
  255. '<li>UL 2</li>' +
  256. '</ul>' +
  257. '</li>' +
  258. '<li>OL 3</li>' +
  259. '</ol>'
  260. );
  261. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  262. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">OL 1</listItem>' +
  263. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">OL 2</listItem>' +
  264. '<listItem listIndent="1" listStyle="circle" listType="bulleted">UL 1</listItem>' +
  265. '<listItem listIndent="1" listStyle="circle" listType="bulleted">UL 2</listItem>' +
  266. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">OL 3</listItem>'
  267. );
  268. } );
  269. it( 'should convert when the list is in the middle of the content', () => {
  270. editor.setData(
  271. '<p>Paragraph.</p>' +
  272. '<ol style="list-style-type:upper-alpha;">' +
  273. '<li>Foo</li>' +
  274. '<li>Bar</li>' +
  275. '</ol>' +
  276. '<p>Paragraph.</p>'
  277. );
  278. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  279. '<paragraph>Paragraph.</paragraph>' +
  280. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Foo</listItem>' +
  281. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Bar</listItem>' +
  282. '<paragraph>Paragraph.</paragraph>'
  283. );
  284. } );
  285. } );
  286. } );
  287. // At this moment editing and data pipelines produce exactly the same content.
  288. // Just a few tests will be enough here. `model to data` block contains all cases checked.
  289. describe( 'conversion in editing pipeline', () => {
  290. describe( 'model to view', () => {
  291. it( 'should convert single list (type: bulleted, style: default)', () => {
  292. setModelData( model,
  293. '<listItem listIndent="0" listType="bulleted" listStyle="default">Foo</listItem>' +
  294. '<listItem listIndent="0" listType="bulleted" listStyle="default">Bar</listItem>'
  295. );
  296. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  297. '<ul><li>Foo</li><li>Bar</li></ul>'
  298. );
  299. } );
  300. it( 'should convert single list (type: bulleted, style: circle)', () => {
  301. setModelData( model,
  302. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo</listItem>' +
  303. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar</listItem>'
  304. );
  305. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  306. '<ul style="list-style-type:circle"><li>Foo</li><li>Bar</li></ul>'
  307. );
  308. } );
  309. it( 'should convert nested bulleted lists (main: circle, nested: disc)', () => {
  310. setModelData( model,
  311. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 1</listItem>' +
  312. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 1</listItem>' +
  313. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 2</listItem>' +
  314. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 2</listItem>' +
  315. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 3</listItem>'
  316. );
  317. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  318. '<ul style="list-style-type:circle">' +
  319. '<li>Foo 1' +
  320. '<ul style="list-style-type:disc">' +
  321. '<li>Bar 1</li>' +
  322. '<li>Bar 2</li>' +
  323. '</ul>' +
  324. '</li>' +
  325. '<li>Foo 2</li>' +
  326. '<li>Foo 3</li>' +
  327. '</ul>'
  328. );
  329. } );
  330. } );
  331. } );
  332. describe( 'integrations', () => {
  333. describe( 'merging a list into a styled list', () => {
  334. it( 'should inherit the list style attribute when merging the same kind of lists (from top, merge a single item)', () => {
  335. setModelData( model,
  336. '<paragraph>Foo Bar.[]</paragraph>' +
  337. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  338. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  339. );
  340. editor.execute( 'bulletedList' );
  341. expect( getModelData( model ) ).to.equal(
  342. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>' +
  343. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  344. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  345. );
  346. } );
  347. it( 'should inherit the list style attribute when merging the same kind of lists (from top, merge a few items)', () => {
  348. setModelData( model,
  349. '<paragraph>[Foo Bar 1.</paragraph>' +
  350. '<paragraph>Foo Bar 2.]</paragraph>' +
  351. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  352. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  353. );
  354. editor.execute( 'bulletedList' );
  355. expect( getModelData( model ) ).to.equal(
  356. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[Foo Bar 1.</listItem>' +
  357. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar 2.]</listItem>' +
  358. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  359. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  360. );
  361. } );
  362. it( 'should not inherit anything if there is no list below the inserted list', () => {
  363. setModelData( model,
  364. '<paragraph>Foo Bar 1.[]</paragraph>' +
  365. '<paragraph>Foo Bar 2.</paragraph>'
  366. );
  367. editor.execute( 'bulletedList' );
  368. expect( getModelData( model ) ).to.equal(
  369. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar 1.[]</listItem>' +
  370. '<paragraph>Foo Bar 2.</paragraph>'
  371. );
  372. } );
  373. it( 'should not inherit anything if replacing the entire content with a list', () => {
  374. setModelData( model,
  375. '<paragraph>Foo Bar 1.[]</paragraph>'
  376. );
  377. editor.execute( 'bulletedList' );
  378. expect( getModelData( model ) ).to.equal(
  379. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar 1.[]</listItem>'
  380. );
  381. } );
  382. it( 'should not inherit the list style attribute when merging different kind of lists (from top, merge a single item)', () => {
  383. setModelData( model,
  384. '<paragraph>Foo Bar.[]</paragraph>' +
  385. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  386. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>'
  387. );
  388. editor.execute( 'bulletedList' );
  389. expect( getModelData( model ) ).to.equal(
  390. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>' +
  391. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  392. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>'
  393. );
  394. } );
  395. it(
  396. 'should not inherit the list style attribute when merging different kind of lists (from bottom, merge a single item)',
  397. () => {
  398. setModelData( model,
  399. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  400. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>' +
  401. '<paragraph>Foo Bar.[]</paragraph>'
  402. );
  403. editor.execute( 'bulletedList' );
  404. expect( getModelData( model ) ).to.equal(
  405. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  406. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>' +
  407. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>'
  408. );
  409. }
  410. );
  411. it( 'should inherit the list style attribute when merging the same kind of lists (from bottom, merge a single item)', () => {
  412. setModelData( model,
  413. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  414. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  415. '<paragraph>Foo Bar.[]</paragraph>'
  416. );
  417. editor.execute( 'bulletedList' );
  418. expect( getModelData( model ) ).to.equal(
  419. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  420. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  421. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>'
  422. );
  423. } );
  424. it(
  425. 'should inherit the list style attribute from listIndent=0 element when merging the same kind of lists (from bottom)',
  426. () => {
  427. setModelData( model,
  428. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  429. '<listItem listIndent="1" listStyle="square" listType="bulleted">Bar</listItem>' +
  430. '<listItem listIndent="2" listStyle="disc" listType="bulleted">Foo Bar</listItem>' +
  431. '<paragraph>Foo Bar.[]</paragraph>'
  432. );
  433. editor.execute( 'bulletedList' );
  434. expect( getModelData( model ) ).to.equal(
  435. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  436. '<listItem listIndent="1" listStyle="square" listType="bulleted">Bar</listItem>' +
  437. '<listItem listIndent="2" listStyle="disc" listType="bulleted">Foo Bar</listItem>' +
  438. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>'
  439. );
  440. }
  441. );
  442. } );
  443. describe( 'modifying "listType" attribute', () => {
  444. it( 'should inherit the list style attribute when the modified list is the same kind of the list as next sibling', () => {
  445. setModelData( model,
  446. '<listItem listIndent="0" listStyle="default" listType="numbered">Foo Bar.[]</listItem>' +
  447. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  448. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  449. );
  450. editor.execute( 'bulletedList' );
  451. expect( getModelData( model ) ).to.equal(
  452. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>' +
  453. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  454. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  455. );
  456. } );
  457. it( 'should inherit the list style attribute when the modified list is the same kind of the list as previous sibling', () => {
  458. setModelData( model,
  459. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  460. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  461. '<listItem listIndent="0" listStyle="default" listType="numbered">Foo Bar.[]</listItem>'
  462. );
  463. editor.execute( 'bulletedList' );
  464. expect( getModelData( model ) ).to.equal(
  465. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  466. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  467. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>'
  468. );
  469. } );
  470. it( 'should not inherit the list style attribute when the modified list already has defined it (next sibling check)', () => {
  471. setModelData( model,
  472. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>' +
  473. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  474. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  475. );
  476. editor.execute( 'listStyle', { type: 'disc' } );
  477. expect( getModelData( model ) ).to.equal(
  478. '<listItem listIndent="0" listStyle="disc" listType="bulleted">Foo Bar.[]</listItem>' +
  479. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  480. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  481. );
  482. } );
  483. it(
  484. 'should not inherit the list style attribute when the modified list already has defined it (previous sibling check)',
  485. () => {
  486. setModelData( model,
  487. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  488. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  489. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>'
  490. );
  491. editor.execute( 'listStyle', { type: 'disc' } );
  492. expect( getModelData( model ) ).to.equal(
  493. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  494. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  495. '<listItem listIndent="0" listStyle="disc" listType="bulleted">Foo Bar.[]</listItem>'
  496. );
  497. }
  498. );
  499. } );
  500. describe( 'indenting lists', () => {
  501. it( 'should restore the default value for the list style attribute when indenting a single item', () => {
  502. setModelData( model,
  503. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  504. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  505. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  506. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  507. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  508. );
  509. editor.execute( 'indentList' );
  510. expect( getModelData( model ) ).to.equal(
  511. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  512. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  513. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  514. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  515. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  516. );
  517. } );
  518. it( 'should restore the default value for the list style attribute when indenting a few items', () => {
  519. setModelData( model,
  520. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  521. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[2.</listItem>' +
  522. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.]</listItem>'
  523. );
  524. editor.execute( 'indentList' );
  525. expect( getModelData( model ) ).to.equal(
  526. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  527. '<listItem listIndent="1" listStyle="default" listType="bulleted">[2.</listItem>' +
  528. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.]</listItem>'
  529. );
  530. } );
  531. it(
  532. 'should copy the value for the list style attribute when indenting a single item into a nested list (default value)',
  533. () => {
  534. setModelData( model,
  535. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  536. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  537. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>' +
  538. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  539. );
  540. editor.execute( 'indentList' );
  541. expect( getModelData( model ) ).to.equal(
  542. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  543. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  544. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.[]</listItem>' +
  545. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  546. );
  547. }
  548. );
  549. it(
  550. 'should copy the value for the list style attribute when indenting a single item into a nested list (changed value)',
  551. () => {
  552. setModelData( model,
  553. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  554. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  555. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>' +
  556. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  557. );
  558. editor.execute( 'indentList' );
  559. expect( getModelData( model ) ).to.equal(
  560. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  561. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  562. '<listItem listIndent="1" listStyle="disc" listType="bulleted">3.[]</listItem>' +
  563. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  564. );
  565. }
  566. );
  567. it( 'should copy the value for the list style attribute when indenting a single item into a nested list', () => {
  568. setModelData( model,
  569. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  570. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  571. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  572. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  573. );
  574. editor.execute( 'indentList' );
  575. expect( getModelData( model ) ).to.equal(
  576. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  577. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  578. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  579. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  580. );
  581. } );
  582. it(
  583. 'should copy the value for the list style attribute when indenting a single item into a nested list ' +
  584. '(many nested lists check)',
  585. () => {
  586. setModelData( model,
  587. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  588. '<listItem listIndent="1" listStyle="disc" 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( 'indentList' );
  593. expect( getModelData( model ) ).to.equal(
  594. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  595. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  596. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  597. '<listItem listIndent="1" listStyle="disc" listType="bulleted">4.[]</listItem>'
  598. );
  599. }
  600. );
  601. it( 'should inherit the list style attribute from nested list if the `listType` is other than indenting element', () => {
  602. setModelData( model,
  603. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  604. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.</listItem>' +
  605. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>'
  606. );
  607. editor.execute( 'indentList' );
  608. expect( getModelData( model ) ).to.equal(
  609. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  610. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.</listItem>' +
  611. '<listItem listIndent="1" listStyle="decimal" listType="numbered">3.[]</listItem>'
  612. );
  613. } );
  614. } );
  615. describe( 'outdenting lists', () => {
  616. it( 'should inherit the list style attribute from parent list (change the first nested item)', () => {
  617. setModelData( model,
  618. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  619. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  620. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  621. );
  622. editor.execute( 'outdentList' );
  623. expect( getModelData( model ) ).to.equal(
  624. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  625. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  626. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  627. );
  628. } );
  629. it( 'should inherit the list style attribute from parent list (change the second nested item)', () => {
  630. setModelData( model,
  631. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  632. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  633. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.[]</listItem>'
  634. );
  635. editor.execute( 'outdentList' );
  636. expect( getModelData( model ) ).to.equal(
  637. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  638. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  639. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>'
  640. );
  641. } );
  642. it( 'should inherit the list style attribute from parent list (modifying nested lists)', () => {
  643. setModelData( model,
  644. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  645. '<listItem listIndent="1" listStyle="default" listType="bulleted">[2.</listItem>' +
  646. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.]</listItem>'
  647. );
  648. editor.execute( 'outdentList' );
  649. expect( getModelData( model ) ).to.equal(
  650. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  651. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[2.</listItem>' +
  652. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.]</listItem>'
  653. );
  654. } );
  655. it(
  656. 'should inherit the list style attribute from parent list (outdenting many items, including the first one in the list)',
  657. () => {
  658. setModelData( model,
  659. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[1.</listItem>' +
  660. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  661. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.]</listItem>' +
  662. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  663. );
  664. editor.execute( 'outdentList' );
  665. expect( getModelData( model ) ).to.equal(
  666. '<paragraph>[1.</paragraph>' +
  667. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  668. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.]</listItem>' +
  669. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  670. );
  671. }
  672. );
  673. it(
  674. 'should inherit the list style attribute from parent list (outdenting the first item that is a parent for next list)',
  675. () => {
  676. setModelData( model,
  677. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  678. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  679. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  680. '<listItem listIndent="3" listStyle="disc" listType="bulleted">4.</listItem>' +
  681. '<listItem listIndent="0" listStyle="circle" listType="bulleted">5.</listItem>'
  682. );
  683. editor.execute( 'outdentList' );
  684. expect( getModelData( model ) ).to.equal(
  685. '<paragraph>1.[]</paragraph>' +
  686. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  687. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  688. '<listItem listIndent="2" listStyle="disc" listType="bulleted">4.</listItem>' +
  689. '<listItem listIndent="0" listStyle="circle" listType="bulleted">5.</listItem>'
  690. );
  691. }
  692. );
  693. it( 'should not inherit the list style if outdented the only one item in the list', () => {
  694. setModelData( model,
  695. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  696. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  697. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>'
  698. );
  699. editor.execute( 'outdentList' );
  700. expect( getModelData( model ) ).to.equal(
  701. '<paragraph>1.[]</paragraph>' +
  702. '<listItem listIndent="0" listStyle="disc" listType="bulleted">2.</listItem>' +
  703. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>'
  704. );
  705. } );
  706. it( 'should not inherit the list style if outdented the only one item in the list (a paragraph below the list)', () => {
  707. setModelData( model,
  708. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  709. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  710. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  711. '<paragraph>Foo</paragraph>'
  712. );
  713. editor.execute( 'outdentList' );
  714. expect( getModelData( model ) ).to.equal(
  715. '<paragraph>1.[]</paragraph>' +
  716. '<listItem listIndent="0" listStyle="disc" listType="bulleted">2.</listItem>' +
  717. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  718. '<paragraph>Foo</paragraph>'
  719. );
  720. } );
  721. it( 'should not inherit the list style attribute from parent list if the `listType` is other than outdenting element', () => {
  722. setModelData( model,
  723. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  724. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.[]</listItem>' +
  725. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  726. );
  727. editor.execute( 'outdentList' );
  728. expect( getModelData( model ) ).to.equal(
  729. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  730. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.[]</listItem>' +
  731. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  732. );
  733. } );
  734. it( 'should not do anything if there is no list after outdenting', () => {
  735. setModelData( model,
  736. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>'
  737. );
  738. editor.execute( 'outdentList' );
  739. expect( getModelData( model ) ).to.equal(
  740. '<paragraph>1.[]</paragraph>'
  741. );
  742. } );
  743. } );
  744. describe( 'indent/outdent + undo', () => {
  745. it( 'should use the same batch for indenting a list and updating `listType` attribute', () => {
  746. setModelData( model,
  747. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  748. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  749. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  750. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  751. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  752. );
  753. editor.execute( 'indentList' );
  754. editor.execute( 'undo' );
  755. expect( getModelData( model ) ).to.equal(
  756. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  757. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  758. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  759. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  760. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  761. );
  762. } );
  763. it( 'should use the same batch for outdenting a list and updating `listType` attribute', () => {
  764. setModelData( model,
  765. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  766. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  767. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  768. );
  769. editor.execute( 'outdentList' );
  770. editor.execute( 'undo' );
  771. expect( getModelData( model ) ).to.equal(
  772. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  773. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  774. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  775. );
  776. } );
  777. } );
  778. describe( 'todo list', () => {
  779. let editor, model;
  780. beforeEach( () => {
  781. return VirtualTestEditor
  782. .create( {
  783. // TodoListEditing is at the end by design. Check `ListStyleEditing.afterInit()` call.
  784. plugins: [ Paragraph, ListStyleEditing, TodoListEditing ]
  785. } )
  786. .then( newEditor => {
  787. editor = newEditor;
  788. model = editor.model;
  789. } );
  790. } );
  791. afterEach( () => {
  792. return editor.destroy();
  793. } );
  794. it( 'should not add the `listStyle` attribute while creating a todo list', () => {
  795. setModelData( model, '<paragraph>Foo[]</paragraph>' );
  796. editor.execute( 'todoList' );
  797. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  798. } );
  799. it( 'should not add the `listStyle` attribute while switching the list type', () => {
  800. setModelData( model, '<listItem listIndent="0" listType="bulleted">Foo[]</listItem>' );
  801. editor.execute( 'todoList' );
  802. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  803. } );
  804. it( 'should remove the `listStyle` attribute while switching the list type that uses the list style feature', () => {
  805. setModelData( model, '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo[]</listItem>' );
  806. editor.execute( 'todoList' );
  807. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  808. } );
  809. it( 'should not inherit the list style attribute when inserting a todo list item', () => {
  810. setModelData( model,
  811. '<paragraph>Foo Bar.[]</paragraph>' +
  812. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  813. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  814. );
  815. editor.execute( 'todoList' );
  816. expect( getModelData( model ) ).to.equal(
  817. '<listItem listIndent="0" listType="todo">Foo Bar.[]</listItem>' +
  818. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  819. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  820. );
  821. } );
  822. } );
  823. describe( 'removing content between two lists', () => {
  824. let editor, model;
  825. beforeEach( () => {
  826. return VirtualTestEditor
  827. .create( {
  828. plugins: [ Paragraph, ListStyleEditing, Typing ]
  829. } )
  830. .then( newEditor => {
  831. editor = newEditor;
  832. model = editor.model;
  833. } );
  834. } );
  835. afterEach( () => {
  836. return editor.destroy();
  837. } );
  838. it( 'should not do anything while removing a letter inside a listItem', () => {
  839. setModelData( model,
  840. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  841. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  842. '<paragraph></paragraph>' +
  843. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  844. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  845. );
  846. editor.execute( 'delete' );
  847. expect( getModelData( model ) ).to.equal(
  848. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  849. '<listItem listIndent="0" listStyle="square" listType="bulleted">2[]</listItem>' +
  850. '<paragraph></paragraph>' +
  851. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  852. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  853. );
  854. } );
  855. it( 'should not do anything if there is a non-listItem before the removed content', () => {
  856. setModelData( model,
  857. '<paragraph>Foo</paragraph>' +
  858. '<paragraph>[]</paragraph>' +
  859. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  860. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  861. );
  862. editor.execute( 'delete' );
  863. expect( getModelData( model ) ).to.equal(
  864. '<paragraph>Foo[]</paragraph>' +
  865. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  866. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  867. );
  868. } );
  869. it( 'should not do anything if there is a non-listItem after the removed content', () => {
  870. setModelData( model,
  871. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  872. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  873. '<paragraph>[]</paragraph>' +
  874. '<paragraph>Foo</paragraph>'
  875. );
  876. editor.execute( 'delete' );
  877. expect( getModelData( model ) ).to.equal(
  878. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  879. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  880. '<paragraph>Foo</paragraph>'
  881. );
  882. } );
  883. it( 'should not do anything if there is no element after the removed content', () => {
  884. setModelData( model,
  885. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  886. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  887. '<paragraph>[]</paragraph>'
  888. );
  889. editor.execute( 'delete' );
  890. expect( getModelData( model ) ).to.equal(
  891. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  892. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>'
  893. );
  894. } );
  895. it(
  896. 'should modify the the `listStyle` attribute for the merged (second) list when removing content between those lists',
  897. () => {
  898. setModelData( model,
  899. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  900. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  901. '<paragraph>[]</paragraph>' +
  902. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  903. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  904. );
  905. editor.execute( 'delete' );
  906. expect( getModelData( model ) ).to.equal(
  907. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  908. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  909. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  910. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  911. );
  912. }
  913. );
  914. it( 'should read the `listStyle` attribute from the most outer list', () => {
  915. setModelData( model,
  916. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  917. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  918. '<listItem listIndent="1" listStyle="numbered" listType="decimal">2.1.</listItem>' +
  919. '<listItem listIndent="2" listStyle="default" listType="default">2.1.1</listItem>' +
  920. '<paragraph>[]</paragraph>' +
  921. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  922. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  923. );
  924. editor.execute( 'delete' );
  925. expect( getModelData( model ) ).to.equal(
  926. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  927. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  928. '<listItem listIndent="1" listStyle="numbered" listType="decimal">2.1.</listItem>' +
  929. '<listItem listIndent="2" listStyle="default" listType="default">2.1.1[]</listItem>' +
  930. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  931. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  932. );
  933. } );
  934. it(
  935. 'should not modify the the `listStyle` attribute for the merged (second) list if merging different `listType` attribute',
  936. () => {
  937. setModelData( model,
  938. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  939. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  940. '<paragraph>[]</paragraph>' +
  941. '<listItem listIndent="0" listStyle="decimal" listType="numbered">1.</listItem>' +
  942. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.</listItem>'
  943. );
  944. editor.execute( 'delete' );
  945. expect( getModelData( model ) ).to.equal(
  946. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  947. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  948. '<listItem listIndent="0" listStyle="decimal" listType="numbered">1.</listItem>' +
  949. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.</listItem>'
  950. );
  951. }
  952. );
  953. it(
  954. 'should modify the the `listStyle` attribute for the merged (second) list when removing content from both lists',
  955. () => {
  956. setModelData( model,
  957. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  958. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  959. '<listItem listIndent="0" listStyle="square" listType="bulleted">[3.</listItem>' +
  960. '<paragraph>Foo</paragraph>' +
  961. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.]</listItem>' +
  962. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  963. );
  964. editor.execute( 'delete' );
  965. expect( getModelData( model ) ).to.equal(
  966. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  967. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  968. '<listItem listIndent="0" listStyle="square" listType="bulleted">[]</listItem>' +
  969. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  970. );
  971. }
  972. );
  973. it(
  974. 'should modify the the `listStyle` attribute for the merged (second) list when typing over content from both lists',
  975. () => {
  976. setModelData( model,
  977. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  978. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  979. '<listItem listIndent="0" listStyle="square" listType="bulleted">[3.</listItem>' +
  980. '<paragraph>Foo</paragraph>' +
  981. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.]</listItem>' +
  982. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  983. );
  984. editor.execute( 'input', { text: 'Foo' } );
  985. expect( getModelData( model ) ).to.equal(
  986. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  987. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  988. '<listItem listIndent="0" listStyle="square" listType="bulleted">Foo[]</listItem>' +
  989. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  990. );
  991. }
  992. );
  993. it(
  994. 'should not modify the the `listStyle` if lists were not merged but the content was partially removed',
  995. () => {
  996. setModelData( model,
  997. '<listItem listIndent="0" listStyle="square" listType="bulleted">111.</listItem>' +
  998. '<listItem listIndent="0" listStyle="square" listType="bulleted">222.</listItem>' +
  999. '<listItem listIndent="0" listStyle="square" listType="bulleted">[333.</listItem>' +
  1000. '<paragraph>Foo</paragraph>' +
  1001. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1]11.</listItem>' +
  1002. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1003. );
  1004. editor.execute( 'delete' );
  1005. expect( getModelData( model ) ).to.equal(
  1006. '<listItem listIndent="0" listStyle="square" listType="bulleted">111.</listItem>' +
  1007. '<listItem listIndent="0" listStyle="square" listType="bulleted">222.</listItem>' +
  1008. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[]11.</listItem>' +
  1009. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1010. );
  1011. }
  1012. );
  1013. it( 'should not do anything while typing in a list item', () => {
  1014. setModelData( model,
  1015. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1016. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  1017. '<listItem listIndent="0" listStyle="square" listType="bulleted">3.</listItem>' +
  1018. '<paragraph></paragraph>' +
  1019. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1020. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1021. );
  1022. const modelChangeStub = sinon.stub( model, 'change' ).callThrough();
  1023. simulateTyping( ' Foo' );
  1024. // Each character calls `editor.model.change()`.
  1025. expect( modelChangeStub.callCount ).to.equal( 4 );
  1026. expect( getModelData( model ) ).to.equal(
  1027. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1028. '<listItem listIndent="0" listStyle="square" listType="bulleted">2. Foo[]</listItem>' +
  1029. '<listItem listIndent="0" listStyle="square" listType="bulleted">3.</listItem>' +
  1030. '<paragraph></paragraph>' +
  1031. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1032. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1033. );
  1034. } );
  1035. function simulateTyping( text ) {
  1036. // While typing, every character is an atomic change.
  1037. text.split( '' ).forEach( character => {
  1038. editor.execute( 'input', {
  1039. text: character
  1040. } );
  1041. } );
  1042. }
  1043. } );
  1044. } );
  1045. } );