liststyleediting.js 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626
  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. /* global document */
  6. import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
  7. import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
  8. import Typing from '@ckeditor/ckeditor5-typing/src/typing';
  9. import UndoEditing from '@ckeditor/ckeditor5-undo/src/undoediting';
  10. import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
  11. import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
  12. import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  13. import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
  14. import ListStyleEditing from '../src/liststyleediting';
  15. import TodoListEditing from '../src/todolistediting';
  16. import ListStyleCommand from '../src/liststylecommand';
  17. describe( 'ListStyleEditing', () => {
  18. let editor, model, view;
  19. beforeEach( () => {
  20. return VirtualTestEditor
  21. .create( {
  22. plugins: [ Paragraph, ListStyleEditing, UndoEditing ]
  23. } )
  24. .then( newEditor => {
  25. editor = newEditor;
  26. model = editor.model;
  27. view = editor.editing.view;
  28. } );
  29. } );
  30. afterEach( () => {
  31. return editor.destroy();
  32. } );
  33. it( 'should have pluginName', () => {
  34. expect( ListStyleEditing.pluginName ).to.equal( 'ListStyleEditing' );
  35. } );
  36. it( 'should be loaded', () => {
  37. expect( editor.plugins.get( ListStyleEditing ) ).to.be.instanceOf( ListStyleEditing );
  38. } );
  39. describe( 'schema rules', () => {
  40. it( 'should allow set `listStyle` on the `listItem`', () => {
  41. expect( model.schema.checkAttribute( [ '$root', 'listItem' ], 'listStyle' ) ).to.be.true;
  42. } );
  43. } );
  44. describe( 'command', () => {
  45. it( 'should register listStyle command', () => {
  46. const command = editor.commands.get( 'listStyle' );
  47. expect( command ).to.be.instanceOf( ListStyleCommand );
  48. } );
  49. } );
  50. describe( 'conversion in data pipeline', () => {
  51. describe( 'model to data', () => {
  52. it( 'should convert single list (type: bulleted)', () => {
  53. setModelData( model,
  54. '<listItem listIndent="0" listType="bulleted">Foo</listItem>' +
  55. '<listItem listIndent="0" listType="bulleted">Bar</listItem>'
  56. );
  57. expect( editor.getData() ).to.equal( '<ul><li>Foo</li><li>Bar</li></ul>' );
  58. } );
  59. it( 'should convert single list (type: numbered)', () => {
  60. setModelData( model,
  61. '<listItem listIndent="0" listType="numbered">Foo</listItem>' +
  62. '<listItem listIndent="0" listType="numbered">Bar</listItem>'
  63. );
  64. expect( editor.getData() ).to.equal( '<ol><li>Foo</li><li>Bar</li></ol>' );
  65. } );
  66. it( 'should convert single list (type: bulleted, style: default)', () => {
  67. setModelData( model,
  68. '<listItem listIndent="0" listType="bulleted" listStyle="default">Foo</listItem>' +
  69. '<listItem listIndent="0" listType="bulleted" listStyle="default">Bar</listItem>'
  70. );
  71. expect( editor.getData() ).to.equal( '<ul><li>Foo</li><li>Bar</li></ul>' );
  72. } );
  73. it( 'should convert single list (type: numbered, style: default)', () => {
  74. setModelData( model,
  75. '<listItem listIndent="0" listType="numbered" listStyle="default">Foo</listItem>' +
  76. '<listItem listIndent="0" listType="numbered" listStyle="default">Bar</listItem>'
  77. );
  78. expect( editor.getData() ).to.equal( '<ol><li>Foo</li><li>Bar</li></ol>' );
  79. } );
  80. it( 'should convert single list (type: bulleted, style: circle)', () => {
  81. setModelData( model,
  82. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo</listItem>' +
  83. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar</listItem>'
  84. );
  85. expect( editor.getData() ).to.equal( '<ul style="list-style-type:circle;"><li>Foo</li><li>Bar</li></ul>' );
  86. } );
  87. it( 'should convert single list (type: numbered, style: upper-alpha)', () => {
  88. setModelData( model,
  89. '<listItem listIndent="0" listType="numbered" listStyle="upper-alpha">Foo</listItem>' +
  90. '<listItem listIndent="0" listType="numbered" listStyle="upper-alpha">Bar</listItem>'
  91. );
  92. expect( editor.getData() ).to.equal( '<ol style="list-style-type:upper-alpha;"><li>Foo</li><li>Bar</li></ol>' );
  93. } );
  94. it( 'should convert nested bulleted lists (main: circle, nested: disc)', () => {
  95. setModelData( model,
  96. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 1</listItem>' +
  97. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 1</listItem>' +
  98. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 2</listItem>' +
  99. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 2</listItem>' +
  100. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 3</listItem>'
  101. );
  102. expect( editor.getData() ).to.equal(
  103. '<ul style="list-style-type:circle;">' +
  104. '<li>Foo 1' +
  105. '<ul style="list-style-type:disc;">' +
  106. '<li>Bar 1</li>' +
  107. '<li>Bar 2</li>' +
  108. '</ul>' +
  109. '</li>' +
  110. '<li>Foo 2</li>' +
  111. '<li>Foo 3</li>' +
  112. '</ul>'
  113. );
  114. } );
  115. it( 'should convert nested numbered lists (main: decimal-leading-zero, nested: lower-latin)', () => {
  116. setModelData( model,
  117. '<listItem listIndent="0" listType="numbered" listStyle="decimal-leading-zero">Foo 1</listItem>' +
  118. '<listItem listIndent="1" listType="numbered" listStyle="lower-latin">Bar 1</listItem>' +
  119. '<listItem listIndent="1" listType="numbered" listStyle="lower-latin">Bar 2</listItem>' +
  120. '<listItem listIndent="0" listType="numbered" listStyle="decimal-leading-zero">Foo 2</listItem>' +
  121. '<listItem listIndent="0" listType="numbered" listStyle="decimal-leading-zero">Foo 3</listItem>'
  122. );
  123. expect( editor.getData() ).to.equal(
  124. '<ol style="list-style-type:decimal-leading-zero;">' +
  125. '<li>Foo 1' +
  126. '<ol style="list-style-type:lower-latin;">' +
  127. '<li>Bar 1</li>' +
  128. '<li>Bar 2</li>' +
  129. '</ol>' +
  130. '</li>' +
  131. '<li>Foo 2</li>' +
  132. '<li>Foo 3</li>' +
  133. '</ol>'
  134. );
  135. } );
  136. it( 'should convert nested mixed lists (ul>ol, main: square, nested: lower-roman)', () => {
  137. setModelData( model,
  138. '<listItem listIndent="0" listType="bulleted" listStyle="square">Foo 1</listItem>' +
  139. '<listItem listIndent="1" listType="numbered" listStyle="lower-roman">Bar 1</listItem>' +
  140. '<listItem listIndent="1" listType="numbered" listStyle="lower-roman">Bar 2</listItem>' +
  141. '<listItem listIndent="0" listType="bulleted" listStyle="square">Foo 2</listItem>' +
  142. '<listItem listIndent="0" listType="bulleted" listStyle="square">Foo 3</listItem>'
  143. );
  144. expect( editor.getData() ).to.equal(
  145. '<ul style="list-style-type:square;">' +
  146. '<li>Foo 1' +
  147. '<ol style="list-style-type:lower-roman;">' +
  148. '<li>Bar 1</li>' +
  149. '<li>Bar 2</li>' +
  150. '</ol>' +
  151. '</li>' +
  152. '<li>Foo 2</li>' +
  153. '<li>Foo 3</li>' +
  154. '</ul>'
  155. );
  156. } );
  157. it( 'should produce nested lists (different `listIndent` attribute)', () => {
  158. setModelData( model,
  159. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 1</listItem>' +
  160. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 2</listItem>' +
  161. '<listItem listIndent="1" listType="numbered" listStyle="decimal">Bar 1</listItem>' +
  162. '<listItem listIndent="1" listType="numbered" listStyle="decimal">Bar 2</listItem>'
  163. );
  164. expect( editor.getData() ).to.equal(
  165. '<ol style="list-style-type:decimal;">' +
  166. '<li>Foo 1</li>' +
  167. '<li>Foo 2' +
  168. '<ol style="list-style-type:decimal;">' +
  169. '<li>Bar 1</li>' +
  170. '<li>Bar 2</li>' +
  171. '</ol>' +
  172. '</li>' +
  173. '</ol>'
  174. );
  175. } );
  176. it( 'should produce two different lists (different `listType` attribute)', () => {
  177. setModelData( model,
  178. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 1</listItem>' +
  179. '<listItem listIndent="0" listType="numbered" listStyle="decimal">Foo 2</listItem>' +
  180. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Bar 1</listItem>' +
  181. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Bar 2</listItem>'
  182. );
  183. expect( editor.getData() ).to.equal(
  184. '<ol style="list-style-type:decimal;">' +
  185. '<li>Foo 1</li>' +
  186. '<li>Foo 2</li>' +
  187. '</ol>' +
  188. '<ul style="list-style-type:disc;">' +
  189. '<li>Bar 1</li>' +
  190. '<li>Bar 2</li>' +
  191. '</ul>'
  192. );
  193. } );
  194. it( 'should produce two different lists (different `listStyle` attribute)', () => {
  195. setModelData( model,
  196. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Foo 1</listItem>' +
  197. '<listItem listIndent="0" listType="bulleted" listStyle="disc">Foo 2</listItem>' +
  198. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar 1</listItem>' +
  199. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar 2</listItem>'
  200. );
  201. expect( editor.getData() ).to.equal(
  202. '<ul style="list-style-type:disc;">' +
  203. '<li>Foo 1</li>' +
  204. '<li>Foo 2</li>' +
  205. '</ul>' +
  206. '<ul style="list-style-type:circle;">' +
  207. '<li>Bar 1</li>' +
  208. '<li>Bar 2</li>' +
  209. '</ul>'
  210. );
  211. } );
  212. it( 'should not allow to set the `listStyle` attribute in to-do list item', () => {
  213. setModelData( model, '<listItem listIndent="0" listType="todo">Foo</listItem>' );
  214. const listItem = model.document.getRoot().getChild( 0 );
  215. expect( listItem.hasAttribute( 'listItem' ) ).to.be.false;
  216. model.change( writer => {
  217. writer.setAttribute( 'listType', 'foo', listItem );
  218. } );
  219. expect( listItem.hasAttribute( 'listItem' ) ).to.be.false;
  220. } );
  221. } );
  222. describe( 'view to model', () => {
  223. it( 'should convert single list (type: bulleted)', () => {
  224. editor.setData( '<ul><li>Foo</li><li>Bar</li></ul>' );
  225. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  226. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo</listItem>' +
  227. '<listItem listIndent="0" listStyle="default" listType="bulleted">Bar</listItem>'
  228. );
  229. } );
  230. it( 'should convert single list (type: numbered)', () => {
  231. editor.setData( '<ol><li>Foo</li><li>Bar</li></ol>' );
  232. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  233. '<listItem listIndent="0" listStyle="default" listType="numbered">Foo</listItem>' +
  234. '<listItem listIndent="0" listStyle="default" listType="numbered">Bar</listItem>'
  235. );
  236. } );
  237. it( 'should convert single list (type: bulleted, style: circle)', () => {
  238. editor.setData( '<ul style="list-style-type:circle;"><li>Foo</li><li>Bar</li></ul>' );
  239. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  240. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  241. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  242. );
  243. } );
  244. it( 'should convert single list (type: numbered, style: upper-alpha)', () => {
  245. editor.setData( '<ol style="list-style-type:upper-alpha;"><li>Foo</li><li>Bar</li></ol>' );
  246. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  247. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Foo</listItem>' +
  248. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Bar</listItem>'
  249. );
  250. } );
  251. it( 'should convert nested and mixed lists', () => {
  252. editor.setData(
  253. '<ol style="list-style-type:upper-alpha;">' +
  254. '<li>OL 1</li>' +
  255. '<li>OL 2' +
  256. '<ul style="list-style-type:circle;">' +
  257. '<li>UL 1</li>' +
  258. '<li>UL 2</li>' +
  259. '</ul>' +
  260. '</li>' +
  261. '<li>OL 3</li>' +
  262. '</ol>'
  263. );
  264. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  265. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">OL 1</listItem>' +
  266. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">OL 2</listItem>' +
  267. '<listItem listIndent="1" listStyle="circle" listType="bulleted">UL 1</listItem>' +
  268. '<listItem listIndent="1" listStyle="circle" listType="bulleted">UL 2</listItem>' +
  269. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">OL 3</listItem>'
  270. );
  271. } );
  272. it( 'should convert when the list is in the middle of the content', () => {
  273. editor.setData(
  274. '<p>Paragraph.</p>' +
  275. '<ol style="list-style-type:upper-alpha;">' +
  276. '<li>Foo</li>' +
  277. '<li>Bar</li>' +
  278. '</ol>' +
  279. '<p>Paragraph.</p>'
  280. );
  281. expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
  282. '<paragraph>Paragraph.</paragraph>' +
  283. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Foo</listItem>' +
  284. '<listItem listIndent="0" listStyle="upper-alpha" listType="numbered">Bar</listItem>' +
  285. '<paragraph>Paragraph.</paragraph>'
  286. );
  287. } );
  288. // See: #8262.
  289. describe( 'list conversion with surrounding text nodes', () => {
  290. let editor;
  291. beforeEach( () => {
  292. return VirtualTestEditor
  293. .create( {
  294. plugins: [ ListStyleEditing ]
  295. } )
  296. .then( newEditor => {
  297. editor = newEditor;
  298. } );
  299. } );
  300. afterEach( () => {
  301. return editor.destroy();
  302. } );
  303. it( 'should convert a list if raw text is before the list', () => {
  304. editor.setData( 'Foo<ul><li>Foo</li></ul>' );
  305. expect( editor.getData() ).to.equal( '<p>Foo</p><ul><li>Foo</li></ul>' );
  306. } );
  307. it( 'should convert a list if raw text is after the list', () => {
  308. editor.setData( '<ul><li>Foo</li></ul>Foo' );
  309. expect( editor.getData() ).to.equal( '<ul><li>Foo</li></ul><p>Foo</p>' );
  310. } );
  311. it( 'should convert a list if it is surrender by two text nodes', () => {
  312. editor.setData( 'Foo<ul><li>Foo</li></ul>Foo' );
  313. expect( editor.getData() ).to.equal( '<p>Foo</p><ul><li>Foo</li></ul><p>Foo</p>' );
  314. } );
  315. } );
  316. } );
  317. } );
  318. // At this moment editing and data pipelines produce exactly the same content.
  319. // Just a few tests will be enough here. `model to data` block contains all cases checked.
  320. describe( 'conversion in editing pipeline', () => {
  321. describe( 'model to view', () => {
  322. it( 'should convert single list (type: bulleted, style: default)', () => {
  323. setModelData( model,
  324. '<listItem listIndent="0" listType="bulleted" listStyle="default">Foo</listItem>' +
  325. '<listItem listIndent="0" listType="bulleted" listStyle="default">Bar</listItem>'
  326. );
  327. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  328. '<ul><li>Foo</li><li>Bar</li></ul>'
  329. );
  330. } );
  331. it( 'should convert single list (type: bulleted, style: circle)', () => {
  332. setModelData( model,
  333. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo</listItem>' +
  334. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar</listItem>'
  335. );
  336. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  337. '<ul style="list-style-type:circle"><li>Foo</li><li>Bar</li></ul>'
  338. );
  339. } );
  340. it( 'should convert nested bulleted lists (main: circle, nested: disc)', () => {
  341. setModelData( model,
  342. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 1</listItem>' +
  343. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 1</listItem>' +
  344. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 2</listItem>' +
  345. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 2</listItem>' +
  346. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 3</listItem>'
  347. );
  348. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  349. '<ul style="list-style-type:circle">' +
  350. '<li>Foo 1' +
  351. '<ul style="list-style-type:disc">' +
  352. '<li>Bar 1</li>' +
  353. '<li>Bar 2</li>' +
  354. '</ul>' +
  355. '</li>' +
  356. '<li>Foo 2</li>' +
  357. '<li>Foo 3</li>' +
  358. '</ul>'
  359. );
  360. } );
  361. // See: #8081.
  362. it( 'should convert properly nested list styles', () => {
  363. // ■ Level 0
  364. // ▶ Level 0.1
  365. // ○ Level 0.1.1
  366. // ▶ Level 0.2
  367. // ○ Level 0.2.1
  368. setModelData( model,
  369. '<listItem listIndent="0" listType="bulleted" listStyle="default">Level 0</listItem>' +
  370. '<listItem listIndent="1" listType="bulleted" listStyle="default">Level 0.1</listItem>' +
  371. '<listItem listIndent="2" listType="bulleted" listStyle="circle">Level 0.1.1</listItem>' +
  372. '<listItem listIndent="1" listType="bulleted" listStyle="default">Level 0.2</listItem>' +
  373. '<listItem listIndent="2" listType="bulleted" listStyle="circle">Level 0.2.1</listItem>'
  374. );
  375. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  376. '<ul>' +
  377. '<li>Level 0' +
  378. '<ul>' +
  379. '<li>Level 0.1' +
  380. '<ul style="list-style-type:circle">' +
  381. '<li>Level 0.1.1</li>' +
  382. '</ul>' +
  383. '</li>' +
  384. '<li>Level 0.2' +
  385. '<ul style="list-style-type:circle">' +
  386. '<li>Level 0.2.1</li>' +
  387. '</ul>' +
  388. '</li>' +
  389. '</ul>' +
  390. '</li>' +
  391. '</ul>'
  392. );
  393. } );
  394. } );
  395. } );
  396. describe( 'integrations', () => {
  397. describe( 'merging a list into a styled list', () => {
  398. it( 'should inherit the list style attribute when merging the same kind of lists (from top, merge a single item)', () => {
  399. setModelData( model,
  400. '<paragraph>Foo Bar.[]</paragraph>' +
  401. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  402. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  403. );
  404. editor.execute( 'bulletedList' );
  405. expect( getModelData( model ) ).to.equal(
  406. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>' +
  407. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  408. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  409. );
  410. } );
  411. it( 'should inherit the list style attribute when merging the same kind of lists (from top, merge a few items)', () => {
  412. setModelData( model,
  413. '<paragraph>[Foo Bar 1.</paragraph>' +
  414. '<paragraph>Foo Bar 2.]</paragraph>' +
  415. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  416. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  417. );
  418. editor.execute( 'bulletedList' );
  419. expect( getModelData( model ) ).to.equal(
  420. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[Foo Bar 1.</listItem>' +
  421. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar 2.]</listItem>' +
  422. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  423. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  424. );
  425. } );
  426. it( 'should not inherit anything if there is no list below the inserted list', () => {
  427. setModelData( model,
  428. '<paragraph>Foo Bar 1.[]</paragraph>' +
  429. '<paragraph>Foo Bar 2.</paragraph>'
  430. );
  431. editor.execute( 'bulletedList' );
  432. expect( getModelData( model ) ).to.equal(
  433. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar 1.[]</listItem>' +
  434. '<paragraph>Foo Bar 2.</paragraph>'
  435. );
  436. } );
  437. it( 'should not inherit anything if replacing the entire content with a list', () => {
  438. setModelData( model,
  439. '<paragraph>Foo Bar 1.[]</paragraph>'
  440. );
  441. editor.execute( 'bulletedList' );
  442. expect( getModelData( model ) ).to.equal(
  443. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar 1.[]</listItem>'
  444. );
  445. } );
  446. it( 'should not inherit the list style attribute when merging different kind of lists (from top, merge a single item)', () => {
  447. setModelData( model,
  448. '<paragraph>Foo Bar.[]</paragraph>' +
  449. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  450. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>'
  451. );
  452. editor.execute( 'bulletedList' );
  453. expect( getModelData( model ) ).to.equal(
  454. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>' +
  455. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  456. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>'
  457. );
  458. } );
  459. it(
  460. 'should not inherit the list style attribute when merging different kind of lists (from bottom, merge a single item)',
  461. () => {
  462. setModelData( model,
  463. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  464. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>' +
  465. '<paragraph>Foo Bar.[]</paragraph>'
  466. );
  467. editor.execute( 'bulletedList' );
  468. expect( getModelData( model ) ).to.equal(
  469. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  470. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>' +
  471. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>'
  472. );
  473. }
  474. );
  475. it( 'should inherit the list style attribute when merging the same kind of lists (from bottom, merge a single item)', () => {
  476. setModelData( model,
  477. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  478. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  479. '<paragraph>Foo Bar.[]</paragraph>'
  480. );
  481. editor.execute( 'bulletedList' );
  482. expect( getModelData( model ) ).to.equal(
  483. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  484. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  485. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>'
  486. );
  487. } );
  488. it(
  489. 'should inherit the list style attribute from listIndent=0 element when merging the same kind of lists (from bottom)',
  490. () => {
  491. setModelData( model,
  492. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  493. '<listItem listIndent="1" listStyle="square" listType="bulleted">Bar</listItem>' +
  494. '<listItem listIndent="2" listStyle="disc" listType="bulleted">Foo Bar</listItem>' +
  495. '<paragraph>Foo Bar.[]</paragraph>'
  496. );
  497. editor.execute( 'bulletedList' );
  498. expect( getModelData( model ) ).to.equal(
  499. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  500. '<listItem listIndent="1" listStyle="square" listType="bulleted">Bar</listItem>' +
  501. '<listItem listIndent="2" listStyle="disc" listType="bulleted">Foo Bar</listItem>' +
  502. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>'
  503. );
  504. }
  505. );
  506. } );
  507. describe( 'modifying "listType" attribute', () => {
  508. it( 'should inherit the list style attribute when the modified list is the same kind of the list as next sibling', () => {
  509. setModelData( model,
  510. '<listItem listIndent="0" listStyle="default" listType="numbered">Foo Bar.[]</listItem>' +
  511. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  512. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  513. );
  514. editor.execute( 'bulletedList' );
  515. expect( getModelData( model ) ).to.equal(
  516. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>' +
  517. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  518. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  519. );
  520. } );
  521. it( 'should inherit the list style attribute when the modified list is the same kind of the list as previous sibling', () => {
  522. setModelData( model,
  523. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  524. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  525. '<listItem listIndent="0" listStyle="default" listType="numbered">Foo Bar.[]</listItem>'
  526. );
  527. editor.execute( 'bulletedList' );
  528. expect( getModelData( model ) ).to.equal(
  529. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  530. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  531. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>'
  532. );
  533. } );
  534. it( 'should not inherit the list style attribute when the modified list already has defined it (next sibling check)', () => {
  535. setModelData( model,
  536. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>' +
  537. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  538. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  539. );
  540. editor.execute( 'listStyle', { type: 'disc' } );
  541. expect( getModelData( model ) ).to.equal(
  542. '<listItem listIndent="0" listStyle="disc" listType="bulleted">Foo Bar.[]</listItem>' +
  543. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  544. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  545. );
  546. } );
  547. it(
  548. 'should not inherit the list style attribute when the modified list already has defined it (previous sibling check)',
  549. () => {
  550. setModelData( model,
  551. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  552. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  553. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>'
  554. );
  555. editor.execute( 'listStyle', { type: 'disc' } );
  556. expect( getModelData( model ) ).to.equal(
  557. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  558. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  559. '<listItem listIndent="0" listStyle="disc" listType="bulleted">Foo Bar.[]</listItem>'
  560. );
  561. }
  562. );
  563. } );
  564. describe( 'indenting lists', () => {
  565. it( 'should restore the default value for the list style attribute when indenting a single item', () => {
  566. setModelData( model,
  567. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  568. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  569. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  570. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  571. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  572. );
  573. editor.execute( 'indentList' );
  574. expect( getModelData( model ) ).to.equal(
  575. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  576. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  577. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  578. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  579. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  580. );
  581. } );
  582. it( 'should restore the default value for the list style attribute when indenting a few items', () => {
  583. setModelData( model,
  584. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  585. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[2.</listItem>' +
  586. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.]</listItem>'
  587. );
  588. editor.execute( 'indentList' );
  589. expect( getModelData( model ) ).to.equal(
  590. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  591. '<listItem listIndent="1" listStyle="default" listType="bulleted">[2.</listItem>' +
  592. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.]</listItem>'
  593. );
  594. } );
  595. it(
  596. 'should copy the value for the list style attribute when indenting a single item into a nested list (default value)',
  597. () => {
  598. setModelData( model,
  599. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  600. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  601. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>' +
  602. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  603. );
  604. editor.execute( 'indentList' );
  605. expect( getModelData( model ) ).to.equal(
  606. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  607. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  608. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.[]</listItem>' +
  609. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  610. );
  611. }
  612. );
  613. it(
  614. 'should copy the value for the list style attribute when indenting a single item into a nested list (changed value)',
  615. () => {
  616. setModelData( model,
  617. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  618. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  619. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>' +
  620. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  621. );
  622. editor.execute( 'indentList' );
  623. expect( getModelData( model ) ).to.equal(
  624. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  625. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  626. '<listItem listIndent="1" listStyle="disc" listType="bulleted">3.[]</listItem>' +
  627. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  628. );
  629. }
  630. );
  631. it( 'should copy the value for the list style attribute when indenting a single item into a nested list', () => {
  632. setModelData( model,
  633. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  634. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  635. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  636. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  637. );
  638. editor.execute( 'indentList' );
  639. expect( getModelData( model ) ).to.equal(
  640. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  641. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  642. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  643. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  644. );
  645. } );
  646. it(
  647. 'should copy the value for the list style attribute when indenting a single item into a nested list ' +
  648. '(many nested lists check)',
  649. () => {
  650. setModelData( model,
  651. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  652. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  653. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  654. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.[]</listItem>'
  655. );
  656. editor.execute( 'indentList' );
  657. expect( getModelData( model ) ).to.equal(
  658. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  659. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  660. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  661. '<listItem listIndent="1" listStyle="disc" listType="bulleted">4.[]</listItem>'
  662. );
  663. }
  664. );
  665. it( 'should inherit the list style attribute from nested list if the `listType` is other than indenting element', () => {
  666. setModelData( model,
  667. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  668. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.</listItem>' +
  669. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>'
  670. );
  671. editor.execute( 'indentList' );
  672. expect( getModelData( model ) ).to.equal(
  673. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  674. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.</listItem>' +
  675. '<listItem listIndent="1" listStyle="decimal" listType="numbered">3.[]</listItem>'
  676. );
  677. } );
  678. // See: #8072.
  679. it( 'should not throw when indenting a list without any other content in the editor', () => {
  680. setModelData( model,
  681. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo</listItem>' +
  682. '<listItem listIndent="0" listStyle="default" listType="bulleted">[]</listItem>'
  683. );
  684. editor.execute( 'indentList' );
  685. expect( getModelData( model ) ).to.equal(
  686. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo</listItem>' +
  687. '<listItem listIndent="1" listStyle="default" listType="bulleted">[]</listItem>'
  688. );
  689. } );
  690. } );
  691. describe( 'outdenting lists', () => {
  692. it( 'should inherit the list style attribute from parent list (change the first nested item)', () => {
  693. setModelData( model,
  694. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  695. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  696. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  697. );
  698. editor.execute( 'outdentList' );
  699. expect( getModelData( model ) ).to.equal(
  700. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  701. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  702. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  703. );
  704. } );
  705. it( 'should inherit the list style attribute from parent list (change the second nested item)', () => {
  706. setModelData( model,
  707. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  708. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  709. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.[]</listItem>'
  710. );
  711. editor.execute( 'outdentList' );
  712. expect( getModelData( model ) ).to.equal(
  713. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  714. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  715. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>'
  716. );
  717. } );
  718. it( 'should inherit the list style attribute from parent list (modifying nested lists)', () => {
  719. setModelData( model,
  720. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  721. '<listItem listIndent="1" listStyle="default" listType="bulleted">[2.</listItem>' +
  722. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.]</listItem>'
  723. );
  724. editor.execute( 'outdentList' );
  725. expect( getModelData( model ) ).to.equal(
  726. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  727. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[2.</listItem>' +
  728. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.]</listItem>'
  729. );
  730. } );
  731. it(
  732. 'should inherit the list style attribute from parent list (outdenting many items, including the first one in the list)',
  733. () => {
  734. setModelData( model,
  735. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[1.</listItem>' +
  736. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  737. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.]</listItem>' +
  738. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  739. );
  740. editor.execute( 'outdentList' );
  741. expect( getModelData( model ) ).to.equal(
  742. '<paragraph>[1.</paragraph>' +
  743. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  744. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.]</listItem>' +
  745. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  746. );
  747. }
  748. );
  749. it(
  750. 'should inherit the list style attribute from parent list (outdenting the first item that is a parent for next list)',
  751. () => {
  752. setModelData( model,
  753. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  754. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  755. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  756. '<listItem listIndent="3" listStyle="disc" listType="bulleted">4.</listItem>' +
  757. '<listItem listIndent="0" listStyle="circle" listType="bulleted">5.</listItem>'
  758. );
  759. editor.execute( 'outdentList' );
  760. expect( getModelData( model ) ).to.equal(
  761. '<paragraph>1.[]</paragraph>' +
  762. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  763. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  764. '<listItem listIndent="2" listStyle="disc" listType="bulleted">4.</listItem>' +
  765. '<listItem listIndent="0" listStyle="circle" listType="bulleted">5.</listItem>'
  766. );
  767. }
  768. );
  769. it( 'should not inherit the list style if outdented the only one item in the list', () => {
  770. setModelData( model,
  771. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  772. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  773. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>'
  774. );
  775. editor.execute( 'outdentList' );
  776. expect( getModelData( model ) ).to.equal(
  777. '<paragraph>1.[]</paragraph>' +
  778. '<listItem listIndent="0" listStyle="disc" listType="bulleted">2.</listItem>' +
  779. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>'
  780. );
  781. } );
  782. it( 'should not inherit the list style if outdented the only one item in the list (a paragraph below the list)', () => {
  783. setModelData( model,
  784. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  785. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  786. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  787. '<paragraph>Foo</paragraph>'
  788. );
  789. editor.execute( 'outdentList' );
  790. expect( getModelData( model ) ).to.equal(
  791. '<paragraph>1.[]</paragraph>' +
  792. '<listItem listIndent="0" listStyle="disc" listType="bulleted">2.</listItem>' +
  793. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  794. '<paragraph>Foo</paragraph>'
  795. );
  796. } );
  797. it( 'should not inherit the list style attribute from parent list if the `listType` is other than outdenting element', () => {
  798. setModelData( model,
  799. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  800. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.[]</listItem>' +
  801. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  802. );
  803. editor.execute( 'outdentList' );
  804. expect( getModelData( model ) ).to.equal(
  805. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  806. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.[]</listItem>' +
  807. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  808. );
  809. } );
  810. it( 'should not do anything if there is no list after outdenting', () => {
  811. setModelData( model,
  812. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>'
  813. );
  814. editor.execute( 'outdentList' );
  815. expect( getModelData( model ) ).to.equal(
  816. '<paragraph>1.[]</paragraph>'
  817. );
  818. } );
  819. } );
  820. describe( 'indent/outdent + undo', () => {
  821. it( 'should use the same batch for indenting a list and updating `listType` attribute', () => {
  822. setModelData( model,
  823. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  824. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  825. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  826. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  827. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  828. );
  829. editor.execute( 'indentList' );
  830. editor.execute( 'undo' );
  831. expect( getModelData( model ) ).to.equal(
  832. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  833. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  834. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  835. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  836. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  837. );
  838. } );
  839. it( 'should use the same batch for outdenting a list and updating `listType` attribute', () => {
  840. setModelData( model,
  841. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  842. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  843. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  844. );
  845. editor.execute( 'outdentList' );
  846. editor.execute( 'undo' );
  847. expect( getModelData( model ) ).to.equal(
  848. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  849. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  850. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  851. );
  852. } );
  853. } );
  854. describe( 'delete + undo', () => {
  855. let editor, model, view;
  856. beforeEach( () => {
  857. return VirtualTestEditor
  858. .create( {
  859. plugins: [ Paragraph, ListStyleEditing, Typing, UndoEditing ]
  860. } )
  861. .then( newEditor => {
  862. editor = newEditor;
  863. model = editor.model;
  864. view = editor.editing.view;
  865. } );
  866. } );
  867. afterEach( () => {
  868. return editor.destroy();
  869. } );
  870. // See: #7930.
  871. it( 'should restore proper list style attribute after undo merging lists', () => {
  872. // ○ 1.
  873. // ○ 2.
  874. // ○ 3.
  875. // <paragraph>
  876. // ■ 1.
  877. // ■ 2.
  878. setModelData( model,
  879. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  880. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  881. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>' +
  882. '<paragraph>[]</paragraph>' +
  883. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  884. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  885. );
  886. expect( getViewData( view, { withoutSelection: true } ), 'initial data' ).to.equal(
  887. '<ul style="list-style-type:circle">' +
  888. '<li>1.</li>' +
  889. '<li>2.</li>' +
  890. '<li>3.</li>' +
  891. '</ul>' +
  892. '<p></p>' +
  893. '<ul style="list-style-type:square">' +
  894. '<li>1.</li>' +
  895. '<li>2.</li>' +
  896. '</ul>'
  897. );
  898. // After removing the paragraph.
  899. // ○ 1.
  900. // ○ 2.
  901. // ○ 3.
  902. // ○ 1.
  903. // ○ 2.
  904. editor.execute( 'delete' );
  905. expect( getViewData( view, { withoutSelection: true } ), 'executing delete' ).to.equal(
  906. '<ul style="list-style-type:circle">' +
  907. '<li>1.</li>' +
  908. '<li>2.</li>' +
  909. '<li>3.</li>' +
  910. '<li>1.</li>' +
  911. '<li>2.</li>' +
  912. '</ul>'
  913. );
  914. // After undo.
  915. // ○ 1.
  916. // ○ 2.
  917. // ○ 3.
  918. // <paragraph>
  919. // ■ 1.
  920. // ■ 2.
  921. editor.execute( 'undo' );
  922. expect( getViewData( view, { withoutSelection: true } ), 'initial data' ).to.equal(
  923. '<ul style="list-style-type:circle">' +
  924. '<li>1.</li>' +
  925. '<li>2.</li>' +
  926. '<li>3.</li>' +
  927. '</ul>' +
  928. '<p></p>' +
  929. '<ul style="list-style-type:square">' +
  930. '<li>1.</li>' +
  931. '<li>2.</li>' +
  932. '</ul>'
  933. );
  934. } );
  935. } );
  936. describe( 'todo list', () => {
  937. let editor, model;
  938. beforeEach( () => {
  939. return VirtualTestEditor
  940. .create( {
  941. // TodoListEditing is at the end by design. Check `ListStyleEditing.afterInit()` call.
  942. plugins: [ Paragraph, ListStyleEditing, TodoListEditing ]
  943. } )
  944. .then( newEditor => {
  945. editor = newEditor;
  946. model = editor.model;
  947. } );
  948. } );
  949. afterEach( () => {
  950. return editor.destroy();
  951. } );
  952. it( 'should not add the `listStyle` attribute while creating a todo list', () => {
  953. setModelData( model, '<paragraph>Foo[]</paragraph>' );
  954. editor.execute( 'todoList' );
  955. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  956. } );
  957. it( 'should not add the `listStyle` attribute while switching the list type', () => {
  958. setModelData( model, '<listItem listIndent="0" listType="bulleted">Foo[]</listItem>' );
  959. editor.execute( 'todoList' );
  960. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  961. } );
  962. it( 'should remove the `listStyle` attribute while switching the list type that uses the list style feature', () => {
  963. setModelData( model, '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo[]</listItem>' );
  964. editor.execute( 'todoList' );
  965. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  966. } );
  967. it( 'should not inherit the list style attribute when inserting a todo list item', () => {
  968. setModelData( model,
  969. '<paragraph>Foo Bar.[]</paragraph>' +
  970. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  971. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  972. );
  973. editor.execute( 'todoList' );
  974. expect( getModelData( model ) ).to.equal(
  975. '<listItem listIndent="0" listType="todo">Foo Bar.[]</listItem>' +
  976. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  977. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  978. );
  979. } );
  980. } );
  981. describe( 'removing content between two lists', () => {
  982. let editor, model;
  983. beforeEach( () => {
  984. return VirtualTestEditor
  985. .create( {
  986. plugins: [ Paragraph, ListStyleEditing, Typing ]
  987. } )
  988. .then( newEditor => {
  989. editor = newEditor;
  990. model = editor.model;
  991. } );
  992. } );
  993. afterEach( () => {
  994. return editor.destroy();
  995. } );
  996. it( 'should not do anything while removing a letter inside a listItem', () => {
  997. setModelData( model,
  998. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  999. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  1000. '<paragraph></paragraph>' +
  1001. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</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">1.</listItem>' +
  1007. '<listItem listIndent="0" listStyle="square" listType="bulleted">2[]</listItem>' +
  1008. '<paragraph></paragraph>' +
  1009. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1010. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1011. );
  1012. } );
  1013. it( 'should not do anything if there is a non-listItem before the removed content', () => {
  1014. setModelData( model,
  1015. '<paragraph>Foo</paragraph>' +
  1016. '<paragraph>[]</paragraph>' +
  1017. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1018. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1019. );
  1020. editor.execute( 'delete' );
  1021. expect( getModelData( model ) ).to.equal(
  1022. '<paragraph>Foo[]</paragraph>' +
  1023. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1024. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1025. );
  1026. } );
  1027. it( 'should not do anything if there is a non-listItem after the removed content', () => {
  1028. setModelData( model,
  1029. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1030. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  1031. '<paragraph>[]</paragraph>' +
  1032. '<paragraph>Foo</paragraph>'
  1033. );
  1034. editor.execute( 'delete' );
  1035. expect( getModelData( model ) ).to.equal(
  1036. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1037. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  1038. '<paragraph>Foo</paragraph>'
  1039. );
  1040. } );
  1041. it( 'should not do anything if there is no element after the removed content', () => {
  1042. setModelData( model,
  1043. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1044. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  1045. '<paragraph>[]</paragraph>'
  1046. );
  1047. editor.execute( 'delete' );
  1048. expect( getModelData( model ) ).to.equal(
  1049. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1050. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>'
  1051. );
  1052. } );
  1053. it(
  1054. 'should modify the the `listStyle` attribute for the merged (second) list when removing content between those lists',
  1055. () => {
  1056. setModelData( model,
  1057. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1058. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1059. '<paragraph>[]</paragraph>' +
  1060. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1061. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1062. );
  1063. editor.execute( 'delete' );
  1064. expect( getModelData( model ) ).to.equal(
  1065. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1066. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  1067. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1068. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  1069. );
  1070. }
  1071. );
  1072. it( 'should read the `listStyle` attribute from the most outer list', () => {
  1073. setModelData( model,
  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="default" listType="numbered">2.1.1</listItem>' +
  1078. '<paragraph>[]</paragraph>' +
  1079. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1080. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1081. );
  1082. editor.execute( 'delete' );
  1083. expect( getModelData( model ) ).to.equal(
  1084. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1085. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1086. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.1.</listItem>' +
  1087. '<listItem listIndent="2" listStyle="default" listType="numbered">2.1.1[]</listItem>' +
  1088. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1089. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  1090. );
  1091. } );
  1092. it(
  1093. 'should not modify the the `listStyle` attribute for the merged (second) list if merging different `listType` attribute',
  1094. () => {
  1095. setModelData( model,
  1096. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1097. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1098. '<paragraph>[]</paragraph>' +
  1099. '<listItem listIndent="0" listStyle="decimal" listType="numbered">1.</listItem>' +
  1100. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.</listItem>'
  1101. );
  1102. editor.execute( 'delete' );
  1103. expect( getModelData( model ) ).to.equal(
  1104. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1105. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  1106. '<listItem listIndent="0" listStyle="decimal" listType="numbered">1.</listItem>' +
  1107. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.</listItem>'
  1108. );
  1109. }
  1110. );
  1111. it(
  1112. 'should modify the the `listStyle` attribute for the merged (second) list when removing content from both lists',
  1113. () => {
  1114. setModelData( model,
  1115. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1116. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1117. '<listItem listIndent="0" listStyle="square" listType="bulleted">[3.</listItem>' +
  1118. '<paragraph>Foo</paragraph>' +
  1119. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.]</listItem>' +
  1120. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1121. );
  1122. editor.execute( 'delete' );
  1123. expect( getModelData( model ) ).to.equal(
  1124. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1125. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1126. '<listItem listIndent="0" listStyle="square" listType="bulleted">[]</listItem>' +
  1127. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  1128. );
  1129. }
  1130. );
  1131. it(
  1132. 'should modify the the `listStyle` attribute for the merged (second) list when typing over content from both lists',
  1133. () => {
  1134. setModelData( model,
  1135. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1136. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1137. '<listItem listIndent="0" listStyle="square" listType="bulleted">[3.</listItem>' +
  1138. '<paragraph>Foo</paragraph>' +
  1139. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.]</listItem>' +
  1140. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1141. );
  1142. editor.execute( 'input', { text: 'Foo' } );
  1143. expect( getModelData( model ) ).to.equal(
  1144. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1145. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1146. '<listItem listIndent="0" listStyle="square" listType="bulleted">Foo[]</listItem>' +
  1147. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  1148. );
  1149. }
  1150. );
  1151. it(
  1152. 'should not modify the the `listStyle` if lists were not merged but the content was partially removed',
  1153. () => {
  1154. setModelData( model,
  1155. '<listItem listIndent="0" listStyle="square" listType="bulleted">111.</listItem>' +
  1156. '<listItem listIndent="0" listStyle="square" listType="bulleted">222.</listItem>' +
  1157. '<listItem listIndent="0" listStyle="square" listType="bulleted">[333.</listItem>' +
  1158. '<paragraph>Foo</paragraph>' +
  1159. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1]11.</listItem>' +
  1160. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1161. );
  1162. editor.execute( 'delete' );
  1163. expect( getModelData( model ) ).to.equal(
  1164. '<listItem listIndent="0" listStyle="square" listType="bulleted">111.</listItem>' +
  1165. '<listItem listIndent="0" listStyle="square" listType="bulleted">222.</listItem>' +
  1166. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[]11.</listItem>' +
  1167. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1168. );
  1169. }
  1170. );
  1171. it( 'should not do anything while typing in a list item', () => {
  1172. setModelData( model,
  1173. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1174. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  1175. '<listItem listIndent="0" listStyle="square" listType="bulleted">3.</listItem>' +
  1176. '<paragraph></paragraph>' +
  1177. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1178. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1179. );
  1180. const modelChangeStub = sinon.stub( model, 'change' ).callThrough();
  1181. simulateTyping( ' Foo' );
  1182. // Each character calls `editor.model.change()`.
  1183. expect( modelChangeStub.callCount ).to.equal( 4 );
  1184. expect( getModelData( model ) ).to.equal(
  1185. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1186. '<listItem listIndent="0" listStyle="square" listType="bulleted">2. Foo[]</listItem>' +
  1187. '<listItem listIndent="0" listStyle="square" listType="bulleted">3.</listItem>' +
  1188. '<paragraph></paragraph>' +
  1189. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1190. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1191. );
  1192. } );
  1193. // See: #8073.
  1194. it( 'should not crash when removing a content between intended lists', () => {
  1195. setModelData( model,
  1196. '<listItem listIndent="0" listStyle="default" listType="bulleted">aaaa</listItem>' +
  1197. '<listItem listIndent="1" listStyle="default" listType="bulleted">bb[bb</listItem>' +
  1198. '<listItem listIndent="2" listStyle="default" listType="bulleted">cc]cc</listItem>' +
  1199. '<listItem listIndent="3" listStyle="default" listType="bulleted">dddd</listItem>'
  1200. );
  1201. editor.execute( 'delete' );
  1202. expect( getModelData( model ) ).to.equal(
  1203. '<listItem listIndent="0" listStyle="default" listType="bulleted">aaaa</listItem>' +
  1204. '<listItem listIndent="1" listStyle="default" listType="bulleted">bb[]cc</listItem>' +
  1205. '<listItem listIndent="2" listStyle="default" listType="bulleted">dddd</listItem>'
  1206. );
  1207. } );
  1208. it( 'should read the `listStyle` attribute from the most outer selected list while removing content between lists', () => {
  1209. setModelData( model,
  1210. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1211. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1212. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.1.</listItem>' +
  1213. '<listItem listIndent="2" listStyle="lower-latin" listType="numbered">2.1.1[foo</listItem>' +
  1214. '<paragraph>Foo</paragraph>' +
  1215. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1216. '<listItem listIndent="1" listStyle="circle" listType="bulleted">bar]2.</listItem>'
  1217. );
  1218. editor.execute( 'delete' );
  1219. expect( getModelData( model ) ).to.equal(
  1220. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1221. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1222. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.1.</listItem>' +
  1223. '<listItem listIndent="2" listStyle="lower-latin" listType="numbered">2.1.1[]2.</listItem>'
  1224. );
  1225. } );
  1226. function simulateTyping( text ) {
  1227. // While typing, every character is an atomic change.
  1228. text.split( '' ).forEach( character => {
  1229. editor.execute( 'input', {
  1230. text: character
  1231. } );
  1232. } );
  1233. }
  1234. } );
  1235. // #8160
  1236. describe( 'pasting a list into another list', () => {
  1237. let element;
  1238. beforeEach( () => {
  1239. element = document.createElement( 'div' );
  1240. document.body.append( element );
  1241. return ClassicTestEditor
  1242. .create( element, {
  1243. plugins: [ Paragraph, Clipboard, ListStyleEditing, UndoEditing ]
  1244. } )
  1245. .then( newEditor => {
  1246. editor = newEditor;
  1247. model = editor.model;
  1248. } );
  1249. } );
  1250. afterEach( () => {
  1251. return editor.destroy()
  1252. .then( () => {
  1253. element.remove();
  1254. } );
  1255. } );
  1256. it( 'should inherit attributes from the previous sibling element (collapsed selection)', () => {
  1257. setModelData( model,
  1258. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  1259. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo Bar</listItem>' +
  1260. '<listItem listIndent="1" listStyle="decimal" listType="numbered">[]</listItem>' +
  1261. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  1262. );
  1263. pasteHtml( editor,
  1264. '<ul style="list-style-type: square">' +
  1265. '<li>Foo 1</li>' +
  1266. '<li>Foo 2</li>' +
  1267. '</ul>'
  1268. );
  1269. expect( getModelData( model ) ).to.equal(
  1270. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  1271. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo Bar</listItem>' +
  1272. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo 1</listItem>' +
  1273. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo 2[]</listItem>' +
  1274. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  1275. );
  1276. } );
  1277. it( 'should inherit attributes from the previous sibling element (non-collapsed selection)', () => {
  1278. setModelData( model,
  1279. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  1280. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo Bar</listItem>' +
  1281. '<listItem listIndent="1" listStyle="decimal" listType="numbered">[Foo]</listItem>' +
  1282. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  1283. );
  1284. pasteHtml( editor,
  1285. '<ul style="list-style-type: square">' +
  1286. '<li>Foo 1</li>' +
  1287. '<li>Foo 2</li>' +
  1288. '</ul>'
  1289. );
  1290. expect( getModelData( model ) ).to.equal(
  1291. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  1292. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo Bar</listItem>' +
  1293. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo 1</listItem>' +
  1294. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo 2[]</listItem>' +
  1295. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  1296. );
  1297. } );
  1298. it( 'should inherit attributes from the previous sibling element (non-collapsed selection over a few elements)', () => {
  1299. setModelData( model,
  1300. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  1301. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo Bar</listItem>' +
  1302. '<listItem listIndent="1" listStyle="decimal" listType="numbered">[Foo 1.</listItem>' +
  1303. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo 2.</listItem>' +
  1304. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo 3.]</listItem>' +
  1305. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  1306. );
  1307. pasteHtml( editor,
  1308. '<ul style="list-style-type: square">' +
  1309. '<li>Foo 1</li>' +
  1310. '<li>Foo 2</li>' +
  1311. '</ul>'
  1312. );
  1313. expect( getModelData( model ) ).to.equal(
  1314. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  1315. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo Bar</listItem>' +
  1316. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo 1</listItem>' +
  1317. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo 2[]</listItem>' +
  1318. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  1319. );
  1320. } );
  1321. it( 'should do nothing when pasting the similar list', () => {
  1322. setModelData( model,
  1323. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  1324. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo Bar</listItem>' +
  1325. '<listItem listIndent="1" listStyle="decimal" listType="numbered">[]</listItem>' +
  1326. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  1327. );
  1328. pasteHtml( editor,
  1329. '<ol style="list-style-type: decimal">' +
  1330. '<li>Foo</li>' +
  1331. '</ol>'
  1332. );
  1333. expect( getModelData( model ) ).to.equal(
  1334. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  1335. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo Bar</listItem>' +
  1336. '<listItem listIndent="1" listStyle="decimal" listType="numbered">Foo[]</listItem>' +
  1337. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  1338. );
  1339. } );
  1340. it( 'should replace the entire list if selected', () => {
  1341. setModelData( model,
  1342. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  1343. '<listItem listIndent="1" listStyle="decimal" listType="numbered">[Foo Bar]</listItem>' +
  1344. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  1345. );
  1346. pasteHtml( editor,
  1347. '<ul style="list-style-type: square">' +
  1348. '<li>Foo</li>' +
  1349. '</ul>'
  1350. );
  1351. expect( getModelData( model ) ).to.equal(
  1352. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  1353. '<listItem listIndent="1" listStyle="square" listType="bulleted">Foo[]</listItem>' +
  1354. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  1355. );
  1356. } );
  1357. function pasteHtml( editor, html ) {
  1358. editor.editing.view.document.fire( 'paste', {
  1359. dataTransfer: createDataTransfer( { 'text/html': html } ),
  1360. stopPropagation() {},
  1361. preventDefault() {}
  1362. } );
  1363. }
  1364. function createDataTransfer( data ) {
  1365. return {
  1366. getData( type ) {
  1367. return data[ type ];
  1368. },
  1369. setData() {}
  1370. };
  1371. }
  1372. } );
  1373. } );
  1374. } );