splitdelta.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. /**
  2. * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import transformations from '../../../../src/model/delta/basic-transformations';
  6. /*jshint unused: false*/
  7. import deltaTransform from '../../../../src/model/delta/transform';
  8. const transform = deltaTransform.transform;
  9. import Element from '../../../../src/model/element';
  10. import Position from '../../../../src/model/position';
  11. import Range from '../../../../src/model/range';
  12. import Delta from '../../../../src/model/delta/delta';
  13. import SplitDelta from '../../../../src/model/delta/splitdelta';
  14. import AttributeDelta from '../../../../src/model/delta/attributedelta';
  15. import RenameDelta from '../../../../src/model/delta/renamedelta';
  16. import RemoveDelta from '../../../../src/model/delta/removedelta';
  17. import InsertOperation from '../../../../src/model/operation/insertoperation';
  18. import AttributeOperation from '../../../../src/model/operation/attributeoperation';
  19. import ReinsertOperation from '../../../../src/model/operation/reinsertoperation';
  20. import MoveOperation from '../../../../src/model/operation/moveoperation';
  21. import NoOperation from '../../../../src/model/operation/nooperation';
  22. import RenameOperation from '../../../../src/model/operation/renameoperation';
  23. import { getNodesAndText, jsonParseStringify } from '../../../../tests/model/_utils/utils';
  24. import {
  25. applyDelta,
  26. expectDelta,
  27. getFilledDocument,
  28. getSplitDelta,
  29. getWrapDelta,
  30. getUnwrapDelta,
  31. getRemoveDelta
  32. } from '../../../../tests/model/delta/transform/_utils/utils';
  33. describe( 'transform', () => {
  34. let doc, root, gy, baseVersion;
  35. beforeEach( () => {
  36. doc = getFilledDocument();
  37. root = doc.getRoot();
  38. gy = doc.graveyard;
  39. baseVersion = doc.version;
  40. } );
  41. describe( 'SplitDelta by', () => {
  42. let splitDelta, splitPosition;
  43. beforeEach( () => {
  44. splitPosition = new Position( root, [ 3, 3, 3, 3 ] );
  45. splitDelta = getSplitDelta( splitPosition, new Element( 'p' ), 9, baseVersion );
  46. } );
  47. describe( 'SplitDelta', () => {
  48. it( 'split in same parent and offset', () => {
  49. let splitDeltaB = getSplitDelta( splitPosition, new Element( 'p' ), 9, baseVersion );
  50. let transformed = transform( splitDelta, splitDeltaB );
  51. baseVersion = splitDeltaB.operations.length;
  52. expect( transformed.length ).to.equal( 1 );
  53. expectDelta( transformed[ 0 ], {
  54. type: Delta,
  55. operations: [
  56. {
  57. type: NoOperation,
  58. baseVersion: baseVersion
  59. }
  60. ]
  61. } );
  62. // Test if deltas do what they should after applying transformed delta.
  63. applyDelta( splitDeltaB, doc );
  64. applyDelta( transformed[ 0 ], doc );
  65. let nodesAndText = getNodesAndText( Range.createFromPositionAndShift( new Position( root, [ 3, 3, 0 ] ), 5 ) );
  66. // Incoming split delta is discarded. Only one new element is created after applying both split deltas.
  67. // There are no empty P elements.
  68. expect( nodesAndText ).to.equal( 'XXXXXabcdXPabcPPfoobarxyzP' );
  69. } );
  70. it( 'split in same parent, incoming delta splits closer', () => {
  71. let splitDeltaB = getSplitDelta( new Position( root, [ 3, 3, 3, 5 ] ), new Element( 'p' ), 7, baseVersion );
  72. let transformed = transform( splitDelta, splitDeltaB );
  73. baseVersion = splitDeltaB.operations.length;
  74. expect( transformed.length ).to.equal( 1 );
  75. expectDelta( transformed[ 0 ], {
  76. type: SplitDelta,
  77. operations: [
  78. {
  79. type: InsertOperation,
  80. position: new Position( root, [ 3, 3, 4 ] ),
  81. baseVersion: baseVersion
  82. },
  83. {
  84. type: MoveOperation,
  85. sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
  86. howMany: 2,
  87. targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
  88. baseVersion: baseVersion + 1
  89. }
  90. ]
  91. } );
  92. // Test if deltas do what they should after applying transformed delta.
  93. applyDelta( splitDeltaB, doc );
  94. applyDelta( transformed[ 0 ], doc );
  95. let nodesAndText = getNodesAndText( Range.createFromPositionAndShift( new Position( root, [ 3, 3, 0 ] ), 6 ) );
  96. // P element is correctly split, there are three P elements, letters in P elements are in correct order.
  97. expect( nodesAndText ).to.equal( 'XXXXXabcdXPabcPPfoPPobarxyzP' );
  98. } );
  99. it( 'split in same parent, incoming delta splits closer, split deltas have reinsert operations', () => {
  100. let reOp = new ReinsertOperation(
  101. new Position( gy, [ 1 ] ),
  102. 1,
  103. Position.createFromPosition( splitDelta.operations[ 0 ].position ),
  104. splitDelta.operations[ 0 ].baseVersion
  105. );
  106. splitDelta.operations[ 0 ] = reOp;
  107. let splitDeltaB = getSplitDelta( new Position( root, [ 3, 3, 3, 5 ] ), new Element( 'p' ), 7, baseVersion );
  108. reOp = new ReinsertOperation(
  109. new Position( gy, [ 0 ] ),
  110. 1,
  111. Position.createFromPosition( splitDeltaB.operations[ 0 ].position ),
  112. splitDeltaB.operations[ 0 ].baseVersion
  113. );
  114. splitDeltaB.operations[ 0 ] = reOp;
  115. let transformed = transform( splitDelta, splitDeltaB );
  116. baseVersion = splitDeltaB.operations.length;
  117. expect( transformed.length ).to.equal( 1 );
  118. expectDelta( transformed[ 0 ], {
  119. type: SplitDelta,
  120. operations: [
  121. {
  122. type: ReinsertOperation,
  123. sourcePosition: new Position( gy, [ 0 ] ),
  124. howMany: 1,
  125. targetPosition: new Position( root, [ 3, 3, 4 ] ),
  126. baseVersion: baseVersion
  127. },
  128. {
  129. type: MoveOperation,
  130. sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
  131. howMany: 2,
  132. targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
  133. baseVersion: baseVersion + 1
  134. }
  135. ]
  136. } );
  137. } );
  138. it( 'split in same parent, incoming delta splits further', () => {
  139. let splitDeltaB = getSplitDelta( new Position( root, [ 3, 3, 3, 1 ] ), new Element( 'p' ), 11, baseVersion );
  140. let transformed = transform( splitDelta, splitDeltaB );
  141. baseVersion = splitDeltaB.operations.length;
  142. expect( transformed.length ).to.equal( 1 );
  143. expectDelta( transformed[ 0 ], {
  144. type: SplitDelta,
  145. operations: [
  146. {
  147. type: InsertOperation,
  148. position: new Position( root, [ 3, 3, 5 ] ),
  149. baseVersion: baseVersion
  150. },
  151. {
  152. type: MoveOperation,
  153. sourcePosition: new Position( root, [ 3, 3, 4, 2 ] ),
  154. howMany: 9,
  155. targetPosition: new Position( root, [ 3, 3, 5, 0 ] ),
  156. baseVersion: baseVersion + 1
  157. }
  158. ]
  159. } );
  160. // Test if deltas do what they should after applying transformed delta.
  161. applyDelta( splitDeltaB, doc );
  162. applyDelta( transformed[ 0 ], doc );
  163. let nodesAndText = getNodesAndText( Range.createFromPositionAndShift( new Position( root, [ 3, 3, 0 ] ), 6 ) );
  164. // P element is correctly split, there are three P elements, letters in P elements are in correct order.
  165. expect( nodesAndText ).to.equal( 'XXXXXabcdXPaPPbcPPfoobarxyzP' );
  166. } );
  167. it( 'split in same parent, incoming delta splits further, split deltas have reinsert operations', () => {
  168. let reOp = new ReinsertOperation(
  169. new Position( gy, [ 1 ] ),
  170. 1,
  171. Position.createFromPosition( splitDelta.operations[ 0 ].position ),
  172. splitDelta.operations[ 0 ].baseVersion
  173. );
  174. splitDelta.operations[ 0 ] = reOp;
  175. let splitDeltaB = getSplitDelta( new Position( root, [ 3, 3, 3, 1 ] ), new Element( 'p' ), 11, baseVersion );
  176. reOp = new ReinsertOperation(
  177. new Position( gy, [ 0 ] ),
  178. 1,
  179. Position.createFromPosition( splitDeltaB.operations[ 0 ].position ),
  180. splitDeltaB.operations[ 0 ].baseVersion
  181. );
  182. splitDeltaB.operations[ 0 ] = reOp;
  183. let transformed = transform( splitDelta, splitDeltaB );
  184. baseVersion = splitDeltaB.operations.length;
  185. expect( transformed.length ).to.equal( 1 );
  186. expectDelta( transformed[ 0 ], {
  187. type: SplitDelta,
  188. operations: [
  189. {
  190. type: ReinsertOperation,
  191. sourcePosition: new Position( gy, [ 0 ] ),
  192. howMany: 1,
  193. targetPosition: new Position( root, [ 3, 3, 5 ] ),
  194. baseVersion: baseVersion
  195. },
  196. {
  197. type: MoveOperation,
  198. sourcePosition: new Position( root, [ 3, 3, 4, 2 ] ),
  199. howMany: 9,
  200. targetPosition: new Position( root, [ 3, 3, 5, 0 ] ),
  201. baseVersion: baseVersion + 1
  202. }
  203. ]
  204. } );
  205. } );
  206. it( 'split in split parent', () => {
  207. let splitDeltaB = getSplitDelta( new Position( root, [ 3, 3, 3 ] ), new Element( 'div' ), 1, baseVersion );
  208. let transformed = transform( splitDelta, splitDeltaB );
  209. baseVersion = splitDeltaB.operations.length;
  210. expect( transformed.length ).to.equal( 1 );
  211. expectDelta( transformed[ 0 ], {
  212. type: SplitDelta,
  213. operations: [
  214. {
  215. type: InsertOperation,
  216. position: new Position( root, [ 3, 4, 1 ] ),
  217. baseVersion: baseVersion
  218. },
  219. {
  220. type: MoveOperation,
  221. sourcePosition: new Position( root, [ 3, 4, 0, 3 ] ),
  222. howMany: 9,
  223. targetPosition: new Position( root, [ 3, 4, 1, 0 ] ),
  224. baseVersion: baseVersion + 1
  225. }
  226. ]
  227. } );
  228. // Test if deltas do what they should after applying transformed delta.
  229. applyDelta( splitDeltaB, doc );
  230. applyDelta( transformed[ 0 ], doc );
  231. let nodesAndText = getNodesAndText( Range.createFromPositionAndShift( new Position( root, [ 3, 3 ] ), 2 ) );
  232. // DIV and P elements are correctly split.
  233. expect( nodesAndText ).to.equal( 'DIVXXXXXabcdXDIVDIVPabcPPfoobarxyzPDIV' );
  234. } );
  235. } );
  236. describe( 'UnwrapDelta', () => {
  237. it( 'split position directly in unwrapped node', () => {
  238. let unwrapDelta = getUnwrapDelta( new Position( root, [ 3, 3, 3 ] ), 12, baseVersion );
  239. let transformed = transform( splitDelta, unwrapDelta );
  240. baseVersion = unwrapDelta.operations.length;
  241. expect( transformed.length ).to.equal( 1 );
  242. expectDelta( transformed[ 0 ], {
  243. type: Delta,
  244. operations: [
  245. {
  246. type: NoOperation,
  247. baseVersion: baseVersion
  248. }
  249. ]
  250. } );
  251. // Test if deltas do what they should after applying transformed delta.
  252. applyDelta( unwrapDelta, doc );
  253. applyDelta( transformed[ 0 ], doc );
  254. let nodesAndText = getNodesAndText( Range.createFromPositionAndShift( new Position( root, [ 3, 3 ] ), 1 ) );
  255. // UnwrapDelta is applied. SplitDelta is discarded.
  256. expect( nodesAndText ).to.equal( 'DIVXXXXXabcdXabcfoobarxyzDIV' );
  257. } );
  258. it( 'split position indirectly in unwrapped node', () => {
  259. let unwrapDelta = getUnwrapDelta( new Position( root, [ 3, 3 ] ), 4, baseVersion );
  260. let transformed = transform( splitDelta, unwrapDelta );
  261. expect( transformed.length ).to.equal( 1 );
  262. baseVersion = unwrapDelta.operations.length;
  263. expectDelta( transformed[ 0 ], {
  264. type: SplitDelta,
  265. operations: [
  266. {
  267. type: InsertOperation,
  268. position: new Position( root, [ 3, 7 ] ),
  269. baseVersion: baseVersion
  270. },
  271. {
  272. type: MoveOperation,
  273. sourcePosition: new Position( root, [ 3, 6, 3 ] ),
  274. howMany: 9,
  275. targetPosition: new Position( root, [ 3, 7, 0 ] ),
  276. baseVersion: baseVersion + 1
  277. }
  278. ]
  279. } );
  280. // Test if deltas do what they should after applying transformed delta.
  281. applyDelta( unwrapDelta, doc );
  282. applyDelta( transformed[ 0 ], doc );
  283. let nodesAndText = getNodesAndText( Range.createFromPositionAndShift( new Position( root, [ 3 ] ), 1 ) );
  284. // UnwrapDelta and SplitDelta are correctly applied.
  285. expect( nodesAndText ).to.equal( 'DIVXXXXXaXXXXXXabcdXPabcPPfoobarxyzPDIV' );
  286. } );
  287. } );
  288. describe( 'WrapDelta', () => {
  289. it( 'split position is between wrapped nodes', () => {
  290. let wrapRange = new Range( new Position( root, [ 3, 3, 3, 1 ] ), new Position( root, [ 3, 3, 3, 5 ] ) );
  291. let wrapElement = new Element( 'E' );
  292. let wrapDelta = getWrapDelta( wrapRange, wrapElement, baseVersion );
  293. let transformed = transform( splitDelta, wrapDelta );
  294. baseVersion = wrapDelta.operations.length;
  295. expect( transformed.length ).to.equal( 1 );
  296. expectDelta( transformed[ 0 ], {
  297. type: Delta,
  298. operations: [
  299. {
  300. type: NoOperation,
  301. baseVersion: baseVersion
  302. }
  303. ]
  304. } );
  305. // Test if deltas do what they should after applying transformed delta.
  306. applyDelta( wrapDelta, doc );
  307. applyDelta( transformed[ 0 ], doc );
  308. let nodesAndText = getNodesAndText( Range.createFromPositionAndShift( new Position( root, [ 3, 3, 3 ] ), 1 ) );
  309. // WrapDelta is applied. SplitDelta is discarded.
  310. expect( nodesAndText ).to.equal( 'PaEbcfoEobarxyzP' );
  311. } );
  312. it( 'split position is before wrapped nodes', () => {
  313. let wrapRange = new Range( new Position( root, [ 3, 3, 3, 5 ] ), new Position( root, [ 3, 3, 3, 7 ] ) );
  314. let wrapElement = new Element( 'E' );
  315. let wrapDelta = getWrapDelta( wrapRange, wrapElement, baseVersion );
  316. let transformed = transform( splitDelta, wrapDelta );
  317. expect( transformed.length ).to.equal( 1 );
  318. baseVersion = wrapDelta.operations.length;
  319. expectDelta( transformed[ 0 ], {
  320. type: SplitDelta,
  321. operations: [
  322. {
  323. type: InsertOperation,
  324. position: new Position( root, [ 3, 3, 4 ] ),
  325. baseVersion: baseVersion
  326. },
  327. {
  328. type: MoveOperation,
  329. sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
  330. howMany: 8,
  331. targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
  332. baseVersion: baseVersion + 1
  333. }
  334. ]
  335. } );
  336. // Test if deltas do what they should after applying transformed delta.
  337. applyDelta( wrapDelta, doc );
  338. applyDelta( transformed[ 0 ], doc );
  339. let nodesAndText = getNodesAndText( Range.createFromPositionAndShift( new Position( root, [ 3, 3, 3 ] ), 2 ) );
  340. // WrapDelta and SplitDelta are correctly applied.
  341. expect( nodesAndText ).to.equal( 'PabcPPfoEobEarxyzP' );
  342. } );
  343. it( 'split position is inside wrapped node', () => {
  344. let wrapRange = new Range( new Position( root, [ 3, 3, 2 ] ), new Position( root, [ 3, 3, 4 ] ) );
  345. let wrapElement = new Element( 'E' );
  346. let wrapDelta = getWrapDelta( wrapRange, wrapElement, baseVersion );
  347. let transformed = transform( splitDelta, wrapDelta );
  348. expect( transformed.length ).to.equal( 1 );
  349. baseVersion = wrapDelta.operations.length;
  350. expectDelta( transformed[ 0 ], {
  351. type: SplitDelta,
  352. operations: [
  353. {
  354. type: InsertOperation,
  355. position: new Position( root, [ 3, 3, 2, 2 ] ),
  356. baseVersion: baseVersion
  357. },
  358. {
  359. type: MoveOperation,
  360. sourcePosition: new Position( root, [ 3, 3, 2, 1, 3 ] ),
  361. howMany: 9,
  362. targetPosition: new Position( root, [ 3, 3, 2, 2, 0 ] ),
  363. baseVersion: baseVersion + 1
  364. }
  365. ]
  366. } );
  367. // Test if deltas do what they should after applying transformed delta.
  368. applyDelta( wrapDelta, doc );
  369. applyDelta( transformed[ 0 ], doc );
  370. let nodesAndText = getNodesAndText( Range.createFromPositionAndShift( new Position( root, [ 3, 3, 2 ] ), 1 ) );
  371. // WrapDelta and SplitDelta are correctly applied.
  372. expect( nodesAndText ).to.equal( 'EXabcdXPabcPPfoobarxyzPE' );
  373. } );
  374. } );
  375. describe( 'AttributeDelta', () => {
  376. it( 'attribute changed on split element', () => {
  377. let attributeDelta = new AttributeDelta();
  378. attributeDelta.addOperation( new AttributeOperation(
  379. Range.createFromParentsAndOffsets( root, 0, root, 2 ), 'key', 'oldValue', 'newValue', baseVersion
  380. ) );
  381. attributeDelta.addOperation( new AttributeOperation(
  382. Range.createFromPositionAndShift( new Position( root, [ 3, 3, 2 ] ), 3 ), 'key', null, 'newValue', baseVersion + 1
  383. ) );
  384. let transformed = transform( splitDelta, attributeDelta );
  385. baseVersion = attributeDelta.operations.length;
  386. expect( transformed.length ).to.equal( 1 );
  387. expectDelta( transformed[ 0 ], {
  388. type: SplitDelta,
  389. operations: [
  390. {
  391. type: InsertOperation,
  392. position: new Position( root, [ 3, 3, 4 ] ),
  393. baseVersion: baseVersion
  394. },
  395. {
  396. type: MoveOperation,
  397. sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
  398. howMany: 9,
  399. targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
  400. baseVersion: baseVersion + 1
  401. }
  402. ]
  403. } );
  404. expect( transformed[ 0 ].operations[ 0 ].nodes.getNode( 0 ).getAttribute( 'key' ) ).to.equal( 'newValue' );
  405. } );
  406. it( 'attribute removed from split element', () => {
  407. splitDelta.operations[ 0 ].nodes.getNode( 0 ).setAttribute( 'key', 'oldValue' );
  408. let attributeDelta = new AttributeDelta();
  409. attributeDelta.addOperation( new AttributeOperation(
  410. Range.createFromParentsAndOffsets( root, 0, root, 2 ), 'key', 'otherValue', null, baseVersion
  411. ) );
  412. attributeDelta.addOperation( new AttributeOperation(
  413. Range.createFromPositionAndShift( new Position( root, [ 3, 3, 2 ] ), 3 ), 'key', 'oldValue', null, baseVersion + 1
  414. ) );
  415. let transformed = transform( splitDelta, attributeDelta );
  416. baseVersion = attributeDelta.operations.length;
  417. expect( transformed.length ).to.equal( 1 );
  418. expectDelta( transformed[ 0 ], {
  419. type: SplitDelta,
  420. operations: [
  421. {
  422. type: InsertOperation,
  423. position: new Position( root, [ 3, 3, 4 ] ),
  424. baseVersion: baseVersion
  425. },
  426. {
  427. type: MoveOperation,
  428. sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
  429. howMany: 9,
  430. targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
  431. baseVersion: baseVersion + 1
  432. }
  433. ]
  434. } );
  435. expect( transformed[ 0 ].operations[ 0 ].nodes.getNode( 0 ).hasAttribute( 'key' ) ).to.be.false;
  436. } );
  437. it( 'attribute changed on split element that is reinserted from graveyard', () => {
  438. splitDelta.operations[ 0 ] = new ReinsertOperation(
  439. new Position( gy, [ 1 ] ),
  440. 1,
  441. new Position( root, [ 3, 3, 4 ] ),
  442. baseVersion
  443. );
  444. let attributeDelta = new AttributeDelta();
  445. attributeDelta.addOperation( new AttributeOperation(
  446. Range.createFromParentsAndOffsets( root, 0, root, 4 ), 'key', 'oldValue', 'newValue', baseVersion
  447. ) );
  448. let transformed = transform( splitDelta, attributeDelta );
  449. baseVersion = attributeDelta.operations.length;
  450. expect( transformed.length ).to.equal( 1 );
  451. expectDelta( transformed[ 0 ], {
  452. type: SplitDelta,
  453. operations: [
  454. {
  455. type: ReinsertOperation,
  456. sourcePosition: new Position( gy, [ 1 ] ),
  457. howMany: 1,
  458. targetPosition: new Position( root, [ 3, 3, 4 ] ),
  459. baseVersion: baseVersion
  460. },
  461. {
  462. type: MoveOperation,
  463. sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
  464. howMany: 9,
  465. targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
  466. baseVersion: baseVersion + 1
  467. }
  468. ]
  469. } );
  470. } );
  471. } );
  472. describe( 'RenameDelta', () => {
  473. it( 'renamed split element', () => {
  474. const renameDelta = new RenameDelta();
  475. renameDelta.addOperation( new RenameOperation(
  476. new Position( root, [ 3, 3, 3 ] ), 'p', 'li', baseVersion
  477. ) );
  478. let transformed = transform( splitDelta, renameDelta );
  479. baseVersion = renameDelta.operations.length;
  480. expect( transformed.length ).to.equal( 1 );
  481. expectDelta( transformed[ 0 ], {
  482. type: SplitDelta,
  483. operations: [
  484. {
  485. type: InsertOperation,
  486. position: new Position( root, [ 3, 3, 4 ] ),
  487. baseVersion: baseVersion
  488. },
  489. {
  490. type: MoveOperation,
  491. sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
  492. howMany: 9,
  493. targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
  494. baseVersion: baseVersion + 1
  495. }
  496. ]
  497. } );
  498. expect( transformed[ 0 ].operations[ 0 ].nodes.getNode( 0 ).name ).to.equal( 'li' );
  499. } );
  500. it( 'split element is different than renamed element', () => {
  501. const renameDelta = new RenameDelta();
  502. renameDelta.addOperation( new RenameOperation(
  503. new Position( root, [ 4 ] ), 'p', 'li', baseVersion
  504. ) );
  505. let transformed = transform( splitDelta, renameDelta );
  506. baseVersion = renameDelta.operations.length;
  507. expect( transformed.length ).to.equal( 1 );
  508. expectDelta( transformed[ 0 ], {
  509. type: SplitDelta,
  510. operations: [
  511. {
  512. type: InsertOperation,
  513. position: new Position( root, [ 3, 3, 4 ] ),
  514. baseVersion: baseVersion
  515. },
  516. {
  517. type: MoveOperation,
  518. sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
  519. howMany: 9,
  520. targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
  521. baseVersion: baseVersion + 1
  522. }
  523. ]
  524. } );
  525. } );
  526. it( 'renamed split element that is reinserted from graveyard', () => {
  527. splitDelta.operations[ 0 ] = new ReinsertOperation(
  528. new Position( gy, [ 1 ] ),
  529. 1,
  530. new Position( root, [ 3, 3, 4 ] ),
  531. baseVersion
  532. );
  533. const renameDelta = new RenameDelta();
  534. renameDelta.addOperation( new RenameOperation(
  535. new Position( root, [ 3, 3, 3 ] ), 'p', 'li', baseVersion
  536. ) );
  537. let transformed = transform( splitDelta, renameDelta );
  538. baseVersion = renameDelta.operations.length;
  539. expect( transformed.length ).to.equal( 1 );
  540. expectDelta( transformed[ 0 ], {
  541. type: SplitDelta,
  542. operations: [
  543. {
  544. type: ReinsertOperation,
  545. sourcePosition: new Position( gy, [ 1 ] ),
  546. howMany: 1,
  547. targetPosition: new Position( root, [ 3, 3, 4 ] ),
  548. baseVersion: baseVersion
  549. },
  550. {
  551. type: MoveOperation,
  552. sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
  553. howMany: 9,
  554. targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
  555. baseVersion: baseVersion + 1
  556. }
  557. ]
  558. } );
  559. } );
  560. } );
  561. describe( 'RemoveDelta', () => {
  562. it( 'node inside the removed range was a node that has been split', () => {
  563. splitPosition = new Position( root, [ 3, 3, 2, 2 ] );
  564. splitDelta = getSplitDelta( splitPosition, new Element( 'x' ), 2, baseVersion );
  565. let removePosition = new Position( root, [ 3, 3, 1 ] );
  566. let removeDelta = getRemoveDelta( removePosition, 3, baseVersion );
  567. let removeOperation = removeDelta.operations[ 0 ];
  568. let transformed = transform( splitDelta, removeDelta );
  569. expect( transformed.length ).to.equal( 1 );
  570. baseVersion = removeDelta.operations.length;
  571. let newInsertPosition = removeOperation.targetPosition.getShiftedBy( 2 );
  572. let newMoveSourcePosition = removeOperation.targetPosition.getShiftedBy( 1 );
  573. newMoveSourcePosition.path.push( 2 );
  574. let newMoveTargetPosition = Position.createAt( newInsertPosition );
  575. newMoveTargetPosition.path.push( 0 );
  576. expectDelta( transformed[ 0 ], {
  577. type: SplitDelta,
  578. operations: [
  579. {
  580. type: InsertOperation,
  581. position: newInsertPosition,
  582. baseVersion: baseVersion
  583. },
  584. {
  585. type: MoveOperation,
  586. sourcePosition: newMoveSourcePosition,
  587. howMany: 2,
  588. targetPosition: newMoveTargetPosition,
  589. baseVersion: baseVersion + 1
  590. }
  591. ]
  592. } );
  593. } );
  594. it( 'last node in the removed range was a node that has been split', () => {
  595. let removePosition = new Position( root, [ 3, 3, 2 ] );
  596. let removeDelta = getRemoveDelta( removePosition, 2, baseVersion );
  597. let removeOperation = removeDelta.operations[ 0 ];
  598. let transformed = transform( splitDelta, removeDelta );
  599. expect( transformed.length ).to.equal( 1 );
  600. baseVersion = removeDelta.operations.length;
  601. let newInsertPosition = removeOperation.targetPosition.getShiftedBy( 2 );
  602. let newMoveSourcePosition = removeOperation.targetPosition.getShiftedBy( 1 );
  603. newMoveSourcePosition.path.push( 3 );
  604. let newMoveTargetPosition = Position.createAt( newInsertPosition );
  605. newMoveTargetPosition.path.push( 0 );
  606. expectDelta( transformed[ 0 ], {
  607. type: SplitDelta,
  608. operations: [
  609. {
  610. type: InsertOperation,
  611. position: newInsertPosition,
  612. baseVersion: baseVersion
  613. },
  614. {
  615. type: MoveOperation,
  616. sourcePosition: newMoveSourcePosition,
  617. howMany: 9,
  618. targetPosition: newMoveTargetPosition,
  619. baseVersion: baseVersion + 1
  620. }
  621. ]
  622. } );
  623. } );
  624. } );
  625. } );
  626. } );