8
0

liststyleediting.js 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300
  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. // See: #8072.
  615. it( 'should not throw when indenting a list without any other content in the editor', () => {
  616. setModelData( model,
  617. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo</listItem>' +
  618. '<listItem listIndent="0" listStyle="default" listType="bulleted">[]</listItem>'
  619. );
  620. editor.execute( 'indentList' );
  621. expect( getModelData( model ) ).to.equal(
  622. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo</listItem>' +
  623. '<listItem listIndent="1" listStyle="default" listType="bulleted">[]</listItem>'
  624. );
  625. } );
  626. } );
  627. describe( 'outdenting lists', () => {
  628. it( 'should inherit the list style attribute from parent list (change the first nested item)', () => {
  629. setModelData( model,
  630. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  631. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  632. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  633. );
  634. editor.execute( 'outdentList' );
  635. expect( getModelData( model ) ).to.equal(
  636. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  637. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  638. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  639. );
  640. } );
  641. it( 'should inherit the list style attribute from parent list (change the second nested item)', () => {
  642. setModelData( model,
  643. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  644. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  645. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.[]</listItem>'
  646. );
  647. editor.execute( 'outdentList' );
  648. expect( getModelData( model ) ).to.equal(
  649. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  650. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  651. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>'
  652. );
  653. } );
  654. it( 'should inherit the list style attribute from parent list (modifying nested lists)', () => {
  655. setModelData( model,
  656. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  657. '<listItem listIndent="1" listStyle="default" listType="bulleted">[2.</listItem>' +
  658. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.]</listItem>'
  659. );
  660. editor.execute( 'outdentList' );
  661. expect( getModelData( model ) ).to.equal(
  662. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  663. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[2.</listItem>' +
  664. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.]</listItem>'
  665. );
  666. } );
  667. it(
  668. 'should inherit the list style attribute from parent list (outdenting many items, including the first one in the list)',
  669. () => {
  670. setModelData( model,
  671. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[1.</listItem>' +
  672. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  673. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.]</listItem>' +
  674. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  675. );
  676. editor.execute( 'outdentList' );
  677. expect( getModelData( model ) ).to.equal(
  678. '<paragraph>[1.</paragraph>' +
  679. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  680. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.]</listItem>' +
  681. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  682. );
  683. }
  684. );
  685. it(
  686. 'should inherit the list style attribute from parent list (outdenting the first item that is a parent for next list)',
  687. () => {
  688. setModelData( model,
  689. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  690. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  691. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  692. '<listItem listIndent="3" listStyle="disc" listType="bulleted">4.</listItem>' +
  693. '<listItem listIndent="0" listStyle="circle" listType="bulleted">5.</listItem>'
  694. );
  695. editor.execute( 'outdentList' );
  696. expect( getModelData( model ) ).to.equal(
  697. '<paragraph>1.[]</paragraph>' +
  698. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  699. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  700. '<listItem listIndent="2" listStyle="disc" listType="bulleted">4.</listItem>' +
  701. '<listItem listIndent="0" listStyle="circle" listType="bulleted">5.</listItem>'
  702. );
  703. }
  704. );
  705. it( 'should not inherit the list style if outdented the only one item in the list', () => {
  706. setModelData( model,
  707. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  708. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  709. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>'
  710. );
  711. editor.execute( 'outdentList' );
  712. expect( getModelData( model ) ).to.equal(
  713. '<paragraph>1.[]</paragraph>' +
  714. '<listItem listIndent="0" listStyle="disc" listType="bulleted">2.</listItem>' +
  715. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>'
  716. );
  717. } );
  718. it( 'should not inherit the list style if outdented the only one item in the list (a paragraph below the list)', () => {
  719. setModelData( model,
  720. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  721. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  722. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  723. '<paragraph>Foo</paragraph>'
  724. );
  725. editor.execute( 'outdentList' );
  726. expect( getModelData( model ) ).to.equal(
  727. '<paragraph>1.[]</paragraph>' +
  728. '<listItem listIndent="0" listStyle="disc" listType="bulleted">2.</listItem>' +
  729. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  730. '<paragraph>Foo</paragraph>'
  731. );
  732. } );
  733. it( 'should not inherit the list style attribute from parent list if the `listType` is other than outdenting element', () => {
  734. setModelData( model,
  735. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  736. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.[]</listItem>' +
  737. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  738. );
  739. editor.execute( 'outdentList' );
  740. expect( getModelData( model ) ).to.equal(
  741. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  742. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.[]</listItem>' +
  743. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  744. );
  745. } );
  746. it( 'should not do anything if there is no list after outdenting', () => {
  747. setModelData( model,
  748. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>'
  749. );
  750. editor.execute( 'outdentList' );
  751. expect( getModelData( model ) ).to.equal(
  752. '<paragraph>1.[]</paragraph>'
  753. );
  754. } );
  755. } );
  756. describe( 'indent/outdent + undo', () => {
  757. it( 'should use the same batch for indenting a list and updating `listType` attribute', () => {
  758. setModelData( model,
  759. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  760. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  761. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  762. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  763. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  764. );
  765. editor.execute( 'indentList' );
  766. editor.execute( 'undo' );
  767. expect( getModelData( model ) ).to.equal(
  768. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  769. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  770. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  771. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  772. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  773. );
  774. } );
  775. it( 'should use the same batch for outdenting a list and updating `listType` attribute', () => {
  776. setModelData( model,
  777. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  778. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  779. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  780. );
  781. editor.execute( 'outdentList' );
  782. editor.execute( 'undo' );
  783. expect( getModelData( model ) ).to.equal(
  784. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  785. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  786. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  787. );
  788. } );
  789. } );
  790. describe( 'todo list', () => {
  791. let editor, model;
  792. beforeEach( () => {
  793. return VirtualTestEditor
  794. .create( {
  795. // TodoListEditing is at the end by design. Check `ListStyleEditing.afterInit()` call.
  796. plugins: [ Paragraph, ListStyleEditing, TodoListEditing ]
  797. } )
  798. .then( newEditor => {
  799. editor = newEditor;
  800. model = editor.model;
  801. } );
  802. } );
  803. afterEach( () => {
  804. return editor.destroy();
  805. } );
  806. it( 'should not add the `listStyle` attribute while creating a todo list', () => {
  807. setModelData( model, '<paragraph>Foo[]</paragraph>' );
  808. editor.execute( 'todoList' );
  809. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  810. } );
  811. it( 'should not add the `listStyle` attribute while switching the list type', () => {
  812. setModelData( model, '<listItem listIndent="0" listType="bulleted">Foo[]</listItem>' );
  813. editor.execute( 'todoList' );
  814. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  815. } );
  816. it( 'should remove the `listStyle` attribute while switching the list type that uses the list style feature', () => {
  817. setModelData( model, '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo[]</listItem>' );
  818. editor.execute( 'todoList' );
  819. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  820. } );
  821. it( 'should not inherit the list style attribute when inserting a todo list item', () => {
  822. setModelData( model,
  823. '<paragraph>Foo Bar.[]</paragraph>' +
  824. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  825. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  826. );
  827. editor.execute( 'todoList' );
  828. expect( getModelData( model ) ).to.equal(
  829. '<listItem listIndent="0" listType="todo">Foo Bar.[]</listItem>' +
  830. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  831. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  832. );
  833. } );
  834. } );
  835. describe( 'removing content between two lists', () => {
  836. let editor, model;
  837. beforeEach( () => {
  838. return VirtualTestEditor
  839. .create( {
  840. plugins: [ Paragraph, ListStyleEditing, Typing ]
  841. } )
  842. .then( newEditor => {
  843. editor = newEditor;
  844. model = editor.model;
  845. } );
  846. } );
  847. afterEach( () => {
  848. return editor.destroy();
  849. } );
  850. it( 'should not do anything while removing a letter inside a listItem', () => {
  851. setModelData( model,
  852. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  853. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  854. '<paragraph></paragraph>' +
  855. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  856. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  857. );
  858. editor.execute( 'delete' );
  859. expect( getModelData( model ) ).to.equal(
  860. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  861. '<listItem listIndent="0" listStyle="square" listType="bulleted">2[]</listItem>' +
  862. '<paragraph></paragraph>' +
  863. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  864. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  865. );
  866. } );
  867. it( 'should not do anything if there is a non-listItem before the removed content', () => {
  868. setModelData( model,
  869. '<paragraph>Foo</paragraph>' +
  870. '<paragraph>[]</paragraph>' +
  871. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  872. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  873. );
  874. editor.execute( 'delete' );
  875. expect( getModelData( model ) ).to.equal(
  876. '<paragraph>Foo[]</paragraph>' +
  877. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  878. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  879. );
  880. } );
  881. it( 'should not do anything if there is a non-listItem after the removed content', () => {
  882. setModelData( model,
  883. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  884. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  885. '<paragraph>[]</paragraph>' +
  886. '<paragraph>Foo</paragraph>'
  887. );
  888. editor.execute( 'delete' );
  889. expect( getModelData( model ) ).to.equal(
  890. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  891. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  892. '<paragraph>Foo</paragraph>'
  893. );
  894. } );
  895. it( 'should not do anything if there is no element after the removed content', () => {
  896. setModelData( model,
  897. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  898. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  899. '<paragraph>[]</paragraph>'
  900. );
  901. editor.execute( 'delete' );
  902. expect( getModelData( model ) ).to.equal(
  903. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  904. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>'
  905. );
  906. } );
  907. it(
  908. 'should modify the the `listStyle` attribute for the merged (second) list when removing content between those lists',
  909. () => {
  910. setModelData( model,
  911. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  912. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  913. '<paragraph>[]</paragraph>' +
  914. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  915. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  916. );
  917. editor.execute( 'delete' );
  918. expect( getModelData( model ) ).to.equal(
  919. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  920. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  921. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  922. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  923. );
  924. }
  925. );
  926. it( 'should read the `listStyle` attribute from the most outer list', () => {
  927. setModelData( model,
  928. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  929. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  930. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.1.</listItem>' +
  931. '<listItem listIndent="2" listStyle="default" listType="numbered">2.1.1</listItem>' +
  932. '<paragraph>[]</paragraph>' +
  933. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  934. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  935. );
  936. editor.execute( 'delete' );
  937. expect( getModelData( model ) ).to.equal(
  938. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  939. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  940. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.1.</listItem>' +
  941. '<listItem listIndent="2" listStyle="default" listType="numbered">2.1.1[]</listItem>' +
  942. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  943. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  944. );
  945. } );
  946. it(
  947. 'should not modify the the `listStyle` attribute for the merged (second) list if merging different `listType` attribute',
  948. () => {
  949. setModelData( model,
  950. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  951. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  952. '<paragraph>[]</paragraph>' +
  953. '<listItem listIndent="0" listStyle="decimal" listType="numbered">1.</listItem>' +
  954. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.</listItem>'
  955. );
  956. editor.execute( 'delete' );
  957. expect( getModelData( model ) ).to.equal(
  958. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  959. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  960. '<listItem listIndent="0" listStyle="decimal" listType="numbered">1.</listItem>' +
  961. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.</listItem>'
  962. );
  963. }
  964. );
  965. it(
  966. 'should modify the the `listStyle` attribute for the merged (second) list when removing content from both lists',
  967. () => {
  968. setModelData( model,
  969. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  970. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  971. '<listItem listIndent="0" listStyle="square" listType="bulleted">[3.</listItem>' +
  972. '<paragraph>Foo</paragraph>' +
  973. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.]</listItem>' +
  974. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  975. );
  976. editor.execute( 'delete' );
  977. expect( getModelData( model ) ).to.equal(
  978. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  979. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  980. '<listItem listIndent="0" listStyle="square" listType="bulleted">[]</listItem>' +
  981. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  982. );
  983. }
  984. );
  985. it(
  986. 'should modify the the `listStyle` attribute for the merged (second) list when typing over content from both lists',
  987. () => {
  988. setModelData( model,
  989. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  990. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  991. '<listItem listIndent="0" listStyle="square" listType="bulleted">[3.</listItem>' +
  992. '<paragraph>Foo</paragraph>' +
  993. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.]</listItem>' +
  994. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  995. );
  996. editor.execute( 'input', { text: 'Foo' } );
  997. expect( getModelData( model ) ).to.equal(
  998. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  999. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1000. '<listItem listIndent="0" listStyle="square" listType="bulleted">Foo[]</listItem>' +
  1001. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  1002. );
  1003. }
  1004. );
  1005. it(
  1006. 'should not modify the the `listStyle` if lists were not merged but the content was partially removed',
  1007. () => {
  1008. setModelData( model,
  1009. '<listItem listIndent="0" listStyle="square" listType="bulleted">111.</listItem>' +
  1010. '<listItem listIndent="0" listStyle="square" listType="bulleted">222.</listItem>' +
  1011. '<listItem listIndent="0" listStyle="square" listType="bulleted">[333.</listItem>' +
  1012. '<paragraph>Foo</paragraph>' +
  1013. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1]11.</listItem>' +
  1014. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1015. );
  1016. editor.execute( 'delete' );
  1017. expect( getModelData( model ) ).to.equal(
  1018. '<listItem listIndent="0" listStyle="square" listType="bulleted">111.</listItem>' +
  1019. '<listItem listIndent="0" listStyle="square" listType="bulleted">222.</listItem>' +
  1020. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[]11.</listItem>' +
  1021. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1022. );
  1023. }
  1024. );
  1025. it( 'should not do anything while typing in a list item', () => {
  1026. setModelData( model,
  1027. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1028. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</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. const modelChangeStub = sinon.stub( model, 'change' ).callThrough();
  1035. simulateTyping( ' Foo' );
  1036. // Each character calls `editor.model.change()`.
  1037. expect( modelChangeStub.callCount ).to.equal( 4 );
  1038. expect( getModelData( model ) ).to.equal(
  1039. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1040. '<listItem listIndent="0" listStyle="square" listType="bulleted">2. Foo[]</listItem>' +
  1041. '<listItem listIndent="0" listStyle="square" listType="bulleted">3.</listItem>' +
  1042. '<paragraph></paragraph>' +
  1043. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1044. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1045. );
  1046. } );
  1047. // See: #8073.
  1048. it( 'should not crash when removing a content between intended lists', () => {
  1049. setModelData( model,
  1050. '<listItem listIndent="0" listStyle="default" listType="bulleted">aaaa</listItem>' +
  1051. '<listItem listIndent="1" listStyle="default" listType="bulleted">bb[bb</listItem>' +
  1052. '<listItem listIndent="2" listStyle="default" listType="bulleted">cc]cc</listItem>' +
  1053. '<listItem listIndent="3" listStyle="default" listType="bulleted">dddd</listItem>'
  1054. );
  1055. editor.execute( 'delete' );
  1056. expect( getModelData( model ) ).to.equal(
  1057. '<listItem listIndent="0" listStyle="default" listType="bulleted">aaaa</listItem>' +
  1058. '<listItem listIndent="1" listStyle="default" listType="bulleted">bb[]cc</listItem>' +
  1059. '<listItem listIndent="2" listStyle="default" listType="bulleted">dddd</listItem>'
  1060. );
  1061. } );
  1062. it( 'should read the `listStyle` attribute from the most outer selected list while removing content between lists', () => {
  1063. setModelData( model,
  1064. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1065. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1066. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.1.</listItem>' +
  1067. '<listItem listIndent="2" listStyle="lower-latin" listType="numbered">2.1.1[foo</listItem>' +
  1068. '<paragraph>Foo</paragraph>' +
  1069. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1070. '<listItem listIndent="1" listStyle="circle" listType="bulleted">bar]2.</listItem>'
  1071. );
  1072. editor.execute( 'delete' );
  1073. expect( getModelData( model ) ).to.equal(
  1074. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1075. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1076. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.1.</listItem>' +
  1077. '<listItem listIndent="2" listStyle="lower-latin" listType="numbered">2.1.1[]2.</listItem>'
  1078. );
  1079. } );
  1080. function simulateTyping( text ) {
  1081. // While typing, every character is an atomic change.
  1082. text.split( '' ).forEach( character => {
  1083. editor.execute( 'input', {
  1084. text: character
  1085. } );
  1086. } );
  1087. }
  1088. } );
  1089. } );
  1090. } );