treewalker.js 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /* globals document */
  6. /* bender-tags: view */
  7. import Document from '/ckeditor5/engine/view/document.js';
  8. import AttributeElement from '/ckeditor5/engine/view/attributeelement.js';
  9. import ContainerElement from '/ckeditor5/engine/view/containerelement.js';
  10. import Text from '/ckeditor5/engine/view/text.js';
  11. import TreeWalker from '/ckeditor5/engine/view/treewalker.js';
  12. import Position from '/ckeditor5/engine/view/position.js';
  13. import Range from '/ckeditor5/engine/view/range.js';
  14. import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
  15. describe( 'TreeWalker', () => {
  16. let doc, root, img1, paragraph, bold, textAbcd, charY, img2, charX;
  17. let rootBeginning, rootEnding;
  18. before( () => {
  19. doc = new Document();
  20. root = doc.createRoot( document.createElement( 'div' ) );
  21. // root
  22. // |- img1
  23. // |- p
  24. // |- b
  25. // | |- A
  26. // | |- B
  27. // | |- C
  28. // | |- D
  29. // |
  30. // |- Y
  31. // |
  32. // |- img2
  33. // |
  34. // |- X
  35. textAbcd = new Text( 'abcd' );
  36. bold = new AttributeElement( 'b', null, [ textAbcd ] );
  37. charY = new Text( 'y' );
  38. img2 = new ContainerElement( 'img2' );
  39. charX = new Text( 'x' );
  40. paragraph = new ContainerElement( 'p', null, [ bold, charY, img2, charX ] );
  41. img1 = new ContainerElement( 'img1' );
  42. root.insertChildren( 0, [ img1, paragraph ] );
  43. rootBeginning = new Position( root, 0 );
  44. rootEnding = new Position( root, 2 );
  45. } );
  46. describe( 'constructor', () => {
  47. it( 'should throw if neither boundaries nor starting position is set', () => {
  48. expect( () => {
  49. new TreeWalker();
  50. } ).to.throw( CKEditorError, /^view-tree-walker-no-start-position/ );
  51. expect( () => {
  52. new TreeWalker( {} );
  53. } ).to.throw( CKEditorError, /^view-tree-walker-no-start-position/ );
  54. expect( () => {
  55. new TreeWalker( { singleCharacters: true } );
  56. } ).to.throw( CKEditorError, /^view-tree-walker-no-start-position/ );
  57. } );
  58. it( 'should throw if walking direction is unknown', () => {
  59. expect( () => {
  60. new TreeWalker( { startPosition: rootBeginning, direction: 'unknown' } );
  61. } ).to.throw( CKEditorError, /^view-tree-walker-unknown-direction/ );
  62. } );
  63. } );
  64. describe( 'iterate from start position `startPosition`', () => {
  65. let expected;
  66. beforeEach( () => {
  67. expected = [
  68. {
  69. type: 'elementStart',
  70. item: img1,
  71. previousPosition: new Position( root, 0 ),
  72. nextPosition: new Position( img1, 0 )
  73. },
  74. {
  75. type: 'elementEnd',
  76. item: img1,
  77. previousPosition: new Position( img1, 0 ),
  78. nextPosition: new Position( root, 1 )
  79. },
  80. {
  81. type: 'elementStart',
  82. item: paragraph,
  83. previousPosition: new Position( root, 1 ),
  84. nextPosition: new Position( paragraph, 0 )
  85. },
  86. {
  87. type: 'elementStart',
  88. item: bold,
  89. previousPosition: new Position( paragraph, 0 ),
  90. nextPosition: new Position( bold, 0 )
  91. },
  92. {
  93. type: 'text',
  94. text: 'abcd',
  95. previousPosition: new Position( bold, 0 ),
  96. nextPosition: new Position( bold, 1 )
  97. },
  98. {
  99. type: 'elementEnd',
  100. item: bold,
  101. previousPosition: new Position( bold, 1 ),
  102. nextPosition: new Position( paragraph, 1 )
  103. },
  104. {
  105. type: 'text',
  106. text: 'y',
  107. previousPosition: new Position( paragraph, 1 ),
  108. nextPosition: new Position( paragraph, 2 )
  109. },
  110. {
  111. type: 'elementStart',
  112. item: img2,
  113. previousPosition: new Position( paragraph, 2 ),
  114. nextPosition: new Position( img2, 0 )
  115. },
  116. {
  117. type: 'elementEnd',
  118. item: img2,
  119. previousPosition: new Position( img2, 0 ),
  120. nextPosition: new Position( paragraph, 3 )
  121. },
  122. {
  123. type: 'text',
  124. text: 'x',
  125. previousPosition: new Position( paragraph, 3 ),
  126. nextPosition: new Position( paragraph, 4 )
  127. },
  128. {
  129. type: 'elementEnd',
  130. item: paragraph,
  131. previousPosition: new Position( paragraph, 4 ),
  132. nextPosition: new Position( root, 2 )
  133. }
  134. ];
  135. } );
  136. it( 'should provide iterator interface with default forward direction', () => {
  137. let iterator = new TreeWalker( { startPosition: rootBeginning } );
  138. let i = 0;
  139. for ( let value of iterator ) {
  140. expectValue( value, expected[ i++ ] );
  141. }
  142. expect( i ).to.equal( expected.length );
  143. } );
  144. it( 'should provide iterator interface with forward direction', () => {
  145. let iterator = new TreeWalker( { startPosition: rootBeginning, direction: 'forward' } );
  146. let i = 0;
  147. for ( let value of iterator ) {
  148. expectValue( value, expected[ i++ ] );
  149. }
  150. expect( i ).to.equal( expected.length );
  151. } );
  152. it( 'should provide iterator interface which backward direction', () => {
  153. let iterator = new TreeWalker( { startPosition: rootEnding, direction: 'backward' } );
  154. let i = expected.length;
  155. for ( let value of iterator ) {
  156. expectValue( value, expected[ --i ], { direction: 'backward' } );
  157. }
  158. expect( i ).to.equal( 0 );
  159. } );
  160. it( 'should start iterating at the startPosition witch is not a root bound', () => {
  161. let iterator = new TreeWalker( { startPosition: new Position( root, 1 ) } );
  162. let i = 2;
  163. for ( let value of iterator ) {
  164. expectValue( value, expected[ i++ ] );
  165. }
  166. expect( i ).to.equal( expected.length );
  167. } );
  168. it( 'should start iterating at the startPosition witch is not a root bound, going backward', () => {
  169. let expected = [
  170. {
  171. type: 'elementStart',
  172. item: img1,
  173. previousPosition: new Position( root, 0 ),
  174. nextPosition: new Position( img1, 0 )
  175. },
  176. {
  177. type: 'elementEnd',
  178. item: img1,
  179. previousPosition: new Position( img1, 0 ),
  180. nextPosition: new Position( root, 1 )
  181. }
  182. ];
  183. let iterator = new TreeWalker( { startPosition: new Position( root, 1 ), direction: 'backward' } );
  184. let i = expected.length;
  185. for ( let value of iterator ) {
  186. expectValue( value, expected[ --i ], { direction: 'backward' } );
  187. }
  188. expect( i ).to.equal( 0 );
  189. } );
  190. } );
  191. describe( 'iterate trough the range `boundary`', () => {
  192. describe( 'range starts between elements', () => {
  193. let expected, range;
  194. before( () => {
  195. expected = [
  196. {
  197. type: 'elementStart',
  198. item: paragraph,
  199. previousPosition: new Position( root, 1 ),
  200. nextPosition: new Position( paragraph, 0 )
  201. },
  202. {
  203. type: 'elementStart',
  204. item: bold,
  205. previousPosition: new Position( paragraph, 0 ),
  206. nextPosition: new Position( bold, 0 )
  207. },
  208. {
  209. type: 'text',
  210. text: 'abcd',
  211. previousPosition: new Position( bold, 0 ),
  212. nextPosition: new Position( bold, 1 )
  213. },
  214. {
  215. type: 'elementEnd',
  216. item: bold,
  217. previousPosition: new Position( bold, 1 ),
  218. nextPosition: new Position( paragraph, 1 )
  219. },
  220. {
  221. type: 'text',
  222. text: 'y',
  223. previousPosition: new Position( paragraph, 1 ),
  224. nextPosition: new Position( paragraph, 2 )
  225. },
  226. {
  227. type: 'elementStart',
  228. item: img2,
  229. previousPosition: new Position( paragraph, 2 ),
  230. nextPosition: new Position( img2, 0 )
  231. },
  232. {
  233. type: 'elementEnd',
  234. item: img2,
  235. previousPosition: new Position( img2, 0 ),
  236. nextPosition: new Position( paragraph, 3 )
  237. }
  238. ];
  239. range = Range.createFromParentsAndOffsets( root, 1, paragraph, 3 );
  240. } );
  241. it( 'should iterating over the range', () => {
  242. let iterator = new TreeWalker( { boundaries: range } );
  243. let i = 0;
  244. for ( let value of iterator ) {
  245. expectValue( value, expected[ i++ ] );
  246. }
  247. expect( i ).to.equal( expected.length );
  248. } );
  249. it( 'should iterating over the range going backward', () => {
  250. let iterator = new TreeWalker( { boundaries: range, direction: 'backward' } );
  251. let i = expected.length;
  252. for ( let value of iterator ) {
  253. expectValue( value, expected[ --i ], { direction: 'backward' } );
  254. }
  255. expect( i ).to.equal( 0 );
  256. } );
  257. } );
  258. describe( 'range starts inside the text', () => {
  259. let expected, range;
  260. before( () => {
  261. expected = [
  262. {
  263. type: 'text',
  264. text: 'bcd',
  265. previousPosition: new Position( textAbcd, 1 ),
  266. nextPosition: new Position( bold, 1 )
  267. },
  268. {
  269. type: 'elementEnd',
  270. item: bold,
  271. previousPosition: new Position( bold, 1 ),
  272. nextPosition: new Position( paragraph, 1 )
  273. },
  274. {
  275. type: 'text',
  276. text: 'y',
  277. previousPosition: new Position( paragraph, 1 ),
  278. nextPosition: new Position( paragraph, 2 )
  279. },
  280. {
  281. type: 'elementStart',
  282. item: img2,
  283. previousPosition: new Position( paragraph, 2 ),
  284. nextPosition: new Position( img2, 0 )
  285. },
  286. {
  287. type: 'elementEnd',
  288. item: img2,
  289. previousPosition: new Position( img2, 0 ),
  290. nextPosition: new Position( paragraph, 3 )
  291. }
  292. ];
  293. range = Range.createFromParentsAndOffsets( textAbcd, 1, paragraph, 3 );
  294. } );
  295. it( 'should return part of the text', () => {
  296. let iterator = new TreeWalker( { boundaries: range } );
  297. let i = 0;
  298. for ( let value of iterator ) {
  299. expectValue( value, expected[ i++ ] );
  300. }
  301. expect( i ).to.equal( expected.length );
  302. } );
  303. it( 'should return part of the text going backward', () => {
  304. let iterator = new TreeWalker( {
  305. boundaries: range,
  306. direction: 'backward'
  307. }
  308. );
  309. let i = expected.length;
  310. for ( let value of iterator ) {
  311. expectValue( value, expected[ --i ], { direction: 'backward' } );
  312. }
  313. expect( i ).to.equal( 0 );
  314. } );
  315. } );
  316. describe( 'range ends inside the text', () => {
  317. let expected, range;
  318. before( () => {
  319. expected = [
  320. {
  321. type: 'elementStart',
  322. item: img1,
  323. previousPosition: new Position( root, 0 ),
  324. nextPosition: new Position( img1, 0 )
  325. },
  326. {
  327. type: 'elementEnd',
  328. item: img1,
  329. previousPosition: new Position( img1, 0 ),
  330. nextPosition: new Position( root, 1 )
  331. },
  332. {
  333. type: 'elementStart',
  334. item: paragraph,
  335. previousPosition: new Position( root, 1 ),
  336. nextPosition: new Position( paragraph, 0 )
  337. },
  338. {
  339. type: 'elementStart',
  340. item: bold,
  341. previousPosition: new Position( paragraph, 0 ),
  342. nextPosition: new Position( bold, 0 )
  343. },
  344. {
  345. type: 'text',
  346. text: 'ab',
  347. previousPosition: new Position( bold, 0 ),
  348. nextPosition: new Position( textAbcd, 2 )
  349. }
  350. ];
  351. range = new Range( rootBeginning, new Position( textAbcd, 2 ) );
  352. } );
  353. it( 'should return part of the text', () => {
  354. let iterator = new TreeWalker( { boundaries: range } );
  355. let i = 0;
  356. for ( let value of iterator ) {
  357. expectValue( value, expected[ i++ ] );
  358. }
  359. expect( i ).to.equal( expected.length );
  360. } );
  361. it( 'should return part of the text going backward', () => {
  362. let iterator = new TreeWalker( {
  363. boundaries: range,
  364. startPosition: range.end,
  365. direction: 'backward'
  366. } );
  367. let i = expected.length;
  368. for ( let value of iterator ) {
  369. expectValue( value, expected[ --i ], { direction: 'backward' } );
  370. }
  371. expect( i ).to.equal( 0 );
  372. } );
  373. } );
  374. describe( 'range starts and ends inside the same text', () => {
  375. let expected, range;
  376. before( () => {
  377. expected = [
  378. {
  379. type: 'text',
  380. text: 'bc',
  381. previousPosition: new Position( textAbcd, 1 ),
  382. nextPosition: new Position( textAbcd, 3 )
  383. }
  384. ];
  385. range = new Range( new Position( textAbcd, 1 ), new Position( textAbcd, 3 ) );
  386. } );
  387. it( 'should return part of the text', () => {
  388. let iterator = new TreeWalker( { boundaries: range } );
  389. let i = 0;
  390. for ( let value of iterator ) {
  391. expectValue( value, expected[ i++ ] );
  392. }
  393. expect( i ).to.equal( expected.length );
  394. } );
  395. it( 'should return part of the text going backward', () => {
  396. let iterator = new TreeWalker( {
  397. boundaries: range,
  398. startPosition: range.end,
  399. direction: 'backward'
  400. } );
  401. let i = expected.length;
  402. for ( let value of iterator ) {
  403. expectValue( value, expected[ --i ], { direction: 'backward' } );
  404. }
  405. expect( i ).to.equal( 0 );
  406. } );
  407. } );
  408. describe( 'custom start position', () => {
  409. it( 'should iterating from the start position', () => {
  410. let expected = [
  411. {
  412. type: 'text',
  413. text: 'y',
  414. previousPosition: new Position( paragraph, 1 ),
  415. nextPosition: new Position( paragraph, 2 )
  416. },
  417. {
  418. type: 'elementStart',
  419. item: img2,
  420. previousPosition: new Position( paragraph, 2 ),
  421. nextPosition: new Position( img2, 0 )
  422. },
  423. {
  424. type: 'elementEnd',
  425. item: img2,
  426. previousPosition: new Position( img2, 0 ),
  427. nextPosition: new Position( paragraph, 3 )
  428. }
  429. ];
  430. let range = Range.createFromParentsAndOffsets( bold, 1, paragraph, 3 );
  431. let iterator = new TreeWalker( {
  432. boundaries: range,
  433. startPosition: new Position( paragraph, 1 )
  434. } );
  435. let i = 0;
  436. for ( let value of iterator ) {
  437. expectValue( value, expected[ i++ ] );
  438. }
  439. expect( i ).to.equal( expected.length );
  440. } );
  441. it( 'should iterating from the start position going backward', () => {
  442. let expected = [
  443. {
  444. type: 'text',
  445. text: 'bcd',
  446. previousPosition: new Position( textAbcd, 1 ),
  447. nextPosition: new Position( bold, 1 )
  448. },
  449. {
  450. type: 'elementEnd',
  451. item: bold,
  452. previousPosition: new Position( bold, 1 ),
  453. nextPosition: new Position( paragraph, 1 )
  454. },
  455. {
  456. type: 'text',
  457. text: 'y',
  458. previousPosition: new Position( paragraph, 1 ),
  459. nextPosition: new Position( paragraph, 2 )
  460. }
  461. ];
  462. let range = new Range( new Position( textAbcd, 1 ), new Position( paragraph, 3 ) );
  463. let iterator = new TreeWalker( {
  464. boundaries: range,
  465. startPosition: new Position( paragraph, 2 ),
  466. direction: 'backward'
  467. } );
  468. let i = expected.length;
  469. for ( let value of iterator ) {
  470. expectValue( value, expected[ --i ], { direction: 'backward' } );
  471. }
  472. expect( i ).to.equal( 0 );
  473. } );
  474. } );
  475. } );
  476. describe( 'iterate by every single characters `singleCharacter`', () => {
  477. describe( 'whole root', () => {
  478. let expected;
  479. before( () => {
  480. expected = [
  481. {
  482. type: 'elementStart',
  483. item: img1,
  484. previousPosition: new Position( root, 0 ),
  485. nextPosition: new Position( img1, 0 )
  486. },
  487. {
  488. type: 'elementEnd',
  489. item: img1,
  490. previousPosition: new Position( img1, 0 ),
  491. nextPosition: new Position( root, 1 )
  492. },
  493. {
  494. type: 'elementStart',
  495. item: paragraph,
  496. previousPosition: new Position( root, 1 ),
  497. nextPosition: new Position( paragraph, 0 )
  498. },
  499. {
  500. type: 'elementStart',
  501. item: bold,
  502. previousPosition: new Position( paragraph, 0 ),
  503. nextPosition: new Position( bold, 0 )
  504. },
  505. {
  506. type: 'text',
  507. text: 'a',
  508. previousPosition: new Position( bold, 0 ),
  509. nextPosition: new Position( textAbcd, 1 )
  510. },
  511. {
  512. type: 'text',
  513. text: 'b',
  514. previousPosition: new Position( textAbcd, 1 ),
  515. nextPosition: new Position( textAbcd, 2 )
  516. },
  517. {
  518. type: 'text',
  519. text: 'c',
  520. previousPosition: new Position( textAbcd, 2 ),
  521. nextPosition: new Position( textAbcd, 3 )
  522. },
  523. {
  524. type: 'text',
  525. text: 'd',
  526. previousPosition: new Position( textAbcd, 3 ),
  527. nextPosition: new Position( bold, 1 )
  528. },
  529. {
  530. type: 'elementEnd',
  531. item: bold,
  532. previousPosition: new Position( bold, 1 ),
  533. nextPosition: new Position( paragraph, 1 )
  534. },
  535. {
  536. type: 'text',
  537. text: 'y',
  538. previousPosition: new Position( paragraph, 1 ),
  539. nextPosition: new Position( paragraph, 2 )
  540. },
  541. {
  542. type: 'elementStart',
  543. item: img2,
  544. previousPosition: new Position( paragraph, 2 ),
  545. nextPosition: new Position( img2, 0 )
  546. },
  547. {
  548. type: 'elementEnd',
  549. item: img2,
  550. previousPosition: new Position( img2, 0 ),
  551. nextPosition: new Position( paragraph, 3 )
  552. },
  553. {
  554. type: 'text',
  555. text: 'x',
  556. previousPosition: new Position( paragraph, 3 ),
  557. nextPosition: new Position( paragraph, 4 )
  558. },
  559. {
  560. type: 'elementEnd',
  561. item: paragraph,
  562. previousPosition: new Position( paragraph, 4 ),
  563. nextPosition: new Position( root, 2 )
  564. }
  565. ];
  566. } );
  567. it( 'should return single characters', () => {
  568. let iterator = new TreeWalker( { startPosition: rootBeginning, singleCharacters: true } );
  569. let i = 0;
  570. for ( let value of iterator ) {
  571. expectValue( value, expected[ i++ ] );
  572. }
  573. expect( i ).to.equal( expected.length );
  574. } );
  575. it( 'should return single characters going backward', () => {
  576. let iterator = new TreeWalker( {
  577. startPosition: rootEnding,
  578. singleCharacters: true,
  579. direction: 'backward'
  580. } );
  581. let i = expected.length;
  582. for ( let value of iterator ) {
  583. expectValue( value, expected[ --i ], { direction: 'backward' } );
  584. }
  585. expect( i ).to.equal( 0 );
  586. } );
  587. } );
  588. describe( 'range', () => {
  589. let range, expected;
  590. before( () => {
  591. expected = [
  592. {
  593. type: 'text',
  594. text: 'a',
  595. previousPosition: new Position( bold, 0 ),
  596. nextPosition: new Position( textAbcd, 1 )
  597. },
  598. {
  599. type: 'text',
  600. text: 'b',
  601. previousPosition: new Position( textAbcd, 1 ),
  602. nextPosition: new Position( textAbcd, 2 )
  603. },
  604. {
  605. type: 'text',
  606. text: 'c',
  607. previousPosition: new Position( textAbcd, 2 ),
  608. nextPosition: new Position( textAbcd, 3 )
  609. },
  610. {
  611. type: 'text',
  612. text: 'd',
  613. previousPosition: new Position( textAbcd, 3 ),
  614. nextPosition: new Position( bold, 1 )
  615. },
  616. {
  617. type: 'elementEnd',
  618. item: bold,
  619. previousPosition: new Position( bold, 1 ),
  620. nextPosition: new Position( paragraph, 1 )
  621. },
  622. {
  623. type: 'text',
  624. text: 'y',
  625. previousPosition: new Position( paragraph, 1 ),
  626. nextPosition: new Position( paragraph, 2 )
  627. },
  628. {
  629. type: 'elementStart',
  630. item: img2,
  631. previousPosition: new Position( paragraph, 2 ),
  632. nextPosition: new Position( img2, 0 )
  633. }
  634. ];
  635. range = new Range( new Position( bold, 0 ), new Position( img2, 0 ) );
  636. } );
  637. it( 'should respect boundaries', () => {
  638. let iterator = new TreeWalker( { boundaries: range, singleCharacters: true } );
  639. let i = 0;
  640. for ( let value of iterator ) {
  641. expectValue( value, expected[ i++ ] );
  642. }
  643. expect( i ).to.equal( expected.length );
  644. } );
  645. it( 'should respect boundaries going backward', () => {
  646. let iterator = new TreeWalker( {
  647. boundaries: range,
  648. singleCharacters: true,
  649. direction: 'backward'
  650. } );
  651. let i = expected.length;
  652. for ( let value of iterator ) {
  653. expectValue( value, expected[ --i ], { direction: 'backward' } );
  654. }
  655. expect( i ).to.equal( 0 );
  656. } );
  657. } );
  658. } );
  659. describe( 'iterate omitting child nodes and elementEnd `shallow`', () => {
  660. let expected;
  661. before( () => {
  662. expected = [
  663. {
  664. type: 'elementStart',
  665. item: img1,
  666. previousPosition: new Position( root, 0 ),
  667. nextPosition: new Position( root, 1 )
  668. },
  669. {
  670. type: 'elementStart',
  671. item: paragraph,
  672. previousPosition: new Position( root, 1 ),
  673. nextPosition: new Position( root, 2 )
  674. }
  675. ];
  676. } );
  677. it( 'should not enter elements', () => {
  678. let iterator = new TreeWalker( { startPosition: rootBeginning, shallow: true } );
  679. let i = 0;
  680. for ( let value of iterator ) {
  681. expectValue( value, expected[ i++ ] );
  682. }
  683. expect( i ).to.equal( expected.length );
  684. } );
  685. it( 'should not enter elements going backward', () => {
  686. let iterator = new TreeWalker( { startPosition: rootEnding, shallow: true, direction: 'backward' } );
  687. let i = expected.length;
  688. for ( let value of iterator ) {
  689. expectValue( value, expected[ --i ], { direction: 'backward' } );
  690. }
  691. expect( i ).to.equal( 0 );
  692. } );
  693. } );
  694. describe( 'iterate omitting elementEnd `ignoreElementEnd`', () => {
  695. describe( 'merged text', () => {
  696. let expected;
  697. before( () => {
  698. expected = [
  699. {
  700. type: 'elementStart',
  701. item: img1,
  702. previousPosition: new Position( root, 0 ),
  703. nextPosition: new Position( img1, 0 )
  704. },
  705. {
  706. type: 'elementStart',
  707. item: paragraph,
  708. previousPosition: new Position( root, 1 ),
  709. nextPosition: new Position( paragraph, 0 )
  710. },
  711. {
  712. type: 'elementStart',
  713. item: bold,
  714. previousPosition: new Position( paragraph, 0 ),
  715. nextPosition: new Position( bold, 0 )
  716. },
  717. {
  718. type: 'text',
  719. text: 'abcd',
  720. previousPosition: new Position( bold, 0 ),
  721. nextPosition: new Position( bold, 1 )
  722. },
  723. {
  724. type: 'text',
  725. text: 'y',
  726. previousPosition: new Position( paragraph, 1 ),
  727. nextPosition: new Position( paragraph, 2 )
  728. },
  729. {
  730. type: 'elementStart',
  731. item: img2,
  732. previousPosition: new Position( paragraph, 2 ),
  733. nextPosition: new Position( img2, 0 )
  734. },
  735. {
  736. type: 'text',
  737. text: 'x',
  738. previousPosition: new Position( paragraph, 3 ),
  739. nextPosition: new Position( paragraph, 4 )
  740. }
  741. ];
  742. } );
  743. it( 'should iterate ignoring elementEnd', () => {
  744. let iterator = new TreeWalker( { startPosition: rootBeginning, ignoreElementEnd: true } );
  745. let i = 0;
  746. for ( let value of iterator ) {
  747. expectValue( value, expected[ i++ ] );
  748. }
  749. expect( i ).to.equal( expected.length );
  750. } );
  751. it( 'should iterate ignoring elementEnd going backward', () => {
  752. let iterator = new TreeWalker( {
  753. startPosition: rootEnding,
  754. ignoreElementEnd: true,
  755. direction: 'backward'
  756. } );
  757. let i = expected.length;
  758. for ( let value of iterator ) {
  759. expectValue( value, expected[ --i ], { direction: 'backward' } );
  760. }
  761. expect( i ).to.equal( 0 );
  762. } );
  763. } );
  764. describe( 'single character', () => {
  765. let expected;
  766. before( () => {
  767. expected = [
  768. {
  769. type: 'elementStart',
  770. item: img1,
  771. previousPosition: new Position( root, 0 ),
  772. nextPosition: new Position( img1, 0 )
  773. },
  774. {
  775. type: 'elementStart',
  776. item: paragraph,
  777. previousPosition: new Position( root, 1 ),
  778. nextPosition: new Position( paragraph, 0 )
  779. },
  780. {
  781. type: 'elementStart',
  782. item: bold,
  783. previousPosition: new Position( paragraph, 0 ),
  784. nextPosition: new Position( bold, 0 )
  785. },
  786. {
  787. type: 'text',
  788. text: 'a',
  789. previousPosition: new Position( bold, 0 ),
  790. nextPosition: new Position( textAbcd, 1 )
  791. },
  792. {
  793. type: 'text',
  794. text: 'b',
  795. previousPosition: new Position( textAbcd, 1 ),
  796. nextPosition: new Position( textAbcd, 2 )
  797. },
  798. {
  799. type: 'text',
  800. text: 'c',
  801. previousPosition: new Position( textAbcd, 2 ),
  802. nextPosition: new Position( textAbcd, 3 )
  803. },
  804. {
  805. type: 'text',
  806. text: 'd',
  807. previousPosition: new Position( textAbcd, 3 ),
  808. nextPosition: new Position( bold, 1 )
  809. },
  810. {
  811. type: 'text',
  812. text: 'y',
  813. previousPosition: new Position( paragraph, 1 ),
  814. nextPosition: new Position( paragraph, 2 )
  815. },
  816. {
  817. type: 'elementStart',
  818. item: img2,
  819. previousPosition: new Position( paragraph, 2 ),
  820. nextPosition: new Position( img2, 0 )
  821. },
  822. {
  823. type: 'text',
  824. text: 'x',
  825. previousPosition: new Position( paragraph, 3 ),
  826. nextPosition: new Position( paragraph, 4 )
  827. }
  828. ];
  829. } );
  830. it( 'should return single characters ignoring elementEnd', () => {
  831. let iterator = new TreeWalker( {
  832. startPosition: rootBeginning,
  833. singleCharacters: true,
  834. ignoreElementEnd: true
  835. } );
  836. let i = 0;
  837. for ( let value of iterator ) {
  838. expectValue( value, expected[ i++ ] );
  839. }
  840. expect( i ).to.equal( expected.length );
  841. } );
  842. it( 'should return single characters ignoring elementEnd going backward', () => {
  843. let iterator = new TreeWalker( {
  844. startPosition: rootEnding,
  845. singleCharacters: true,
  846. ignoreElementEnd: true,
  847. direction: 'backward'
  848. } );
  849. let i = expected.length;
  850. for ( let value of iterator ) {
  851. expectValue( value, expected[ --i ], { direction: 'backward' } );
  852. }
  853. expect( i ).to.equal( 0 );
  854. } );
  855. } );
  856. } );
  857. } );
  858. function expectValue( value, expected, options = {} ) {
  859. let expectedPreviousPosition, expectedNextPosition;
  860. if ( options.direction == 'backward' ) {
  861. expectedNextPosition = expected.previousPosition;
  862. expectedPreviousPosition = expected.nextPosition;
  863. } else {
  864. expectedNextPosition = expected.nextPosition;
  865. expectedPreviousPosition = expected.previousPosition;
  866. }
  867. expect( value.type ).to.equal( expected.type );
  868. expect( value.previousPosition ).to.deep.equal( expectedPreviousPosition );
  869. expect( value.nextPosition ).to.deep.equal( expectedNextPosition );
  870. if ( value.type == 'text' ) {
  871. expectText( value, expected );
  872. } else if ( value.type == 'elementStart' ) {
  873. expectStart( value, expected );
  874. } else if ( value.type == 'elementEnd' ) {
  875. expectEnd( value, expected );
  876. }
  877. }
  878. function expectText( value, expected ) {
  879. expect( value.item.data ).to.equal( expected.text );
  880. expect( value.length ).to.equal( value.item.data.length );
  881. }
  882. function expectStart( value, expected ) {
  883. expect( value.item ).to.equal( expected.item );
  884. expect( value.length ).to.equal( 1 );
  885. }
  886. function expectEnd( value, expected ) {
  887. expect( value.item ).to.equal( expected.item );
  888. expect( value.length ).to.be.undefined;
  889. }