liststyleediting.js 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463
  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. // See: #8262.
  286. describe( 'list conversion with surrounding text nodes', () => {
  287. let editor;
  288. beforeEach( () => {
  289. return VirtualTestEditor
  290. .create( {
  291. plugins: [ ListStyleEditing ]
  292. } )
  293. .then( newEditor => {
  294. editor = newEditor;
  295. } );
  296. } );
  297. afterEach( () => {
  298. return editor.destroy();
  299. } );
  300. it( 'should convert a list if raw text is before the list', () => {
  301. editor.setData( 'Foo<ul><li>Foo</li></ul>' );
  302. expect( editor.getData() ).to.equal( '<p>Foo</p><ul><li>Foo</li></ul>' );
  303. } );
  304. it( 'should convert a list if raw text is after the list', () => {
  305. editor.setData( '<ul><li>Foo</li></ul>Foo' );
  306. expect( editor.getData() ).to.equal( '<ul><li>Foo</li></ul><p>Foo</p>' );
  307. } );
  308. it( 'should convert a list if it is surrender by two text nodes', () => {
  309. editor.setData( 'Foo<ul><li>Foo</li></ul>Foo' );
  310. expect( editor.getData() ).to.equal( '<p>Foo</p><ul><li>Foo</li></ul><p>Foo</p>' );
  311. } );
  312. } );
  313. } );
  314. } );
  315. // At this moment editing and data pipelines produce exactly the same content.
  316. // Just a few tests will be enough here. `model to data` block contains all cases checked.
  317. describe( 'conversion in editing pipeline', () => {
  318. describe( 'model to view', () => {
  319. it( 'should convert single list (type: bulleted, style: default)', () => {
  320. setModelData( model,
  321. '<listItem listIndent="0" listType="bulleted" listStyle="default">Foo</listItem>' +
  322. '<listItem listIndent="0" listType="bulleted" listStyle="default">Bar</listItem>'
  323. );
  324. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  325. '<ul><li>Foo</li><li>Bar</li></ul>'
  326. );
  327. } );
  328. it( 'should convert single list (type: bulleted, style: circle)', () => {
  329. setModelData( model,
  330. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo</listItem>' +
  331. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Bar</listItem>'
  332. );
  333. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  334. '<ul style="list-style-type:circle"><li>Foo</li><li>Bar</li></ul>'
  335. );
  336. } );
  337. it( 'should convert nested bulleted lists (main: circle, nested: disc)', () => {
  338. setModelData( model,
  339. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 1</listItem>' +
  340. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 1</listItem>' +
  341. '<listItem listIndent="1" listType="bulleted" listStyle="disc">Bar 2</listItem>' +
  342. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 2</listItem>' +
  343. '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo 3</listItem>'
  344. );
  345. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  346. '<ul style="list-style-type:circle">' +
  347. '<li>Foo 1' +
  348. '<ul style="list-style-type:disc">' +
  349. '<li>Bar 1</li>' +
  350. '<li>Bar 2</li>' +
  351. '</ul>' +
  352. '</li>' +
  353. '<li>Foo 2</li>' +
  354. '<li>Foo 3</li>' +
  355. '</ul>'
  356. );
  357. } );
  358. // See: #8081.
  359. it( 'should convert properly nested list styles', () => {
  360. // ■ Level 0
  361. // ▶ Level 0.1
  362. // ○ Level 0.1.1
  363. // ▶ Level 0.2
  364. // ○ Level 0.2.1
  365. setModelData( model,
  366. '<listItem listIndent="0" listType="bulleted" listStyle="default">Level 0</listItem>' +
  367. '<listItem listIndent="1" listType="bulleted" listStyle="default">Level 0.1</listItem>' +
  368. '<listItem listIndent="2" listType="bulleted" listStyle="circle">Level 0.1.1</listItem>' +
  369. '<listItem listIndent="1" listType="bulleted" listStyle="default">Level 0.2</listItem>' +
  370. '<listItem listIndent="2" listType="bulleted" listStyle="circle">Level 0.2.1</listItem>'
  371. );
  372. expect( getViewData( view, { withoutSelection: true } ) ).to.equal(
  373. '<ul>' +
  374. '<li>Level 0' +
  375. '<ul>' +
  376. '<li>Level 0.1' +
  377. '<ul style="list-style-type:circle">' +
  378. '<li>Level 0.1.1</li>' +
  379. '</ul>' +
  380. '</li>' +
  381. '<li>Level 0.2' +
  382. '<ul style="list-style-type:circle">' +
  383. '<li>Level 0.2.1</li>' +
  384. '</ul>' +
  385. '</li>' +
  386. '</ul>' +
  387. '</li>' +
  388. '</ul>'
  389. );
  390. } );
  391. } );
  392. } );
  393. describe( 'integrations', () => {
  394. describe( 'merging a list into a styled list', () => {
  395. it( 'should inherit the list style attribute when merging the same kind of lists (from top, merge a single item)', () => {
  396. setModelData( model,
  397. '<paragraph>Foo Bar.[]</paragraph>' +
  398. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  399. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  400. );
  401. editor.execute( 'bulletedList' );
  402. expect( getModelData( model ) ).to.equal(
  403. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>' +
  404. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  405. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  406. );
  407. } );
  408. it( 'should inherit the list style attribute when merging the same kind of lists (from top, merge a few items)', () => {
  409. setModelData( model,
  410. '<paragraph>[Foo Bar 1.</paragraph>' +
  411. '<paragraph>Foo Bar 2.]</paragraph>' +
  412. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  413. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  414. );
  415. editor.execute( 'bulletedList' );
  416. expect( getModelData( model ) ).to.equal(
  417. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[Foo Bar 1.</listItem>' +
  418. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar 2.]</listItem>' +
  419. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  420. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  421. );
  422. } );
  423. it( 'should not inherit anything if there is no list below the inserted list', () => {
  424. setModelData( model,
  425. '<paragraph>Foo Bar 1.[]</paragraph>' +
  426. '<paragraph>Foo Bar 2.</paragraph>'
  427. );
  428. editor.execute( 'bulletedList' );
  429. expect( getModelData( model ) ).to.equal(
  430. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar 1.[]</listItem>' +
  431. '<paragraph>Foo Bar 2.</paragraph>'
  432. );
  433. } );
  434. it( 'should not inherit anything if replacing the entire content with a list', () => {
  435. setModelData( model,
  436. '<paragraph>Foo Bar 1.[]</paragraph>'
  437. );
  438. editor.execute( 'bulletedList' );
  439. expect( getModelData( model ) ).to.equal(
  440. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar 1.[]</listItem>'
  441. );
  442. } );
  443. it( 'should not inherit the list style attribute when merging different kind of lists (from top, merge a single item)', () => {
  444. setModelData( model,
  445. '<paragraph>Foo Bar.[]</paragraph>' +
  446. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  447. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>'
  448. );
  449. editor.execute( 'bulletedList' );
  450. expect( getModelData( model ) ).to.equal(
  451. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>' +
  452. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  453. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>'
  454. );
  455. } );
  456. it(
  457. 'should not inherit the list style attribute when merging different kind of lists (from bottom, merge a single item)',
  458. () => {
  459. setModelData( model,
  460. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  461. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>' +
  462. '<paragraph>Foo Bar.[]</paragraph>'
  463. );
  464. editor.execute( 'bulletedList' );
  465. expect( getModelData( model ) ).to.equal(
  466. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Foo</listItem>' +
  467. '<listItem listIndent="0" listStyle="decimal-leading-zero" listType="numbered">Bar</listItem>' +
  468. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>'
  469. );
  470. }
  471. );
  472. it( 'should inherit the list style attribute when merging the same kind of lists (from bottom, merge a single item)', () => {
  473. setModelData( model,
  474. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  475. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  476. '<paragraph>Foo Bar.[]</paragraph>'
  477. );
  478. editor.execute( 'bulletedList' );
  479. expect( getModelData( model ) ).to.equal(
  480. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  481. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  482. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>'
  483. );
  484. } );
  485. it(
  486. 'should inherit the list style attribute from listIndent=0 element when merging the same kind of lists (from bottom)',
  487. () => {
  488. setModelData( model,
  489. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  490. '<listItem listIndent="1" listStyle="square" listType="bulleted">Bar</listItem>' +
  491. '<listItem listIndent="2" listStyle="disc" listType="bulleted">Foo Bar</listItem>' +
  492. '<paragraph>Foo Bar.[]</paragraph>'
  493. );
  494. editor.execute( 'bulletedList' );
  495. expect( getModelData( model ) ).to.equal(
  496. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  497. '<listItem listIndent="1" listStyle="square" listType="bulleted">Bar</listItem>' +
  498. '<listItem listIndent="2" listStyle="disc" listType="bulleted">Foo Bar</listItem>' +
  499. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>'
  500. );
  501. }
  502. );
  503. } );
  504. describe( 'modifying "listType" attribute', () => {
  505. it( 'should inherit the list style attribute when the modified list is the same kind of the list as next sibling', () => {
  506. setModelData( model,
  507. '<listItem listIndent="0" listStyle="default" listType="numbered">Foo Bar.[]</listItem>' +
  508. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  509. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  510. );
  511. editor.execute( 'bulletedList' );
  512. expect( getModelData( model ) ).to.equal(
  513. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>' +
  514. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  515. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  516. );
  517. } );
  518. it( 'should inherit the list style attribute when the modified list is the same kind of the list as previous sibling', () => {
  519. setModelData( model,
  520. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  521. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  522. '<listItem listIndent="0" listStyle="default" listType="numbered">Foo Bar.[]</listItem>'
  523. );
  524. editor.execute( 'bulletedList' );
  525. expect( getModelData( model ) ).to.equal(
  526. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  527. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  528. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo Bar.[]</listItem>'
  529. );
  530. } );
  531. it( 'should not inherit the list style attribute when the modified list already has defined it (next sibling check)', () => {
  532. setModelData( model,
  533. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>' +
  534. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  535. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  536. );
  537. editor.execute( 'listStyle', { type: 'disc' } );
  538. expect( getModelData( model ) ).to.equal(
  539. '<listItem listIndent="0" listStyle="disc" listType="bulleted">Foo Bar.[]</listItem>' +
  540. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  541. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  542. );
  543. } );
  544. it(
  545. 'should not inherit the list style attribute when the modified list already has defined it (previous sibling check)',
  546. () => {
  547. setModelData( model,
  548. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  549. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  550. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo Bar.[]</listItem>'
  551. );
  552. editor.execute( 'listStyle', { type: 'disc' } );
  553. expect( getModelData( model ) ).to.equal(
  554. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  555. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>' +
  556. '<listItem listIndent="0" listStyle="disc" listType="bulleted">Foo Bar.[]</listItem>'
  557. );
  558. }
  559. );
  560. } );
  561. describe( 'indenting lists', () => {
  562. it( 'should restore the default value for the list style attribute when indenting a single item', () => {
  563. setModelData( model,
  564. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  565. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  566. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  567. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  568. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  569. );
  570. editor.execute( 'indentList' );
  571. expect( getModelData( model ) ).to.equal(
  572. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  573. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  574. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  575. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  576. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  577. );
  578. } );
  579. it( 'should restore the default value for the list style attribute when indenting a few items', () => {
  580. setModelData( model,
  581. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  582. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[2.</listItem>' +
  583. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.]</listItem>'
  584. );
  585. editor.execute( 'indentList' );
  586. expect( getModelData( model ) ).to.equal(
  587. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  588. '<listItem listIndent="1" listStyle="default" listType="bulleted">[2.</listItem>' +
  589. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.]</listItem>'
  590. );
  591. } );
  592. it(
  593. 'should copy the value for the list style attribute when indenting a single item into a nested list (default value)',
  594. () => {
  595. setModelData( model,
  596. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  597. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  598. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>' +
  599. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  600. );
  601. editor.execute( 'indentList' );
  602. expect( getModelData( model ) ).to.equal(
  603. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  604. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  605. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.[]</listItem>' +
  606. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  607. );
  608. }
  609. );
  610. it(
  611. 'should copy the value for the list style attribute when indenting a single item into a nested list (changed value)',
  612. () => {
  613. setModelData( model,
  614. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  615. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  616. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>' +
  617. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  618. );
  619. editor.execute( 'indentList' );
  620. expect( getModelData( model ) ).to.equal(
  621. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  622. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  623. '<listItem listIndent="1" listStyle="disc" listType="bulleted">3.[]</listItem>' +
  624. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  625. );
  626. }
  627. );
  628. it( 'should copy the value for the list style attribute when indenting a single item into a nested list', () => {
  629. setModelData( model,
  630. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  631. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  632. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  633. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  634. );
  635. editor.execute( 'indentList' );
  636. expect( getModelData( model ) ).to.equal(
  637. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  638. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  639. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  640. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  641. );
  642. } );
  643. it(
  644. 'should copy the value for the list style attribute when indenting a single item into a nested list ' +
  645. '(many nested lists check)',
  646. () => {
  647. setModelData( model,
  648. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  649. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  650. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  651. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.[]</listItem>'
  652. );
  653. editor.execute( 'indentList' );
  654. expect( getModelData( model ) ).to.equal(
  655. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  656. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  657. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  658. '<listItem listIndent="1" listStyle="disc" listType="bulleted">4.[]</listItem>'
  659. );
  660. }
  661. );
  662. it( 'should inherit the list style attribute from nested list if the `listType` is other than indenting element', () => {
  663. setModelData( model,
  664. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  665. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.</listItem>' +
  666. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>'
  667. );
  668. editor.execute( 'indentList' );
  669. expect( getModelData( model ) ).to.equal(
  670. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  671. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.</listItem>' +
  672. '<listItem listIndent="1" listStyle="decimal" listType="numbered">3.[]</listItem>'
  673. );
  674. } );
  675. // See: #8072.
  676. it( 'should not throw when indenting a list without any other content in the editor', () => {
  677. setModelData( model,
  678. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo</listItem>' +
  679. '<listItem listIndent="0" listStyle="default" listType="bulleted">[]</listItem>'
  680. );
  681. editor.execute( 'indentList' );
  682. expect( getModelData( model ) ).to.equal(
  683. '<listItem listIndent="0" listStyle="default" listType="bulleted">Foo</listItem>' +
  684. '<listItem listIndent="1" listStyle="default" listType="bulleted">[]</listItem>'
  685. );
  686. } );
  687. } );
  688. describe( 'outdenting lists', () => {
  689. it( 'should inherit the list style attribute from parent list (change the first nested item)', () => {
  690. setModelData( model,
  691. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  692. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  693. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  694. );
  695. editor.execute( 'outdentList' );
  696. expect( getModelData( model ) ).to.equal(
  697. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  698. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  699. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  700. );
  701. } );
  702. it( 'should inherit the list style attribute from parent list (change the second nested item)', () => {
  703. setModelData( model,
  704. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  705. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  706. '<listItem listIndent="1" listStyle="default" listType="bulleted">3.[]</listItem>'
  707. );
  708. editor.execute( 'outdentList' );
  709. expect( getModelData( model ) ).to.equal(
  710. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  711. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  712. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.[]</listItem>'
  713. );
  714. } );
  715. it( 'should inherit the list style attribute from parent list (modifying nested lists)', () => {
  716. setModelData( model,
  717. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  718. '<listItem listIndent="1" listStyle="default" listType="bulleted">[2.</listItem>' +
  719. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.]</listItem>'
  720. );
  721. editor.execute( 'outdentList' );
  722. expect( getModelData( model ) ).to.equal(
  723. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  724. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[2.</listItem>' +
  725. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.]</listItem>'
  726. );
  727. } );
  728. it(
  729. 'should inherit the list style attribute from parent list (outdenting many items, including the first one in the list)',
  730. () => {
  731. setModelData( model,
  732. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[1.</listItem>' +
  733. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  734. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.]</listItem>' +
  735. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  736. );
  737. editor.execute( 'outdentList' );
  738. expect( getModelData( model ) ).to.equal(
  739. '<paragraph>[1.</paragraph>' +
  740. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  741. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.]</listItem>' +
  742. '<listItem listIndent="0" listStyle="circle" listType="bulleted">4.</listItem>'
  743. );
  744. }
  745. );
  746. it(
  747. 'should inherit the list style attribute from parent list (outdenting the first item that is a parent for next list)',
  748. () => {
  749. setModelData( model,
  750. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  751. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.</listItem>' +
  752. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  753. '<listItem listIndent="3" listStyle="disc" listType="bulleted">4.</listItem>' +
  754. '<listItem listIndent="0" listStyle="circle" listType="bulleted">5.</listItem>'
  755. );
  756. editor.execute( 'outdentList' );
  757. expect( getModelData( model ) ).to.equal(
  758. '<paragraph>1.[]</paragraph>' +
  759. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  760. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  761. '<listItem listIndent="2" listStyle="disc" listType="bulleted">4.</listItem>' +
  762. '<listItem listIndent="0" listStyle="circle" listType="bulleted">5.</listItem>'
  763. );
  764. }
  765. );
  766. it( 'should not inherit the list style if outdented the only one item in the list', () => {
  767. setModelData( model,
  768. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  769. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  770. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>'
  771. );
  772. editor.execute( 'outdentList' );
  773. expect( getModelData( model ) ).to.equal(
  774. '<paragraph>1.[]</paragraph>' +
  775. '<listItem listIndent="0" listStyle="disc" listType="bulleted">2.</listItem>' +
  776. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>'
  777. );
  778. } );
  779. it( 'should not inherit the list style if outdented the only one item in the list (a paragraph below the list)', () => {
  780. setModelData( model,
  781. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>' +
  782. '<listItem listIndent="1" listStyle="disc" listType="bulleted">2.</listItem>' +
  783. '<listItem listIndent="2" listStyle="square" listType="bulleted">3.</listItem>' +
  784. '<paragraph>Foo</paragraph>'
  785. );
  786. editor.execute( 'outdentList' );
  787. expect( getModelData( model ) ).to.equal(
  788. '<paragraph>1.[]</paragraph>' +
  789. '<listItem listIndent="0" listStyle="disc" listType="bulleted">2.</listItem>' +
  790. '<listItem listIndent="1" listStyle="square" listType="bulleted">3.</listItem>' +
  791. '<paragraph>Foo</paragraph>'
  792. );
  793. } );
  794. it( 'should not inherit the list style attribute from parent list if the `listType` is other than outdenting element', () => {
  795. setModelData( model,
  796. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  797. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.[]</listItem>' +
  798. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  799. );
  800. editor.execute( 'outdentList' );
  801. expect( getModelData( model ) ).to.equal(
  802. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  803. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.[]</listItem>' +
  804. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  805. );
  806. } );
  807. it( 'should not do anything if there is no list after outdenting', () => {
  808. setModelData( model,
  809. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.[]</listItem>'
  810. );
  811. editor.execute( 'outdentList' );
  812. expect( getModelData( model ) ).to.equal(
  813. '<paragraph>1.[]</paragraph>'
  814. );
  815. } );
  816. } );
  817. describe( 'indent/outdent + undo', () => {
  818. it( 'should use the same batch for indenting a list and updating `listType` attribute', () => {
  819. setModelData( model,
  820. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  821. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  822. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  823. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  824. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  825. );
  826. editor.execute( 'indentList' );
  827. editor.execute( 'undo' );
  828. expect( getModelData( model ) ).to.equal(
  829. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  830. '<listItem listIndent="1" listStyle="default" listType="bulleted">1A.</listItem>' +
  831. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2B.</listItem>' +
  832. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  833. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  834. );
  835. } );
  836. it( 'should use the same batch for outdenting a list and updating `listType` attribute', () => {
  837. setModelData( model,
  838. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  839. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  840. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  841. );
  842. editor.execute( 'outdentList' );
  843. editor.execute( 'undo' );
  844. expect( getModelData( model ) ).to.equal(
  845. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  846. '<listItem listIndent="1" listStyle="default" listType="bulleted">2.[]</listItem>' +
  847. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>'
  848. );
  849. } );
  850. } );
  851. describe( 'delete + undo', () => {
  852. let editor, model, view;
  853. beforeEach( () => {
  854. return VirtualTestEditor
  855. .create( {
  856. plugins: [ Paragraph, ListStyleEditing, Typing, UndoEditing ]
  857. } )
  858. .then( newEditor => {
  859. editor = newEditor;
  860. model = editor.model;
  861. view = editor.editing.view;
  862. } );
  863. } );
  864. afterEach( () => {
  865. return editor.destroy();
  866. } );
  867. // See: #7930.
  868. it( 'should restore proper list style attribute after undo merging lists', () => {
  869. // ○ 1.
  870. // ○ 2.
  871. // ○ 3.
  872. // <paragraph>
  873. // ■ 1.
  874. // ■ 2.
  875. setModelData( model,
  876. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  877. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  878. '<listItem listIndent="0" listStyle="circle" listType="bulleted">3.</listItem>' +
  879. '<paragraph>[]</paragraph>' +
  880. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  881. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  882. );
  883. expect( getViewData( view, { withoutSelection: true } ), 'initial data' ).to.equal(
  884. '<ul style="list-style-type:circle">' +
  885. '<li>1.</li>' +
  886. '<li>2.</li>' +
  887. '<li>3.</li>' +
  888. '</ul>' +
  889. '<p></p>' +
  890. '<ul style="list-style-type:square">' +
  891. '<li>1.</li>' +
  892. '<li>2.</li>' +
  893. '</ul>'
  894. );
  895. // After removing the paragraph.
  896. // ○ 1.
  897. // ○ 2.
  898. // ○ 3.
  899. // ○ 1.
  900. // ○ 2.
  901. editor.execute( 'delete' );
  902. expect( getViewData( view, { withoutSelection: true } ), 'executing delete' ).to.equal(
  903. '<ul style="list-style-type:circle">' +
  904. '<li>1.</li>' +
  905. '<li>2.</li>' +
  906. '<li>3.</li>' +
  907. '<li>1.</li>' +
  908. '<li>2.</li>' +
  909. '</ul>'
  910. );
  911. // After undo.
  912. // ○ 1.
  913. // ○ 2.
  914. // ○ 3.
  915. // <paragraph>
  916. // ■ 1.
  917. // ■ 2.
  918. editor.execute( 'undo' );
  919. expect( getViewData( view, { withoutSelection: true } ), 'initial data' ).to.equal(
  920. '<ul style="list-style-type:circle">' +
  921. '<li>1.</li>' +
  922. '<li>2.</li>' +
  923. '<li>3.</li>' +
  924. '</ul>' +
  925. '<p></p>' +
  926. '<ul style="list-style-type:square">' +
  927. '<li>1.</li>' +
  928. '<li>2.</li>' +
  929. '</ul>'
  930. );
  931. } );
  932. } );
  933. describe( 'todo list', () => {
  934. let editor, model;
  935. beforeEach( () => {
  936. return VirtualTestEditor
  937. .create( {
  938. // TodoListEditing is at the end by design. Check `ListStyleEditing.afterInit()` call.
  939. plugins: [ Paragraph, ListStyleEditing, TodoListEditing ]
  940. } )
  941. .then( newEditor => {
  942. editor = newEditor;
  943. model = editor.model;
  944. } );
  945. } );
  946. afterEach( () => {
  947. return editor.destroy();
  948. } );
  949. it( 'should not add the `listStyle` attribute while creating a todo list', () => {
  950. setModelData( model, '<paragraph>Foo[]</paragraph>' );
  951. editor.execute( 'todoList' );
  952. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  953. } );
  954. it( 'should not add the `listStyle` attribute while switching the list type', () => {
  955. setModelData( model, '<listItem listIndent="0" listType="bulleted">Foo[]</listItem>' );
  956. editor.execute( 'todoList' );
  957. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  958. } );
  959. it( 'should remove the `listStyle` attribute while switching the list type that uses the list style feature', () => {
  960. setModelData( model, '<listItem listIndent="0" listType="bulleted" listStyle="circle">Foo[]</listItem>' );
  961. editor.execute( 'todoList' );
  962. expect( getModelData( model ), '<listItem listIndent="0" listType="todo">Foo[]</listItem>' );
  963. } );
  964. it( 'should not inherit the list style attribute when inserting a todo list item', () => {
  965. setModelData( model,
  966. '<paragraph>Foo Bar.[]</paragraph>' +
  967. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  968. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  969. );
  970. editor.execute( 'todoList' );
  971. expect( getModelData( model ) ).to.equal(
  972. '<listItem listIndent="0" listType="todo">Foo Bar.[]</listItem>' +
  973. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Foo</listItem>' +
  974. '<listItem listIndent="0" listStyle="circle" listType="bulleted">Bar</listItem>'
  975. );
  976. } );
  977. } );
  978. describe( 'removing content between two lists', () => {
  979. let editor, model;
  980. beforeEach( () => {
  981. return VirtualTestEditor
  982. .create( {
  983. plugins: [ Paragraph, ListStyleEditing, Typing ]
  984. } )
  985. .then( newEditor => {
  986. editor = newEditor;
  987. model = editor.model;
  988. } );
  989. } );
  990. afterEach( () => {
  991. return editor.destroy();
  992. } );
  993. it( 'should not do anything while removing a letter inside a listItem', () => {
  994. setModelData( model,
  995. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  996. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  997. '<paragraph></paragraph>' +
  998. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  999. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1000. );
  1001. editor.execute( 'delete' );
  1002. expect( getModelData( model ) ).to.equal(
  1003. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1004. '<listItem listIndent="0" listStyle="square" listType="bulleted">2[]</listItem>' +
  1005. '<paragraph></paragraph>' +
  1006. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1007. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1008. );
  1009. } );
  1010. it( 'should not do anything if there is a non-listItem before the removed content', () => {
  1011. setModelData( model,
  1012. '<paragraph>Foo</paragraph>' +
  1013. '<paragraph>[]</paragraph>' +
  1014. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1015. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1016. );
  1017. editor.execute( 'delete' );
  1018. expect( getModelData( model ) ).to.equal(
  1019. '<paragraph>Foo[]</paragraph>' +
  1020. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1021. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1022. );
  1023. } );
  1024. it( 'should not do anything if there is a non-listItem after the removed content', () => {
  1025. setModelData( model,
  1026. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1027. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  1028. '<paragraph>[]</paragraph>' +
  1029. '<paragraph>Foo</paragraph>'
  1030. );
  1031. editor.execute( 'delete' );
  1032. expect( getModelData( model ) ).to.equal(
  1033. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1034. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>' +
  1035. '<paragraph>Foo</paragraph>'
  1036. );
  1037. } );
  1038. it( 'should not do anything if there is no element after the removed content', () => {
  1039. setModelData( model,
  1040. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1041. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>' +
  1042. '<paragraph>[]</paragraph>'
  1043. );
  1044. editor.execute( 'delete' );
  1045. expect( getModelData( model ) ).to.equal(
  1046. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1047. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.[]</listItem>'
  1048. );
  1049. } );
  1050. it(
  1051. 'should modify the the `listStyle` attribute for the merged (second) list when removing content between those lists',
  1052. () => {
  1053. setModelData( model,
  1054. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1055. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1056. '<paragraph>[]</paragraph>' +
  1057. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1058. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1059. );
  1060. editor.execute( 'delete' );
  1061. expect( getModelData( model ) ).to.equal(
  1062. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1063. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  1064. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1065. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  1066. );
  1067. }
  1068. );
  1069. it( 'should read the `listStyle` attribute from the most outer list', () => {
  1070. setModelData( model,
  1071. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1072. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1073. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.1.</listItem>' +
  1074. '<listItem listIndent="2" listStyle="default" listType="numbered">2.1.1</listItem>' +
  1075. '<paragraph>[]</paragraph>' +
  1076. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1077. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1078. );
  1079. editor.execute( 'delete' );
  1080. expect( getModelData( model ) ).to.equal(
  1081. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1082. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1083. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.1.</listItem>' +
  1084. '<listItem listIndent="2" listStyle="default" listType="numbered">2.1.1[]</listItem>' +
  1085. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1086. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  1087. );
  1088. } );
  1089. it(
  1090. 'should not modify the the `listStyle` attribute for the merged (second) list if merging different `listType` attribute',
  1091. () => {
  1092. setModelData( model,
  1093. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1094. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1095. '<paragraph>[]</paragraph>' +
  1096. '<listItem listIndent="0" listStyle="decimal" listType="numbered">1.</listItem>' +
  1097. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.</listItem>'
  1098. );
  1099. editor.execute( 'delete' );
  1100. expect( getModelData( model ) ).to.equal(
  1101. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1102. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  1103. '<listItem listIndent="0" listStyle="decimal" listType="numbered">1.</listItem>' +
  1104. '<listItem listIndent="0" listStyle="decimal" listType="numbered">2.</listItem>'
  1105. );
  1106. }
  1107. );
  1108. it(
  1109. 'should modify the the `listStyle` attribute for the merged (second) list when removing content from both lists',
  1110. () => {
  1111. setModelData( model,
  1112. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1113. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1114. '<listItem listIndent="0" listStyle="square" listType="bulleted">[3.</listItem>' +
  1115. '<paragraph>Foo</paragraph>' +
  1116. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.]</listItem>' +
  1117. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1118. );
  1119. editor.execute( 'delete' );
  1120. expect( getModelData( model ) ).to.equal(
  1121. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1122. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1123. '<listItem listIndent="0" listStyle="square" listType="bulleted">[]</listItem>' +
  1124. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  1125. );
  1126. }
  1127. );
  1128. it(
  1129. 'should modify the the `listStyle` attribute for the merged (second) list when typing over content from both lists',
  1130. () => {
  1131. setModelData( model,
  1132. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1133. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1134. '<listItem listIndent="0" listStyle="square" listType="bulleted">[3.</listItem>' +
  1135. '<paragraph>Foo</paragraph>' +
  1136. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.]</listItem>' +
  1137. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1138. );
  1139. editor.execute( 'input', { text: 'Foo' } );
  1140. expect( getModelData( model ) ).to.equal(
  1141. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1142. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1143. '<listItem listIndent="0" listStyle="square" listType="bulleted">Foo[]</listItem>' +
  1144. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>'
  1145. );
  1146. }
  1147. );
  1148. it(
  1149. 'should not modify the the `listStyle` if lists were not merged but the content was partially removed',
  1150. () => {
  1151. setModelData( model,
  1152. '<listItem listIndent="0" listStyle="square" listType="bulleted">111.</listItem>' +
  1153. '<listItem listIndent="0" listStyle="square" listType="bulleted">222.</listItem>' +
  1154. '<listItem listIndent="0" listStyle="square" listType="bulleted">[333.</listItem>' +
  1155. '<paragraph>Foo</paragraph>' +
  1156. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1]11.</listItem>' +
  1157. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1158. );
  1159. editor.execute( 'delete' );
  1160. expect( getModelData( model ) ).to.equal(
  1161. '<listItem listIndent="0" listStyle="square" listType="bulleted">111.</listItem>' +
  1162. '<listItem listIndent="0" listStyle="square" listType="bulleted">222.</listItem>' +
  1163. '<listItem listIndent="0" listStyle="circle" listType="bulleted">[]11.</listItem>' +
  1164. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1165. );
  1166. }
  1167. );
  1168. it( 'should not do anything while typing in a list item', () => {
  1169. setModelData( model,
  1170. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1171. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.[]</listItem>' +
  1172. '<listItem listIndent="0" listStyle="square" listType="bulleted">3.</listItem>' +
  1173. '<paragraph></paragraph>' +
  1174. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1175. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1176. );
  1177. const modelChangeStub = sinon.stub( model, 'change' ).callThrough();
  1178. simulateTyping( ' Foo' );
  1179. // Each character calls `editor.model.change()`.
  1180. expect( modelChangeStub.callCount ).to.equal( 4 );
  1181. expect( getModelData( model ) ).to.equal(
  1182. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1183. '<listItem listIndent="0" listStyle="square" listType="bulleted">2. Foo[]</listItem>' +
  1184. '<listItem listIndent="0" listStyle="square" listType="bulleted">3.</listItem>' +
  1185. '<paragraph></paragraph>' +
  1186. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1187. '<listItem listIndent="0" listStyle="circle" listType="bulleted">2.</listItem>'
  1188. );
  1189. } );
  1190. // See: #8073.
  1191. it( 'should not crash when removing a content between intended lists', () => {
  1192. setModelData( model,
  1193. '<listItem listIndent="0" listStyle="default" listType="bulleted">aaaa</listItem>' +
  1194. '<listItem listIndent="1" listStyle="default" listType="bulleted">bb[bb</listItem>' +
  1195. '<listItem listIndent="2" listStyle="default" listType="bulleted">cc]cc</listItem>' +
  1196. '<listItem listIndent="3" listStyle="default" listType="bulleted">dddd</listItem>'
  1197. );
  1198. editor.execute( 'delete' );
  1199. expect( getModelData( model ) ).to.equal(
  1200. '<listItem listIndent="0" listStyle="default" listType="bulleted">aaaa</listItem>' +
  1201. '<listItem listIndent="1" listStyle="default" listType="bulleted">bb[]cc</listItem>' +
  1202. '<listItem listIndent="2" listStyle="default" listType="bulleted">dddd</listItem>'
  1203. );
  1204. } );
  1205. it( 'should read the `listStyle` attribute from the most outer selected list while removing content between lists', () => {
  1206. setModelData( model,
  1207. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1208. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1209. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.1.</listItem>' +
  1210. '<listItem listIndent="2" listStyle="lower-latin" listType="numbered">2.1.1[foo</listItem>' +
  1211. '<paragraph>Foo</paragraph>' +
  1212. '<listItem listIndent="0" listStyle="circle" listType="bulleted">1.</listItem>' +
  1213. '<listItem listIndent="1" listStyle="circle" listType="bulleted">bar]2.</listItem>'
  1214. );
  1215. editor.execute( 'delete' );
  1216. expect( getModelData( model ) ).to.equal(
  1217. '<listItem listIndent="0" listStyle="square" listType="bulleted">1.</listItem>' +
  1218. '<listItem listIndent="0" listStyle="square" listType="bulleted">2.</listItem>' +
  1219. '<listItem listIndent="1" listStyle="decimal" listType="numbered">2.1.</listItem>' +
  1220. '<listItem listIndent="2" listStyle="lower-latin" listType="numbered">2.1.1[]2.</listItem>'
  1221. );
  1222. } );
  1223. function simulateTyping( text ) {
  1224. // While typing, every character is an atomic change.
  1225. text.split( '' ).forEach( character => {
  1226. editor.execute( 'input', {
  1227. text: character
  1228. } );
  1229. } );
  1230. }
  1231. } );
  1232. } );
  1233. } );