treewalker.js 25 KB

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